diff options
| author | 2015-07-29 16:20:40 +0100 | |
|---|---|---|
| committer | 2016-01-13 16:56:56 +0000 | |
| commit | 75e097965cc273d33192555b0e65de3dbc1753ce (patch) | |
| tree | b2258e6a51b26e342571e89f1c81b7ca5113a32f | |
| parent | a1771110d67fa7361f92d92f2e91019882ce3305 (diff) | |
Request Keyboard Shortcuts for SysUI Dialog via Window
Keyboard shortcuts are requested via WindowManager, and
the request pipes through to the view root and the window
callback.
Bug: 22405482
Change-Id: Ic0071e91c7b554be3ac9df71e9539ee8a60e822e
23 files changed, 626 insertions, 36 deletions
diff --git a/api/current.txt b/api/current.txt index 629d832c0c3c..1dcd309b16ca 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3505,6 +3505,7 @@ package android.app {      method public boolean onPreparePanel(int, android.view.View, android.view.Menu);      method public void onProvideAssistContent(android.app.assist.AssistContent);      method public void onProvideAssistData(android.os.Bundle); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public android.net.Uri onProvideReferrer();      method public void onRequestPermissionsResult(int, java.lang.String[], int[]);      method protected void onRestart(); @@ -4189,6 +4190,7 @@ package android.app {      method public void onPanelClosed(int, android.view.Menu);      method public boolean onPrepareOptionsMenu(android.view.Menu);      method public boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public void onRestoreInstanceState(android.os.Bundle);      method public android.os.Bundle onSaveInstanceState();      method public boolean onSearchRequested(android.view.SearchEvent); @@ -33502,6 +33504,7 @@ package android.service.dreams {      method public boolean onMenuOpened(int, android.view.Menu);      method public void onPanelClosed(int, android.view.Menu);      method public boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public boolean onSearchRequested(android.view.SearchEvent);      method public boolean onSearchRequested();      method public void onWakeUp(); @@ -40390,6 +40393,27 @@ package android.view {      method public void startTracking(android.view.KeyEvent, java.lang.Object);    } +  public final class KeyboardShortcutGroup implements android.os.Parcelable { +    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>); +    ctor public KeyboardShortcutGroup(java.lang.CharSequence); +    method public void addItem(android.view.KeyboardShortcutInfo); +    method public int describeContents(); +    method public java.util.List<android.view.KeyboardShortcutInfo> getItems(); +    method public java.lang.CharSequence getLabel(); +    method public void writeToParcel(android.os.Parcel, int); +    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR; +  } + +  public final class KeyboardShortcutInfo implements android.os.Parcelable { +    ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int); +    method public int describeContents(); +    method public char getBaseCharacter(); +    method public java.lang.CharSequence getLabel(); +    method public int getModifiers(); +    method public void writeToParcel(android.os.Parcel, int); +    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR; +  } +    public abstract class LayoutInflater {      ctor protected LayoutInflater(android.content.Context);      ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context); @@ -42391,6 +42415,7 @@ package android.view {      method public abstract boolean onMenuOpened(int, android.view.Menu);      method public abstract void onPanelClosed(int, android.view.Menu);      method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public abstract boolean onSearchRequested();      method public abstract boolean onSearchRequested(android.view.SearchEvent);      method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); diff --git a/api/system-current.txt b/api/system-current.txt index 6a36ce05acca..adce4806c654 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3611,6 +3611,7 @@ package android.app {      method public boolean onPreparePanel(int, android.view.View, android.view.Menu);      method public void onProvideAssistContent(android.app.assist.AssistContent);      method public void onProvideAssistData(android.os.Bundle); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public android.net.Uri onProvideReferrer();      method public void onRequestPermissionsResult(int, java.lang.String[], int[]);      method protected void onRestart(); @@ -4310,6 +4311,7 @@ package android.app {      method public void onPanelClosed(int, android.view.Menu);      method public boolean onPrepareOptionsMenu(android.view.Menu);      method public boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public void onRestoreInstanceState(android.os.Bundle);      method public android.os.Bundle onSaveInstanceState();      method public boolean onSearchRequested(android.view.SearchEvent); @@ -35640,6 +35642,7 @@ package android.service.dreams {      method public boolean onMenuOpened(int, android.view.Menu);      method public void onPanelClosed(int, android.view.Menu);      method public boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public boolean onSearchRequested(android.view.SearchEvent);      method public boolean onSearchRequested();      method public void onWakeUp(); @@ -42741,6 +42744,27 @@ package android.view {      method public void startTracking(android.view.KeyEvent, java.lang.Object);    } +  public final class KeyboardShortcutGroup implements android.os.Parcelable { +    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>); +    ctor public KeyboardShortcutGroup(java.lang.CharSequence); +    method public void addItem(android.view.KeyboardShortcutInfo); +    method public int describeContents(); +    method public java.util.List<android.view.KeyboardShortcutInfo> getItems(); +    method public java.lang.CharSequence getLabel(); +    method public void writeToParcel(android.os.Parcel, int); +    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR; +  } + +  public final class KeyboardShortcutInfo implements android.os.Parcelable { +    ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int); +    method public int describeContents(); +    method public char getBaseCharacter(); +    method public java.lang.CharSequence getLabel(); +    method public int getModifiers(); +    method public void writeToParcel(android.os.Parcel, int); +    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR; +  } +    public abstract class LayoutInflater {      ctor protected LayoutInflater(android.content.Context);      ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context); @@ -44743,6 +44767,7 @@ package android.view {      method public abstract boolean onMenuOpened(int, android.view.Menu);      method public abstract void onPanelClosed(int, android.view.Menu);      method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public abstract boolean onSearchRequested();      method public abstract boolean onSearchRequested(android.view.SearchEvent);      method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); diff --git a/api/test-current.txt b/api/test-current.txt index 21b101fef449..3fed63215746 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3505,6 +3505,7 @@ package android.app {      method public boolean onPreparePanel(int, android.view.View, android.view.Menu);      method public void onProvideAssistContent(android.app.assist.AssistContent);      method public void onProvideAssistData(android.os.Bundle); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public android.net.Uri onProvideReferrer();      method public void onRequestPermissionsResult(int, java.lang.String[], int[]);      method protected void onRestart(); @@ -4189,6 +4190,7 @@ package android.app {      method public void onPanelClosed(int, android.view.Menu);      method public boolean onPrepareOptionsMenu(android.view.Menu);      method public boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public void onRestoreInstanceState(android.os.Bundle);      method public android.os.Bundle onSaveInstanceState();      method public boolean onSearchRequested(android.view.SearchEvent); @@ -33516,6 +33518,7 @@ package android.service.dreams {      method public boolean onMenuOpened(int, android.view.Menu);      method public void onPanelClosed(int, android.view.Menu);      method public boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public boolean onSearchRequested(android.view.SearchEvent);      method public boolean onSearchRequested();      method public void onWakeUp(); @@ -40406,6 +40409,27 @@ package android.view {      method public void startTracking(android.view.KeyEvent, java.lang.Object);    } +  public final class KeyboardShortcutGroup implements android.os.Parcelable { +    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>); +    ctor public KeyboardShortcutGroup(java.lang.CharSequence); +    method public void addItem(android.view.KeyboardShortcutInfo); +    method public int describeContents(); +    method public java.util.List<android.view.KeyboardShortcutInfo> getItems(); +    method public java.lang.CharSequence getLabel(); +    method public void writeToParcel(android.os.Parcel, int); +    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR; +  } + +  public final class KeyboardShortcutInfo implements android.os.Parcelable { +    ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int); +    method public int describeContents(); +    method public char getBaseCharacter(); +    method public java.lang.CharSequence getLabel(); +    method public int getModifiers(); +    method public void writeToParcel(android.os.Parcel, int); +    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR; +  } +    public abstract class LayoutInflater {      ctor protected LayoutInflater(android.content.Context);      ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context); @@ -42407,6 +42431,7 @@ package android.view {      method public abstract boolean onMenuOpened(int, android.view.Menu);      method public abstract void onPanelClosed(int, android.view.Menu);      method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu); +    method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);      method public abstract boolean onSearchRequested();      method public abstract boolean onSearchRequested(android.view.SearchEvent);      method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 34527c2623c6..e31259692501 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -62,6 +62,7 @@ import android.database.Cursor;  import android.graphics.Bitmap;  import android.graphics.Canvas;  import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon;  import android.media.AudioManager;  import android.media.session.MediaController;  import android.net.Uri; @@ -71,6 +72,7 @@ import android.os.Handler;  import android.os.IBinder;  import android.os.Looper;  import android.os.Parcelable; +import android.os.PersistableBundle;  import android.os.RemoteException;  import android.os.StrictMode;  import android.os.UserHandle; @@ -78,23 +80,28 @@ import android.text.Selection;  import android.text.SpannableStringBuilder;  import android.text.TextUtils;  import android.text.method.TextKeyListener; +import android.transition.Scene; +import android.transition.TransitionManager; +import android.util.ArrayMap;  import android.util.AttributeSet;  import android.util.EventLog;  import android.util.Log;  import android.util.PrintWriterPrinter;  import android.util.Slog;  import android.util.SparseArray; +import android.util.SuperNotCalledException;  import android.view.ActionMode;  import android.view.ContextMenu;  import android.view.ContextMenu.ContextMenuInfo;  import android.view.ContextThemeWrapper;  import android.view.KeyEvent; +import android.view.KeyboardShortcutGroup; +import android.view.KeyboardShortcutInfo;  import android.view.LayoutInflater;  import android.view.Menu;  import android.view.MenuInflater;  import android.view.MenuItem;  import android.view.MotionEvent; -import com.android.internal.policy.PhoneWindow;  import android.view.SearchEvent;  import android.view.View;  import android.view.View.OnCreateContextMenuListener; @@ -103,10 +110,17 @@ import android.view.ViewGroup.LayoutParams;  import android.view.ViewManager;  import android.view.ViewRootImpl;  import android.view.Window; +import android.view.Window.WindowControllerCallback;  import android.view.WindowManager;  import android.view.WindowManagerGlobal;  import android.view.accessibility.AccessibilityEvent;  import android.widget.AdapterView; +import android.widget.Toolbar; + +import com.android.internal.app.IVoiceInteractor; +import com.android.internal.app.ToolbarActionBar; +import com.android.internal.app.WindowDecorActionBar; +import com.android.internal.policy.PhoneWindow;  import java.io.FileDescriptor;  import java.io.PrintWriter; @@ -116,6 +130,8 @@ import java.util.ArrayList;  import java.util.HashMap;  import java.util.List; +import static java.lang.Character.MIN_VALUE; +  /**   * An activity is a single, focused thing that the user can do.  Almost all   * activities interact with the user, so the Activity class takes care of @@ -1594,6 +1610,30 @@ public class Activity extends ContextThemeWrapper      public void onProvideAssistContent(AssistContent outContent) {      } +    @Override +    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) { +        if (menu == null) { +          return; +        } +        KeyboardShortcutGroup group = null; +        int menuSize = menu.size(); +        for (int i = 0; i < menuSize; ++i) { +            final MenuItem item = menu.getItem(i); +            final CharSequence title = item.getTitle(); +            final char alphaShortcut = item.getAlphabeticShortcut(); +            if (title != null && alphaShortcut != MIN_VALUE) { +                if (group == null) { +                    group = new KeyboardShortcutGroup(null /* no label */); +                } +                group.addItem(new KeyboardShortcutInfo( +                    title, alphaShortcut, KeyEvent.META_CTRL_ON)); +            } +        } +        if (group != null) { +            data.add(group); +        } +    } +      /**       * Ask to have the current assistant shown to the user.  This only works if the calling       * activity is the current foreground activity.  It is the same as calling diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 6e8e2c44ce37..79461b4863ef 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -21,9 +21,8 @@ import android.annotation.DrawableRes;  import android.annotation.IdRes;  import android.annotation.LayoutRes;  import android.annotation.NonNull; -import android.annotation.StringRes; -  import android.annotation.Nullable; +import android.annotation.StringRes;  import android.annotation.StyleRes;  import android.content.ComponentName;  import android.content.Context; @@ -44,11 +43,11 @@ import android.view.ContextMenu.ContextMenuInfo;  import android.view.ContextThemeWrapper;  import android.view.Gravity;  import android.view.KeyEvent; +import android.view.KeyboardShortcutGroup;  import android.view.LayoutInflater;  import android.view.Menu;  import android.view.MenuItem;  import android.view.MotionEvent; -import com.android.internal.policy.PhoneWindow;  import android.view.SearchEvent;  import android.view.View;  import android.view.View.OnCreateContextMenuListener; @@ -60,8 +59,10 @@ import android.view.accessibility.AccessibilityEvent;  import com.android.internal.R;  import com.android.internal.app.WindowDecorActionBar; +import com.android.internal.policy.PhoneWindow;  import java.lang.ref.WeakReference; +import java.util.List;  /**   * Base class for Dialogs. @@ -1081,6 +1082,13 @@ public class Dialog implements DialogInterface, Window.Callback,      }      /** +     * {@inheritDoc} +     */ +    @Override +    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) { +    } + +    /**       * @return The activity associated with this dialog, or null if there is no associated activity.       */      private ComponentName getAssociatedActivity() { diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index bb46e8302de6..816ecde84377 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -15,9 +15,6 @@   */  package android.service.dreams; -import java.io.FileDescriptor; -import java.io.PrintWriter; -  import android.annotation.IdRes;  import android.annotation.LayoutRes;  import android.annotation.Nullable; @@ -33,27 +30,32 @@ import android.os.IBinder;  import android.os.PowerManager;  import android.os.RemoteException;  import android.os.ServiceManager; +import android.util.MathUtils;  import android.util.Slog;  import android.view.ActionMode;  import android.view.Display;  import android.view.KeyEvent; +import android.view.KeyboardShortcutGroup;  import android.view.Menu;  import android.view.MenuItem;  import android.view.MotionEvent; -import com.android.internal.policy.PhoneWindow;  import android.view.SearchEvent;  import android.view.View;  import android.view.ViewGroup;  import android.view.Window;  import android.view.WindowManager; -import android.view.WindowManagerGlobal;  import android.view.WindowManager.LayoutParams; +import android.view.WindowManagerGlobal;  import android.view.accessibility.AccessibilityEvent; -import android.util.MathUtils; +import com.android.internal.policy.PhoneWindow;  import com.android.internal.util.DumpUtils;  import com.android.internal.util.DumpUtils.Dump; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; +  /**   * Extend this class to implement a custom dream (available to the user as a "Daydream").   * @@ -365,6 +367,11 @@ public class DreamService extends Service implements Window.Callback {      @Override      public void onActionModeFinished(ActionMode mode) {      } + +    /** {@inheritDoc} */ +    @Override +    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) { +    }      // end Window.Callback methods      // begin public api diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 9e478c1d1e73..923139406088 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -25,6 +25,8 @@ import android.view.DragEvent;  import android.view.KeyEvent;  import android.view.MotionEvent; +import com.android.internal.os.IResultReceiver; +  /**   * API back to a client window that the Window Manager uses to inform it of   * interesting things happening. @@ -83,4 +85,9 @@ oneway interface IWindow {       * Called for non-application windows when the enter animation has completed.       */      void dispatchWindowShown(); + +    /** +     * Called when Keyboard Shortcuts are requested for the window. +     */ +    void requestAppKeyboardShortcuts(IResultReceiver receiver);  } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 84d312d59b64..b045c17a9295 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -17,6 +17,7 @@  package android.view;  import com.android.internal.app.IAssistScreenshotReceiver; +import com.android.internal.os.IResultReceiver;  import com.android.internal.view.IInputContext;  import com.android.internal.view.IInputMethodClient; @@ -370,4 +371,11 @@ interface IWindowManager       * @param alpha The translucency of the dim layer, between 0 and 1.       */      void setResizeDimLayer(boolean visible, int targetStackId, float alpha); + +    /** +     * Requests Keyboard Shortcuts from the displayed window. +     * +     * @param receiver The receiver to deliver the results to. +     */ +    void requestAppKeyboardShortcuts(IResultReceiver receiver);  } diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java new file mode 100644 index 000000000000..013255b9a612 --- /dev/null +++ b/core/java/android/view/KeyboardShortcutGroup.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 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. + */ +package android.view; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.android.internal.util.Preconditions.checkNotNull; + +/** + * A group of {@link KeyboardShortcutInfo}. + */ +public final class KeyboardShortcutGroup implements Parcelable { +    private final CharSequence mLabel; +    private final List<KeyboardShortcutInfo> mItems; + +    /** +     * @param label The title to be used for this group, or null if there is none. +     * @param items The set of items to be included. +     */ +    public KeyboardShortcutGroup(@Nullable CharSequence label, +            @NonNull List<KeyboardShortcutInfo> items) { +        mLabel = label; +        mItems = new ArrayList<>(checkNotNull(items)); +    } + +    /** +     * @param label The title to be used for this group, or null if there is none. +     */ +    public KeyboardShortcutGroup(@Nullable CharSequence label) { +        this(label, Collections.<KeyboardShortcutInfo>emptyList()); +    } + +    private KeyboardShortcutGroup(Parcel source) { +        mItems = new ArrayList<>(); +        mLabel = source.readCharSequence(); +        source.readTypedList(mItems, KeyboardShortcutInfo.CREATOR); +    } + +    /** +     * Returns the label to be used to describe this group. +     */ +    public CharSequence getLabel() { +        return mLabel; +    } + +    /** +     * Returns the list of items included in this group. +     */ +    public List<KeyboardShortcutInfo> getItems() { +        return mItems; +    } + +    /** +     * Adds an item to the existing list. +     * +     * @param item The item to be added. +     */ +    public void addItem(KeyboardShortcutInfo item) { +        mItems.add(item); +    } + +    @Override +    public int describeContents() { +        return 0; +    } + +    @Override +    public void writeToParcel(Parcel dest, int flags) { +        dest.writeCharSequence(mLabel); +        dest.writeTypedList(mItems); +    } + +    public static final Creator<KeyboardShortcutGroup> CREATOR = +            new Creator<KeyboardShortcutGroup>() { +        public KeyboardShortcutGroup createFromParcel(Parcel source) { +            return new KeyboardShortcutGroup(source); +        } +        public KeyboardShortcutGroup[] newArray(int size) { +            return new KeyboardShortcutGroup[size]; +        } +    }; +}
\ No newline at end of file diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java new file mode 100644 index 000000000000..2c9006deb189 --- /dev/null +++ b/core/java/android/view/KeyboardShortcutInfo.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015 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. + */ +package android.view; + +import android.annotation.Nullable; +import android.graphics.drawable.Icon; +import android.os.Parcel; +import android.os.Parcelable; + +import static com.android.internal.util.Preconditions.checkArgument; +import static java.lang.Character.MIN_VALUE; + +/** + * Information about a Keyboard Shortcut. + */ +public final class KeyboardShortcutInfo implements Parcelable { +    private final CharSequence mLabel; +    private final Icon mIcon; +    private final char mBaseCharacter; +    private final int mModifiers; + +    /** +     * @param label The label that identifies the action performed by this shortcut. +     * @param icon An icon that identifies the action performed by this shortcut. +     * @param baseCharacter The character that triggers the shortcut. +     * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut. +     *     These should be a combination of {@link KeyEvent#META_CTRL_ON}, +     *     {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and +     *     {@link KeyEvent#META_ALT_ON}. +     * +     * @hide +     */ +    public KeyboardShortcutInfo( +            @Nullable CharSequence label, @Nullable Icon icon, char baseCharacter, int modifiers) { +        mLabel = label; +        mIcon = icon; +        checkArgument(baseCharacter != MIN_VALUE); +        mBaseCharacter = baseCharacter; +        mModifiers = modifiers; +    } + +    /** +     * Convenience constructor for shortcuts with a label and no icon. +     * +     * @param label The label that identifies the action performed by this shortcut. +     * @param baseCharacter The character that triggers the shortcut. +     * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut. +     *     These should be a combination of {@link KeyEvent#META_CTRL_ON}, +     *     {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and +     *     {@link KeyEvent#META_ALT_ON}. +     */ +    public KeyboardShortcutInfo(CharSequence label, char baseCharacter, int modifiers) { +        mLabel = label; +        checkArgument(baseCharacter != MIN_VALUE); +        mBaseCharacter = baseCharacter; +        mModifiers = modifiers; +        mIcon = null; +    } + +    private KeyboardShortcutInfo(Parcel source) { +        mLabel = source.readCharSequence(); +        mIcon = (Icon) source.readParcelable(null); +        mBaseCharacter = (char) source.readInt(); +        mModifiers = source.readInt(); +    } + +    /** +     * Returns the label to be used to describe this shortcut. +     */ +    @Nullable +    public CharSequence getLabel() { +        return mLabel; +    } + +    /** +     * Returns the icon to be used to describe this shortcut. +     * +     * @hide +     */ +    @Nullable +    public Icon getIcon() { +        return mIcon; +    } + +    /** +     * Returns the base character that, combined with the modifiers, triggers this shortcut. +     */ +    public char getBaseCharacter() { +        return mBaseCharacter; +    } + +    /** +     * Returns the set of modifiers that, combined with the key, trigger this shortcut. +     */ +    public int getModifiers() { +        return mModifiers; +    } + +    @Override +    public int describeContents() { +        return 0; +    } + +    @Override +    public void writeToParcel(Parcel dest, int flags) { +        dest.writeCharSequence(mLabel); +        dest.writeParcelable(mIcon, 0); +        dest.writeInt(mBaseCharacter); +        dest.writeInt(mModifiers); +    } + +    public static final Creator<KeyboardShortcutInfo> CREATOR = +            new Creator<KeyboardShortcutInfo>() { +        public KeyboardShortcutInfo createFromParcel(Parcel source) { +            return new KeyboardShortcutInfo(source); +        } +        public KeyboardShortcutInfo[] newArray(int size) { +            return new KeyboardShortcutInfo[size]; +        } +    }; +}
\ No newline at end of file diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 68f1ac3c1108..5559d4dbe705 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -79,10 +79,11 @@ import android.util.StateSet;  import android.util.SuperNotCalledException;  import android.util.TypedValue;  import android.view.ContextMenu.ContextMenuInfo; -import android.view.AccessibilityIterators.TextSegmentIterator;  import android.view.AccessibilityIterators.CharacterTextSegmentIterator; -import android.view.AccessibilityIterators.WordTextSegmentIterator;  import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; +import android.view.AccessibilityIterators.TextSegmentIterator; +import android.view.AccessibilityIterators.WordTextSegmentIterator; +import android.view.ViewGroup.LayoutParams;  import android.view.accessibility.AccessibilityEvent;  import android.view.accessibility.AccessibilityEventSource;  import android.view.accessibility.AccessibilityManager; @@ -21715,6 +21716,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,      }      /** +     * @hide +     */ +    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data) { +        // Do nothing. +    } + +    /**       * Interface definition for a callback to be invoked when a hardware key event is       * dispatched to this view. The callback will be invoked before the key event is       * given to the view. This is only useful for hardware keyboards; a software input diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3eb2e37be781..a14f0dcc2541 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -79,6 +79,7 @@ import android.view.inputmethod.InputMethodManager;  import android.widget.Scroller;  import com.android.internal.R; +import com.android.internal.os.IResultReceiver;  import com.android.internal.os.SomeArgs;  import com.android.internal.policy.PhoneFallbackEventHandler;  import com.android.internal.view.BaseSurfaceHolder; @@ -3235,6 +3236,7 @@ public final class ViewRootImpl implements ViewParent,      private final static int MSG_WINDOW_MOVED = 23;      private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;      private final static int MSG_DISPATCH_WINDOW_SHOWN = 25; +    private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;      final class ViewRootHandler extends Handler {          @Override @@ -3511,7 +3513,11 @@ public final class ViewRootImpl implements ViewParent,              } break;              case MSG_DISPATCH_WINDOW_SHOWN: {                  handleDispatchWindowShown(); -            } +            } break; +            case MSG_REQUEST_KEYBOARD_SHORTCUTS: { +                IResultReceiver receiver = (IResultReceiver) msg.obj; +                handleRequestKeyboardShortcuts(receiver); +            } break;              }          }      } @@ -5404,6 +5410,19 @@ public final class ViewRootImpl implements ViewParent,          mAttachInfo.mTreeObserver.dispatchOnWindowShown();      } +    public void handleRequestKeyboardShortcuts(IResultReceiver receiver) { +        Bundle data = new Bundle(); +        ArrayList<KeyboardShortcutGroup> list = new ArrayList<>(); +        if (mView != null) { +            mView.requestKeyboardShortcuts(list); +        } +        data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list); +        try { +            receiver.send(0, data); +        } catch (RemoteException e) { +        } +    } +      public void getLastTouchPoint(Point outLocation) {          outLocation.x = (int) mLastTouchPoint.x;          outLocation.y = (int) mLastTouchPoint.y; @@ -6333,6 +6352,10 @@ public final class ViewRootImpl implements ViewParent,          }      } +    public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver) { +        mHandler.obtainMessage(MSG_REQUEST_KEYBOARD_SHORTCUTS, receiver).sendToTarget(); +    } +      /**       * Post a callback to send a       * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. @@ -6906,6 +6929,14 @@ public final class ViewRootImpl implements ViewParent,                  viewAncestor.dispatchWindowShown();              }          } + +        @Override +        public void requestAppKeyboardShortcuts(IResultReceiver receiver) { +          ViewRootImpl viewAncestor = mViewAncestor.get(); +          if (viewAncestor != null) { +            viewAncestor.dispatchRequestKeyboardShortcuts(receiver); +          } +        }      }      public static final class CalledFromWrongThreadException extends AndroidRuntimeException { diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 0b06d1591731..d89369bef170 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -42,6 +42,8 @@ import android.transition.Transition;  import android.transition.TransitionManager;  import android.view.accessibility.AccessibilityEvent; +import java.util.List; +  /**   * Abstract base class for a top-level window look and behavior policy.  An   * instance of this class should be used as the top-level view added to the @@ -556,6 +558,15 @@ public abstract class Window {           * @param mode The mode that was just finished.           */          public void onActionModeFinished(ActionMode mode); + +        /** +         * Called when Keyboard Shortcuts are requested for the current window. +         * +         * @param data The data list to populate with shortcuts. +         * @param menu The current menu, which may be null. +         */ +        public void onProvideKeyboardShortcuts( +                List<KeyboardShortcutGroup> data, @Nullable Menu menu);      }      /** @hide */ diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java index 8ce1f8c7e310..bed74e95ae0a 100644 --- a/core/java/android/view/WindowCallbackWrapper.java +++ b/core/java/android/view/WindowCallbackWrapper.java @@ -19,6 +19,8 @@ package android.view;  import android.view.accessibility.AccessibilityEvent; +import java.util.List; +  /**   * A simple decorator stub for Window.Callback that passes through any calls   * to the wrapped instance as a base implementation. Call super.foo() to call into @@ -150,5 +152,10 @@ public class WindowCallbackWrapper implements Window.Callback {      public void onActionModeFinished(ActionMode mode) {          mWrapped.onActionModeFinished(mode);      } + +    @Override +    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) { +        mWrapped.onProvideKeyboardShortcuts(data, menu); +    }  } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 251f4c802ce6..772eeec880ee 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -29,6 +29,8 @@ import android.os.Parcelable;  import android.text.TextUtils;  import android.util.Log; +import java.util.List; +  /**   * The interface that apps use to talk to the window manager. @@ -118,6 +120,34 @@ public interface WindowManager extends ViewManager {       */      public void removeViewImmediate(View view); +    /** +     * Used to asynchronously request Keyboard Shortcuts from the focused window. +     * +     * @hide +     */ +    public interface KeyboardShortcutsReceiver { +        /** +         * Callback used when the focused window keyboard shortcuts are ready to be displayed. +         * +         * @param result The keyboard shortcuts to be displayed. +         */ +        void onKeyboardShortcutsReceived(List<KeyboardShortcutGroup> result); +    } + +    /** +     * @hide +     */ +    public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array"; + +    /** +     * Request for keyboard shortcuts to be retrieved asynchronously. +     * +     * @param receiver The callback to be triggered when the result is ready. +     * +     * @hide +     */ +    public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver); +      public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {          /**           * X position for this window.  With the default gravity it is ignored. diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 98e9f54c13f9..6e11671016b4 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -17,7 +17,15 @@  package android.view;  import android.annotation.NonNull; +import android.content.Context; +import android.os.Bundle;  import android.os.IBinder; +import android.os.RemoteException; + +import com.android.internal.os.IResultReceiver; +import com.android.internal.R; + +import java.util.List;  /**   * Provides low-level communication with the system window manager for @@ -117,6 +125,23 @@ public final class WindowManagerImpl implements WindowManager {      }      @Override +    public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver) { +        IResultReceiver resultReceiver = new IResultReceiver.Stub() { +            @Override +            public void send(int resultCode, Bundle resultData) throws RemoteException { +                List<KeyboardShortcutGroup> result = +                        resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY); +                receiver.onKeyboardShortcutsReceived(result); +            } +        }; +        try { +            WindowManagerGlobal.getWindowManagerService() +                .requestAppKeyboardShortcuts(resultReceiver); +        } catch (RemoteException e) { +        } +    } + +    @Override      public Display getDefaultDisplay() {          return mDisplay;      } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index cea9867b8d88..7ae0efb6030b 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -17,6 +17,7 @@  package com.android.internal.policy;  import com.android.internal.R; +import com.android.internal.policy.PhoneWindow.PanelFeatureState;  import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;  import com.android.internal.view.FloatingActionMode;  import com.android.internal.view.RootViewSurfaceTaker; @@ -28,6 +29,8 @@ import com.android.internal.widget.BackgroundFallback;  import com.android.internal.widget.DecorCaptionView;  import com.android.internal.widget.FloatingToolbar; +import java.util.List; +  import android.animation.Animator;  import android.animation.ObjectAnimator;  import android.app.ActivityManager; @@ -48,6 +51,7 @@ import android.view.ContextThemeWrapper;  import android.view.Gravity;  import android.view.InputQueue;  import android.view.KeyEvent; +import android.view.KeyboardShortcutGroup;  import android.view.LayoutInflater;  import android.view.Menu;  import android.view.MenuItem; @@ -85,6 +89,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATIO  import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;  import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;  import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;  /** @hide */  public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { @@ -1956,6 +1961,21 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind                  res.getConfiguration().screenWidthDp, res.getDisplayMetrics());      } +    /** +     * @hide +     */ +    @Override +    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list) { +        final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false); +        if (!mWindow.isDestroyed() && st != null && mWindow.getCallback() != null) { +            try { +                mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu); +            } catch (AbstractMethodError e) { +                // We run into this if the app is using supportlib. +            } +        } +    } +      private static class ColorViewState {          View view = null;          int targetVisibility = View.INVISIBLE; diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index 8699843eb83b..aa4b564c3800 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -25,6 +25,8 @@ import android.view.DragEvent;  import android.view.IWindow;  import android.view.IWindowSession; +import com.android.internal.os.IResultReceiver; +  public class BaseIWindow extends IWindow.Stub {      private IWindowSession mSession;      public int mSeq; @@ -103,4 +105,8 @@ public class BaseIWindow extends IWindow.Stub {      @Override      public void dispatchWindowShown() {      } + +    @Override +    public void requestAppKeyboardShortcuts(IResultReceiver receiver) { +    }  } diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java index 48590c1ec463..1966313a41f0 100644 --- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java +++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java @@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.SmallTest;  import android.view.ActionMode;  import android.view.ActionMode.Callback;  import android.view.KeyEvent; +import android.view.KeyboardShortcutGroup;  import android.view.Menu;  import android.view.MenuInflater;  import android.view.MenuItem; @@ -32,6 +33,8 @@ import android.view.Window;  import android.view.WindowManager.LayoutParams;  import android.view.accessibility.AccessibilityEvent; +import java.util.List; +  /**   * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.   */ @@ -288,6 +291,9 @@ public final class PhoneWindowActionModeTest          @Override          public void onActionModeFinished(ActionMode mode) {} + +        @Override +        public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {}      }      private static final class MockActionModeCallback implements ActionMode.Callback { diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 4136c110c649..0e4f98f9c715 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1281,4 +1281,13 @@      <!-- Summary of switch for battery saver [CHAR LIMIT=NONE] -->      <string name="battery_detail_switch_summary">Reduces performance and background data</string> +    <!-- User visible title for the system-wide keyboard shortcuts list. --> +    <string name="keyboard_shortcut_group_system">System</string> +    <!-- User visible title for the keyboard shortcut that takes the user to the home screen. --> +    <string name="keyboard_shortcut_group_system_home">Home</string> +    <!-- User visible title for the the keyboard shortcut that takes the user to the recents screen. --> +    <string name="keyboard_shortcut_group_system_recents">Recents</string> +    <!-- User visible title for the the keyboard shortcut that triggers the back action. --> +    <string name="keyboard_shortcut_group_system_back">Back</string> +  </resources> diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 3406da94e53c..f9e825aaf064 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -60,6 +60,7 @@ import android.util.Pair;  import android.view.Display;  import android.view.IDockedStackListener;  import android.view.WindowManager; +import android.view.WindowManager.KeyboardShortcutsReceiver;  import android.view.WindowManagerGlobal;  import android.view.accessibility.AccessibilityManager;  import com.android.internal.app.AssistUtils; @@ -915,4 +916,8 @@ public class SystemServicesProxy {              e.printStackTrace();          }      } + +    public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) { +        mWm.requestAppKeyboardShortcuts(receiver); +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index 3e0ea90f7694..b36fb7e65f7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -20,50 +20,92 @@ import android.app.AlertDialog;  import android.app.Dialog;  import android.content.Context;  import android.graphics.drawable.ColorDrawable; -import android.view.Gravity; +import android.os.Handler; +import android.util.Log; +import android.view.KeyEvent; +import android.view.KeyboardShortcutGroup; +import android.view.KeyboardShortcutInfo;  import android.view.LayoutInflater;  import android.view.View;  import android.view.Window;  import android.view.WindowManager; +import android.view.WindowManager.KeyboardShortcutsReceiver;  import com.android.systemui.R; +import com.android.systemui.recents.Recents; + +import java.util.List; + +import static android.content.Context.LAYOUT_INFLATER_SERVICE; +import static android.graphics.Color.TRANSPARENT; +import static android.view.Gravity.TOP; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;  /**   * Contains functionality for handling keyboard shortcuts.   */  public class KeyboardShortcuts { +    private static final String TAG = "KeyboardShortcuts"; +      private Dialog mKeyboardShortcutsDialog;      public KeyboardShortcuts() {} -    public void toggleKeyboardShortcuts(Context context) { +    public void toggleKeyboardShortcuts(final Context context) {          if (mKeyboardShortcutsDialog == null) { -            // Create dialog. -            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); -            LayoutInflater inflater = (LayoutInflater) context.getSystemService( -                    Context.LAYOUT_INFLATER_SERVICE); -            final View keyboardShortcutsView = inflater.inflate( -                    R.layout.keyboard_shortcuts_view, null); - -            populateKeyboardShortcuts(keyboardShortcutsView.findViewById( -                    R.id.keyboard_shortcuts_wrapper)); -            dialogBuilder.setView(keyboardShortcutsView); -            mKeyboardShortcutsDialog = dialogBuilder.create(); -            mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true); - -            // Setup window. -            Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow(); -            keyboardShortcutsWindow.setType( -                    WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); -            keyboardShortcutsWindow.setBackgroundDrawable( -                    new ColorDrawable(android.graphics.Color.TRANSPARENT)); -            keyboardShortcutsWindow.setGravity(Gravity.TOP); -            mKeyboardShortcutsDialog.show(); +            Recents.getSystemServices().requestKeyboardShortcuts(context, +                new KeyboardShortcutsReceiver() { +                    @Override +                    public void onKeyboardShortcutsReceived( +                            final List<KeyboardShortcutGroup> result) { +                        KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup( +                            context.getString(R.string.keyboard_shortcut_group_system)); +                        systemGroup.addItem(new KeyboardShortcutInfo( +                            context.getString(R.string.keyboard_shortcut_group_system_home), +                            '\u2386', KeyEvent.META_META_ON)); +                        systemGroup.addItem(new KeyboardShortcutInfo( +                            context.getString(R.string.keyboard_shortcut_group_system_back), +                            '\u007F', KeyEvent.META_META_ON)); +                        systemGroup.addItem(new KeyboardShortcutInfo( +                            context.getString(R.string.keyboard_shortcut_group_system_recents), +                            '\u0009', KeyEvent.META_ALT_ON)); +                        result.add(systemGroup); +                        Log.i(TAG, "Keyboard shortcuts received: " + String.valueOf(result)); +                        showKeyboardShortcutsDialog(context); +                    } +                });          } else {              dismissKeyboardShortcutsDialog();          }      } +    private void showKeyboardShortcutsDialog(Context context) { +        // Create dialog. +        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); +        LayoutInflater inflater = (LayoutInflater) context.getSystemService( +                LAYOUT_INFLATER_SERVICE); +        final View keyboardShortcutsView = inflater.inflate( +                R.layout.keyboard_shortcuts_view, null); + +        populateKeyboardShortcuts(keyboardShortcutsView.findViewById( +                R.id.keyboard_shortcuts_wrapper)); +        dialogBuilder.setView(keyboardShortcutsView); +        mKeyboardShortcutsDialog = dialogBuilder.create(); +        mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true); + +        // Setup window. +        Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow(); +        keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG); +        keyboardShortcutsWindow.setBackgroundDrawable( +                new ColorDrawable(TRANSPARENT)); +        keyboardShortcutsWindow.setGravity(TOP); +        keyboardShortcutsView.post(new Runnable() { +            public void run() { +                mKeyboardShortcutsDialog.show(); +            } +        }); +    } +      public void dismissKeyboardShortcutsDialog() {          if (mKeyboardShortcutsDialog != null) {              mKeyboardShortcutsDialog.dismiss(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 685df25910d6..7d142eca0bb4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -119,6 +119,7 @@ import android.widget.Toast;  import com.android.internal.R;  import com.android.internal.app.IAssistScreenshotReceiver; +import com.android.internal.os.IResultReceiver;  import com.android.internal.util.FastPrintWriter;  import com.android.internal.view.IInputContext;  import com.android.internal.view.IInputMethodClient; @@ -10269,6 +10270,14 @@ public class WindowManagerService extends IWindowManager.Stub                  listener);      } +    @Override +    public void requestAppKeyboardShortcuts(IResultReceiver receiver) { +        try { +            getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver); +        } catch (RemoteException e) { +        } +    } +      private final class LocalService extends WindowManagerInternal {          @Override          public void requestTraversalFromDisplayManager() {  |