From 8861cb002f75d3dffef922c28fc0dbaca771ed11 Mon Sep 17 00:00:00 2001 From: Andrei Stingaceanu Date: Wed, 20 Jan 2016 16:48:30 +0000 Subject: [PATCH] Keyboard Shortcuts UI - add shortcuts to dialog. This is the first UI iteration which contains elements for displaying the keyboard shortcuts. Is is by no means final, the following items (and maybe more) still need to be actioned: * no UI for phone * no view for system shortcuts (which contain icons) * the shortcut items container needs a custom layout which needs to wrap and right align elements (prototype done) * find or build an util which can produce human readable names of the baseCharacter and the modifiers (so far I found a few functions, none of them good) * not pixel-perfect * the scrollbar does not show * the last separator (before the DONE button) is not visible Change-Id: I0d191e9516ab8f4728f40b3eefe9d854249ee7a8 --- .../android/view/KeyboardShortcutGroup.java | 33 +++- .../res/layout/keyboard_shortcut_app_item.xml | 55 ++++++ .../keyboard_shortcuts_category_title.xml | 25 +++ .../layout/keyboard_shortcuts_container.xml | 22 +++ .../layout/keyboard_shortcuts_key_view.xml | 25 +++ .../res/layout/keyboard_shortcuts_view.xml | 32 +++- .../res/layout/keyboard_shortcuts_wrapper.xml | 22 +++ packages/SystemUI/res/values/colors.xml | 5 + .../systemui/statusbar/BaseStatusBar.java | 4 +- .../systemui/statusbar/KeyboardShortcuts.java | 181 +++++++++++++----- 10 files changed, 344 insertions(+), 60 deletions(-) create mode 100644 packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml create mode 100644 packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml create mode 100644 packages/SystemUI/res/layout/keyboard_shortcuts_container.xml create mode 100644 packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml create mode 100644 packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java index 013255b9a6123..57d07c0d0eac8 100644 --- a/core/java/android/view/KeyboardShortcutGroup.java +++ b/core/java/android/view/KeyboardShortcutGroup.java @@ -32,6 +32,8 @@ import static com.android.internal.util.Preconditions.checkNotNull; public final class KeyboardShortcutGroup implements Parcelable { private final CharSequence mLabel; private final List mItems; + // The system group looks different UI wise. + private boolean mSystemGroup; /** * @param label The title to be used for this group, or null if there is none. @@ -50,10 +52,33 @@ public final class KeyboardShortcutGroup implements Parcelable { this(label, Collections.emptyList()); } + /** + * @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. + * @param isSystemGroup Set this to {@code true} if this is s system group. + * @hide + */ + public KeyboardShortcutGroup(@Nullable CharSequence label, + @NonNull List items, boolean isSystemGroup) { + mLabel = label; + mItems = new ArrayList<>(checkNotNull(items)); + mSystemGroup = isSystemGroup; + } + + /** + * @param label The title to be used for this group, or null if there is none. + * @param isSystemGroup Set this to {@code true} if this is s system group. + * @hide + */ + public KeyboardShortcutGroup(@Nullable CharSequence label, boolean isSystemGroup) { + this(label, Collections.emptyList(), isSystemGroup); + } + private KeyboardShortcutGroup(Parcel source) { mItems = new ArrayList<>(); mLabel = source.readCharSequence(); source.readTypedList(mItems, KeyboardShortcutInfo.CREATOR); + mSystemGroup = source.readInt() == 1; } /** @@ -70,6 +95,11 @@ public final class KeyboardShortcutGroup implements Parcelable { return mItems; } + /** @hide **/ + public boolean isSystemGroup() { + return mSystemGroup; + } + /** * Adds an item to the existing list. * @@ -88,6 +118,7 @@ public final class KeyboardShortcutGroup implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeCharSequence(mLabel); dest.writeTypedList(mItems); + dest.writeInt(mSystemGroup ? 1 : 0); } public static final Creator CREATOR = @@ -99,4 +130,4 @@ public final class KeyboardShortcutGroup implements Parcelable { return new KeyboardShortcutGroup[size]; } }; -} \ No newline at end of file +} diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml new file mode 100644 index 0000000000000..5a6553ff90db9 --- /dev/null +++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml @@ -0,0 +1,55 @@ + + + + + + + diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml new file mode 100644 index 0000000000000..80a478a6d3d87 --- /dev/null +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml @@ -0,0 +1,25 @@ + + + + diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml new file mode 100644 index 0000000000000..fa07eb1b105ce --- /dev/null +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml new file mode 100644 index 0000000000000..5002c1298eb2a --- /dev/null +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml @@ -0,0 +1,25 @@ + + + diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml index 460433ea1c214..77b12641c8c64 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml @@ -1,6 +1,6 @@ - - + + + + + + diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml new file mode 100644 index 0000000000000..802acfed73e80 --- /dev/null +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index f0d9949fa90c1..9bb6dc6abb752 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -154,4 +154,9 @@ #ff37474f #ff7fcac3 + + + #ff00bcd4 + #fff44336 + #ffffffff diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 240d32ec95bb2..4edb976b0c4d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -1175,7 +1175,7 @@ public abstract class BaseStatusBar extends SystemUI implements } protected void toggleKeyboardShortcuts() { - getKeyboardShortcuts().toggleKeyboardShortcuts(mContext); + getKeyboardShortcuts().toggleKeyboardShortcuts(); } protected void cancelPreloadingRecents() { @@ -1518,7 +1518,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected KeyboardShortcuts getKeyboardShortcuts() { if (mKeyboardShortcuts == null) { - mKeyboardShortcuts = new KeyboardShortcuts(); + mKeyboardShortcuts = new KeyboardShortcuts(mContext); } return mKeyboardShortcuts; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index b36fb7e65f7e1..25e9a7aa1d8bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -19,25 +19,38 @@ package com.android.systemui.statusbar; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.graphics.Color; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Handler; +import android.os.Looper; +import android.util.DisplayMetrics; import android.util.Log; +import android.util.TypedValue; import android.view.KeyEvent; import android.view.KeyboardShortcutGroup; import android.view.KeyboardShortcutInfo; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.Window; -import android.view.WindowManager; import android.view.WindowManager.KeyboardShortcutsReceiver; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; import com.android.systemui.R; import com.android.systemui.recents.Recents; +import java.util.ArrayList; import java.util.List; import static android.content.Context.LAYOUT_INFLATER_SERVICE; -import static android.graphics.Color.TRANSPARENT; +import static android.graphics.Color.WHITE; import static android.view.Gravity.TOP; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; @@ -45,33 +58,44 @@ 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 static final char SYSTEM_HOME_BASE_CHARACTER = '\u2386'; + private static final char SYSTEM_BACK_BASE_CHARACTER = '\u007F'; + private static final char SYSTEM_RECENTS_BASE_CHARACTER = '\u0009'; + + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final Context mContext; + private final OnClickListener dialogCloseListener = new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dismissKeyboardShortcutsDialog(); + } + }; private Dialog mKeyboardShortcutsDialog; - public KeyboardShortcuts() {} + public KeyboardShortcuts(Context context) { + this.mContext = context; + } - public void toggleKeyboardShortcuts(final Context context) { + public void toggleKeyboardShortcuts() { if (mKeyboardShortcutsDialog == null) { - Recents.getSystemServices().requestKeyboardShortcuts(context, + Recents.getSystemServices().requestKeyboardShortcuts(mContext, new KeyboardShortcutsReceiver() { @Override public void onKeyboardShortcutsReceived( final List result) { KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup( - context.getString(R.string.keyboard_shortcut_group_system)); + mContext.getString(R.string.keyboard_shortcut_group_system), true); systemGroup.addItem(new KeyboardShortcutInfo( - context.getString(R.string.keyboard_shortcut_group_system_home), - '\u2386', KeyEvent.META_META_ON)); + mContext.getString(R.string.keyboard_shortcut_group_system_home), + SYSTEM_HOME_BASE_CHARACTER, KeyEvent.META_META_ON)); systemGroup.addItem(new KeyboardShortcutInfo( - context.getString(R.string.keyboard_shortcut_group_system_back), - '\u007F', KeyEvent.META_META_ON)); + mContext.getString(R.string.keyboard_shortcut_group_system_back), + SYSTEM_BACK_BASE_CHARACTER, KeyEvent.META_META_ON)); systemGroup.addItem(new KeyboardShortcutInfo( - context.getString(R.string.keyboard_shortcut_group_system_recents), - '\u0009', KeyEvent.META_ALT_ON)); + mContext.getString(R.string.keyboard_shortcut_group_system_recents), + SYSTEM_RECENTS_BASE_CHARACTER, KeyEvent.META_ALT_ON)); result.add(systemGroup); - Log.i(TAG, "Keyboard shortcuts received: " + String.valueOf(result)); - showKeyboardShortcutsDialog(context); + showKeyboardShortcutsDialog(result); } }); } else { @@ -79,33 +103,6 @@ public class KeyboardShortcuts { } } - 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(); @@ -113,11 +110,99 @@ public class KeyboardShortcuts { } } - /** - * @return {@code true} if the keyboard shortcuts have been successfully populated. - */ - private boolean populateKeyboardShortcuts(View keyboardShortcutsLayout) { - // TODO: Populate shortcuts. - return true; + private void showKeyboardShortcutsDialog( + final List keyboardShortcutGroups) { + // Need to post on the main thread. + mHandler.post(new Runnable() { + @Override + public void run() { + // TODO: break all this code out into a handleShowKeyboard... + // Might add more things posted; should consider adding a custom handler so + // you can send the keyboardShortcutsGroups as part of the message. + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( + LAYOUT_INFLATER_SERVICE); + final View keyboardShortcutsView = inflater.inflate( + R.layout.keyboard_shortcuts_view, null); + DisplayMetrics dm = mContext.getResources().getDisplayMetrics(); + ScrollView scrollView = (ScrollView) keyboardShortcutsView.findViewById( + R.id.keyboard_shortcuts_scroll_view); + // TODO: find a better way to set the height. + scrollView.setLayoutParams(new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, + (int) (dm.heightPixels * dm.density))); + + populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById( + R.id.keyboard_shortcuts_container), keyboardShortcutGroups); + dialogBuilder.setView(keyboardShortcutsView); + dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener); + mKeyboardShortcutsDialog = dialogBuilder.create(); + mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true); + + // Setup window. + Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow(); + keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG); + keyboardShortcutsWindow.setBackgroundDrawable( + mContext.getDrawable(R.color.ksh_dialog_background_color)); + keyboardShortcutsWindow.setGravity(TOP); + mKeyboardShortcutsDialog.show(); + } + }); + } + + private void populateKeyboardShortcuts(LinearLayout keyboardShortcutsLayout, + List keyboardShortcutGroups) { + LayoutInflater inflater = LayoutInflater.from(mContext); + final int keyboardShortcutGroupsSize = keyboardShortcutGroups.size(); + for (int i = 0; i < keyboardShortcutGroupsSize; i++) { + KeyboardShortcutGroup group = keyboardShortcutGroups.get(i); + TextView categoryTitle = (TextView) inflater.inflate( + R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false); + categoryTitle.setText(group.getLabel()); + categoryTitle.setTextColor(group.isSystemGroup() + ? mContext.getColor(R.color.ksh_system_group_color) + : mContext.getColor(R.color.ksh_application_group_color)); + keyboardShortcutsLayout.addView(categoryTitle); + + LinearLayout shortcutWrapper = (LinearLayout) inflater.inflate( + R.layout.keyboard_shortcuts_wrapper, null); + final int itemsSize = group.getItems().size(); + for (int j = 0; j < itemsSize; j++) { + KeyboardShortcutInfo info = group.getItems().get(j); + View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, null); + TextView textView = (TextView) shortcutView + .findViewById(R.id.keyboard_shortcuts_keyword); + textView.setText(info.getLabel()); + + List shortcutKeys = getHumanReadableShortcutKeys(info); + final int shortcutKeysSize = shortcutKeys.size(); + for (int k = 0; k < shortcutKeysSize; k++) { + String shortcutKey = shortcutKeys.get(k); + TextView shortcutKeyView = (TextView) inflater.inflate( + R.layout.keyboard_shortcuts_key_view, null); + shortcutKeyView.setText(shortcutKey); + LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView + .findViewById(R.id.keyboard_shortcuts_item_container); + shortcutItemsContainer.addView(shortcutKeyView); + } + shortcutWrapper.addView(shortcutView); + } + + // TODO: merge container and wrapper into one xml file - wrapper is always a child of + // container. + LinearLayout shortcutsContainer = (LinearLayout) inflater.inflate( + R.layout.keyboard_shortcuts_container, null); + shortcutsContainer.addView(shortcutWrapper); + keyboardShortcutsLayout.addView(shortcutsContainer); + } + } + + private List getHumanReadableShortcutKeys(KeyboardShortcutInfo info) { + // TODO: fix the shortcuts. Find or build an util which can produce human readable + // names of the baseCharacter and the modifiers. + List shortcutKeys = new ArrayList<>(); + shortcutKeys.add(KeyEvent.metaStateToString(info.getModifiers()).toUpperCase()); + shortcutKeys.add(Character.getName(info.getBaseCharacter()).toUpperCase()); + return shortcutKeys; } }