Merge changes If7388e15,Ica73e67a,Ia4d4362e into nyc-dev
* changes:
Assume package failed to compile unless proven otherwise
Refactor return values of performDexOpt
Update packages in post-boot background job
diff --git a/api/current.txt b/api/current.txt
index 3444597..fbbb2e3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3578,6 +3578,7 @@
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
+ method public final void requestKeyboardShortcutsHelper();
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index a4927f2..d91f5d1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3696,6 +3696,7 @@
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
+ method public final void requestKeyboardShortcutsHelper();
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4179948..bad9733 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3578,6 +3578,7 @@
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
+ method public final void requestKeyboardShortcutsHelper();
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 672a706..7652766 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1676,6 +1676,17 @@
public void onProvideAssistContent(AssistContent outContent) {
}
+ /**
+ * Request the Keyboard Shortcuts screen to show up. If it succeeds, this will trigger
+ * {@link #onProvideKeyboardShortcuts} to retrieve the shortcuts for the foreground activity.
+ */
+ public final void requestKeyboardShortcutsHelper() {
+ Intent intent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
+ intent.setComponent(new ComponentName("com.android.systemui",
+ "com.android.systemui.statusbar.KeyboardShortcutsReceiver"));
+ sendBroadcast(intent);
+ }
+
@Override
public void onProvideKeyboardShortcuts(
List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 207b70a..7e67e8d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1404,6 +1404,16 @@
public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
/**
+ * Activity Action: Start the Keyboard Shortcuts Helper screen.
+ * <p>Input: Nothing.
+ * <p>Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SHOW_KEYBOARD_SHORTCUTS =
+ "android.intent.action.SHOW_KEYBOARD_SHORTCUTS";
+
+ /**
* Activity Action: Show settings for managing network data usage of a
* specific application. Applications should define an activity that offers
* options to control data usage.
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index fd73432..24739bf 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.annotation.NonNull;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Parcel;
@@ -25,6 +26,7 @@
import android.text.TextUtils;
import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -36,6 +38,11 @@
*/
public final class CursorAnchorInfo implements Parcelable {
/**
+ * The pre-computed hash code.
+ */
+ private final int mHashCode;
+
+ /**
* The index of the first character of the selected text (inclusive). {@code -1} when there is
* no text selection.
*/
@@ -100,7 +107,8 @@
* Transformation matrix that is applied to any positional information of this class to
* transform local coordinates into screen coordinates.
*/
- private final Matrix mMatrix;
+ @NonNull
+ private final float[] mMatrixValues;
/**
* Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterBoundsFlags(int)}: the
@@ -121,6 +129,7 @@
public static final int FLAG_IS_RTL = 0x04;
public CursorAnchorInfo(final Parcel source) {
+ mHashCode = source.readInt();
mSelectionStart = source.readInt();
mSelectionEnd = source.readInt();
mComposingTextStart = source.readInt();
@@ -131,8 +140,7 @@
mInsertionMarkerBaseline = source.readFloat();
mInsertionMarkerBottom = source.readFloat();
mCharacterBoundsArray = source.readParcelable(SparseRectFArray.class.getClassLoader());
- mMatrix = new Matrix();
- mMatrix.setValues(source.createFloatArray());
+ mMatrixValues = source.createFloatArray();
}
/**
@@ -143,6 +151,7 @@
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mHashCode);
dest.writeInt(mSelectionStart);
dest.writeInt(mSelectionEnd);
dest.writeInt(mComposingTextStart);
@@ -153,27 +162,12 @@
dest.writeFloat(mInsertionMarkerBaseline);
dest.writeFloat(mInsertionMarkerBottom);
dest.writeParcelable(mCharacterBoundsArray, flags);
- final float[] matrixArray = new float[9];
- mMatrix.getValues(matrixArray);
- dest.writeFloatArray(matrixArray);
+ dest.writeFloatArray(mMatrixValues);
}
@Override
public int hashCode(){
- final float floatHash = mInsertionMarkerHorizontal + mInsertionMarkerTop
- + mInsertionMarkerBaseline + mInsertionMarkerBottom;
- int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash);
- hash *= 31;
- hash += mInsertionMarkerFlags;
- hash *= 31;
- hash += mSelectionStart + mSelectionEnd + mComposingTextStart;
- hash *= 31;
- hash += Objects.hashCode(mComposingText);
- hash *= 31;
- hash += Objects.hashCode(mCharacterBoundsArray);
- hash *= 31;
- hash += Objects.hashCode(mMatrix);
- return hash;
+ return mHashCode;
}
/**
@@ -202,13 +196,13 @@
if (hashCode() != that.hashCode()) {
return false;
}
+
+ // Check fields that are not covered by hashCode() first.
+
if (mSelectionStart != that.mSelectionStart || mSelectionEnd != that.mSelectionEnd) {
return false;
}
- if (mComposingTextStart != that.mComposingTextStart
- || !Objects.equals(mComposingText, that.mComposingText)) {
- return false;
- }
+
if (mInsertionMarkerFlags != that.mInsertionMarkerFlags
|| !areSameFloatImpl(mInsertionMarkerHorizontal, that.mInsertionMarkerHorizontal)
|| !areSameFloatImpl(mInsertionMarkerTop, that.mInsertionMarkerTop)
@@ -216,18 +210,35 @@
|| !areSameFloatImpl(mInsertionMarkerBottom, that.mInsertionMarkerBottom)) {
return false;
}
+
if (!Objects.equals(mCharacterBoundsArray, that.mCharacterBoundsArray)) {
return false;
}
- if (!Objects.equals(mMatrix, that.mMatrix)) {
+
+ // Following fields are (partially) covered by hashCode().
+
+ if (mComposingTextStart != that.mComposingTextStart
+ || !Objects.equals(mComposingText, that.mComposingText)) {
return false;
}
+
+ // We do not use Arrays.equals(float[], float[]) to keep the previous behavior regarding
+ // NaN, 0.0f, and -0.0f.
+ if (mMatrixValues.length != that.mMatrixValues.length) {
+ return false;
+ }
+ for (int i = 0; i < mMatrixValues.length; ++i) {
+ if (mMatrixValues[i] != that.mMatrixValues[i]) {
+ return false;
+ }
+ }
return true;
}
@Override
public String toString() {
- return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd
+ return "CursorAnchorInfo{mHashCode=" + mHashCode
+ + " mSelection=" + mSelectionStart + "," + mSelectionEnd
+ " mComposingTextStart=" + mComposingTextStart
+ " mComposingText=" + Objects.toString(mComposingText)
+ " mInsertionMarkerFlags=" + mInsertionMarkerFlags
@@ -236,7 +247,7 @@
+ " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
+ " mInsertionMarkerBottom=" + mInsertionMarkerBottom
+ " mCharacterBoundsArray=" + Objects.toString(mCharacterBoundsArray)
- + " mMatrix=" + Objects.toString(mMatrix)
+ + " mMatrix=" + Arrays.toString(mMatrixValues)
+ "}";
}
@@ -254,7 +265,7 @@
private float mInsertionMarkerBottom = Float.NaN;
private int mInsertionMarkerFlags = 0;
private SparseRectFArrayBuilder mCharacterBoundsArrayBuilder = null;
- private final Matrix mMatrix = new Matrix(Matrix.IDENTITY_MATRIX);
+ private float[] mMatrixValues = null;
private boolean mMatrixInitialized = false;
/**
@@ -349,7 +360,10 @@
* is interpreted as an identity matrix.
*/
public Builder setMatrix(final Matrix matrix) {
- mMatrix.set(matrix != null ? matrix : Matrix.IDENTITY_MATRIX);
+ if (mMatrixValues == null) {
+ mMatrixValues = new float[9];
+ }
+ (matrix != null ? matrix : Matrix.IDENTITY_MATRIX).getValues(mMatrixValues);
mMatrixInitialized = true;
return this;
}
@@ -391,7 +405,6 @@
mInsertionMarkerTop = Float.NaN;
mInsertionMarkerBaseline = Float.NaN;
mInsertionMarkerBottom = Float.NaN;
- mMatrix.set(Matrix.IDENTITY_MATRIX);
mMatrixInitialized = false;
if (mCharacterBoundsArrayBuilder != null) {
mCharacterBoundsArrayBuilder.reset();
@@ -411,7 +424,18 @@
mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
mCharacterBoundsArray = builder.mCharacterBoundsArrayBuilder != null ?
builder.mCharacterBoundsArrayBuilder.build() : null;
- mMatrix = new Matrix(builder.mMatrix);
+ mMatrixValues = new float[9];
+ if (builder.mMatrixInitialized) {
+ System.arraycopy(builder.mMatrixValues, 0, mMatrixValues, 0, 9);
+ } else {
+ Matrix.IDENTITY_MATRIX.getValues(mMatrixValues);
+ }
+
+ // To keep hash function simple, we only use some complex objects for hash.
+ int hash = Objects.hashCode(mComposingText);
+ hash *= 31;
+ hash += Arrays.hashCode(mMatrixValues);
+ mHashCode = hash;
}
/**
@@ -527,7 +551,9 @@
* @return a new instance (copy) of the transformation matrix.
*/
public Matrix getMatrix() {
- return new Matrix(mMatrix);
+ final Matrix matrix = new Matrix();
+ matrix.setValues(mMatrixValues);
+ return matrix;
}
/**
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9e2442c..f5854f5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -488,5 +488,12 @@
<action android:name="com.android.systemui.action.CLEAR_TUNER" />
</intent-filter>
</receiver>
+
+ <receiver
+ android:name=".statusbar.KeyboardShortcutsReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.SHOW_KEYBOARD_SHORTCUTS" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index fff1491..0c079e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -58,11 +58,15 @@
import com.android.systemui.recents.Recents;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import com.google.android.collect.Lists;
+
/**
* Contains functionality for handling keyboard shortcuts.
*/
@@ -76,11 +80,32 @@
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Context mContext;
private final IPackageManager mPackageManager;
- private final OnClickListener dialogCloseListener = new DialogInterface.OnClickListener() {
+ private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dismissKeyboardShortcutsDialog();
}
};
+ private final Comparator<KeyboardShortcutInfo> mApplicationItemsComparator =
+ new Comparator<KeyboardShortcutInfo>() {
+ @Override
+ public int compare(KeyboardShortcutInfo ksh1, KeyboardShortcutInfo ksh2) {
+ boolean ksh1ShouldBeLast = ksh1.getLabel() == null
+ || ksh1.getLabel().toString().isEmpty();
+ boolean ksh2ShouldBeLast = ksh2.getLabel() == null
+ || ksh2.getLabel().toString().isEmpty();
+ if (ksh1ShouldBeLast && ksh2ShouldBeLast) {
+ return 0;
+ }
+ if (ksh1ShouldBeLast) {
+ return 1;
+ }
+ if (ksh2ShouldBeLast) {
+ return -1;
+ }
+ return (ksh1.getLabel().toString()).compareToIgnoreCase(
+ ksh2.getLabel().toString());
+ }
+ };
private Dialog mKeyboardShortcutsDialog;
private KeyCharacterMap mKeyCharacterMap;
@@ -255,10 +280,7 @@
}
public void toggleKeyboardShortcuts(int deviceId) {
- InputDevice inputDevice = InputManager.getInstance().getInputDevice(deviceId);
- if (inputDevice != null) {
- mKeyCharacterMap = inputDevice.getKeyCharacterMap();
- }
+ retrieveKeyCharacterMap(deviceId);
if (mKeyboardShortcutsDialog == null) {
Recents.getSystemServices().requestKeyboardShortcuts(mContext,
new KeyboardShortcutsReceiver() {
@@ -278,6 +300,35 @@
}
}
+ /**
+ * Retrieves a {@link KeyCharacterMap} and assigns it to mKeyCharacterMap. If the given id is an
+ * existing device, that device's map is used. Otherwise, it checks first all available devices
+ * and if there is a full keyboard it uses that map, otherwise falls back to the Virtual
+ * Keyboard with its default map.
+ */
+ private void retrieveKeyCharacterMap(int deviceId) {
+ final InputManager inputManager = InputManager.getInstance();
+ if (deviceId != -1) {
+ final InputDevice inputDevice = inputManager.getInputDevice(deviceId);
+ if (inputDevice != null) {
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ return;
+ }
+ }
+ final int[] deviceIds = inputManager.getInputDeviceIds();
+ for (int i = 0; i < deviceIds.length; ++i) {
+ final InputDevice inputDevice = inputManager.getInputDevice(deviceIds[i]);
+ // -1 is the Virtual Keyboard, with the default key map. Use that one only as last
+ // resort.
+ if (inputDevice.getId() != -1 && inputDevice.isFullKeyboard()) {
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ return;
+ }
+ }
+ final InputDevice inputDevice = inputManager.getInputDevice(-1);
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ }
+
public void dismissKeyboardShortcutsDialog() {
if (mKeyboardShortcutsDialog != null) {
mKeyboardShortcutsDialog.dismiss();
@@ -320,9 +371,7 @@
private KeyboardShortcutGroup getDefaultApplicationShortcuts() {
final int userId = mContext.getUserId();
- final KeyboardShortcutGroup applicationGroup = new KeyboardShortcutGroup(
- mContext.getString(R.string.keyboard_shortcut_group_applications),
- true);
+ List<KeyboardShortcutInfo> keyboardShortcutInfoAppItems = Lists.newArrayList();
// Assist.
final AssistUtils assistUtils = new AssistUtils(mContext);
@@ -340,7 +389,7 @@
assistPackageInfo.applicationInfo.packageName,
assistPackageInfo.applicationInfo.icon);
- applicationGroup.addItem(new KeyboardShortcutInfo(
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_applications_assist),
assistIcon,
KeyEvent.KEYCODE_UNKNOWN,
@@ -350,7 +399,7 @@
// Browser.
final Icon browserIcon = getIconForIntentCategory(Intent.CATEGORY_APP_BROWSER, userId);
if (browserIcon != null) {
- applicationGroup.addItem(new KeyboardShortcutInfo(
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
browserIcon,
KeyEvent.KEYCODE_B,
@@ -361,7 +410,7 @@
// Contacts.
final Icon contactsIcon = getIconForIntentCategory(Intent.CATEGORY_APP_CONTACTS, userId);
if (contactsIcon != null) {
- applicationGroup.addItem(new KeyboardShortcutInfo(
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
contactsIcon,
KeyEvent.KEYCODE_C,
@@ -371,7 +420,7 @@
// Email.
final Icon emailIcon = getIconForIntentCategory(Intent.CATEGORY_APP_EMAIL, userId);
if (emailIcon != null) {
- applicationGroup.addItem(new KeyboardShortcutInfo(
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_applications_email),
emailIcon,
KeyEvent.KEYCODE_E,
@@ -381,7 +430,7 @@
// Messaging.
final Icon messagingIcon = getIconForIntentCategory(Intent.CATEGORY_APP_MESSAGING, userId);
if (messagingIcon != null) {
- applicationGroup.addItem(new KeyboardShortcutInfo(
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_applications_im),
messagingIcon,
KeyEvent.KEYCODE_T,
@@ -391,7 +440,7 @@
// Music.
final Icon musicIcon = getIconForIntentCategory(Intent.CATEGORY_APP_MUSIC, userId);
if (musicIcon != null) {
- applicationGroup.addItem(new KeyboardShortcutInfo(
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_applications_music),
musicIcon,
KeyEvent.KEYCODE_P,
@@ -401,14 +450,24 @@
// Calendar.
final Icon calendarIcon = getIconForIntentCategory(Intent.CATEGORY_APP_CALENDAR, userId);
if (calendarIcon != null) {
- applicationGroup.addItem(new KeyboardShortcutInfo(
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
calendarIcon,
KeyEvent.KEYCODE_L,
KeyEvent.META_META_ON));
}
- return applicationGroup.getItems().size() == 0 ? null : applicationGroup;
+ final int itemsSize = keyboardShortcutInfoAppItems.size();
+ if (itemsSize == 0) {
+ return null;
+ }
+
+ // Sorts by label, case insensitive with nulls and/or empty labels last.
+ Collections.sort(keyboardShortcutInfoAppItems, mApplicationItemsComparator);
+ return new KeyboardShortcutGroup(
+ mContext.getString(R.string.keyboard_shortcut_group_applications),
+ keyboardShortcutInfoAppItems,
+ true);
}
private Icon getIconForIntentCategory(String intentCategory, int userId) {
@@ -459,7 +518,7 @@
populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById(
R.id.keyboard_shortcuts_container), keyboardShortcutGroups);
dialogBuilder.setView(keyboardShortcutsView);
- dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener);
+ dialogBuilder.setPositiveButton(R.string.quick_settings_done, mDialogCloseListener);
mKeyboardShortcutsDialog = dialogBuilder.create();
mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
@@ -488,12 +547,6 @@
final int itemsSize = group.getItems().size();
for (int j = 0; j < itemsSize; j++) {
KeyboardShortcutInfo info = group.getItems().get(j);
- if (info.getKeycode() != KeyEvent.KEYCODE_UNKNOWN
- && !KeyCharacterMap.deviceHasKey(info.getKeycode())) {
- // The user can't achieve this shortcut, so skipping.
- Log.w(TAG, "Keyboard Shortcut contains key not on device, skipping.");
- continue;
- }
List<StringOrDrawable> shortcutKeys = getHumanReadableShortcutKeys(info);
if (shortcutKeys == null) {
// Ignore shortcuts we can't display keys for.
@@ -585,9 +638,7 @@
if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
return shortcutKeys;
}
- // TODO: Have a generic map for when we don't have the device's.
- char displayLabel = mKeyCharacterMap == null
- ? 0 : mKeyCharacterMap.getDisplayLabel(info.getKeycode());
+ char displayLabel = mKeyCharacterMap.getDisplayLabel(info.getKeycode());
if (displayLabel != 0) {
displayLabelString = String.valueOf(displayLabel);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
new file mode 100644
index 0000000..5d22faf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 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 com.android.systemui.statusbar;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Receiver for the Keyboard Shortcuts Helper.
+ */
+public class KeyboardShortcutsReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ final KeyboardShortcuts keyboardShortcuts = new KeyboardShortcuts(context);
+ keyboardShortcuts.toggleKeyboardShortcuts(-1 /* deviceId unknown */);
+ }
+ }
+}