diff options
9 files changed, 595 insertions, 45 deletions
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f346bac4342e..2658b53446f2 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2403,6 +2403,8 @@ <!-- Title of the pop-up dialog in which the user switches input method components. --> <string name="select_input_method">Select input method</string> + <!-- Title of a button to open the settings for input methods [CHAR LIMIT=30] --> + <string name="configure_input_methods">Configure input methods</string> <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string> <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string> diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_input_methods_item.xml b/packages/SystemUI/res/layout-xlarge/status_bar_input_methods_item.xml new file mode 100644 index 000000000000..3028a426a87d --- /dev/null +++ b/packages/SystemUI/res/layout-xlarge/status_bar_input_methods_item.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, 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. +*/ +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:background="@drawable/status_bar_item_background" + android:orientation="vertical" + android:paddingRight="6dip" + android:paddingLeft="6dip" + android:paddingTop="5dip" + android:paddingBottom="5dip" + android:gravity="center_vertical"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="horizontal"> + <LinearLayout + android:id="@+id/item_subtype" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="horizontal" + android:background="?android:attr/selectableItemBackground"> + <RadioButton + android:id="@+id/item_radio" + android:layout_width="30dip" + android:layout_height="wrap_content" + android:layout_marginRight="11dip" + android:focusable="false" + android:clickable="false" /> + <ImageView + android:id="@+id/item_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:scaleType="fitCenter" /> + <LinearLayout + android:orientation="vertical" + android:layout_width="0px" + android:layout_weight="1" + android:layout_height="wrap_content"> + <TextView + android:id="@+id/item_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:singleLine="true" + android:ellipsize="marquee" + android:layout_marginBottom="2dip" /> + <TextView + android:id="@+id/item_subtitle" + android:layout_marginTop="-4dip" + android:layout_gravity="center_vertical|left" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" /> + </LinearLayout> + </LinearLayout> + <View + android:id="@+id/item_vertical_separator" + android:layout_width="2dip" + android:layout_height="match_parent" + android:layout_marginBottom="5dip" + android:background="@android:drawable/divider_horizontal_dark" /> + <ImageView + android:id="@+id/item_settings_icon" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginLeft="5dip" + android:layout_gravity="center_vertical" + android:paddingRight="10dip" + android:paddingLeft="10dip" + android:src="@drawable/ic_sysbar_quicksettings" + android:visibility="visible" + android:clickable="true" + android:focusable="true" + android:background="?android:attr/selectableItemBackground" /> + </LinearLayout> + <View + android:layout_width="match_parent" + android:layout_height="1dip" + android:background="@android:drawable/divider_horizontal_dark" /> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_input_methods_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_input_methods_panel.xml new file mode 100644 index 000000000000..c4bca615240a --- /dev/null +++ b/packages/SystemUI/res/layout-xlarge/status_bar_input_methods_panel.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2011, 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. +*/ +--> + +<com.android.systemui.statusbar.tablet.InputMethodsPanel + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:paddingBottom="28dip" + android:orientation="vertical"> + <View + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1" /> + <FrameLayout + android:id="@+id/glow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/recents_blue_glow"> + <LinearLayout + android:layout_width="450dip" + android:layout_height="wrap_content" + android:layout_marginLeft="20dip" + android:orientation="vertical" + android:background="@*android:drawable/dialog_full_holo_dark"> + <ScrollView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:overScrollMode="ifContentScrolls" + android:layout_marginTop="3dip" + android:layout_weight="1"> + <LinearLayout + android:id="@+id/input_method_menu_list" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" /> + </ScrollView> + <TextView + android:id="@+id/ime_settings_shortcut" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:background="?android:attr/selectableItemBackground" + android:orientation="vertical" + android:paddingRight="6dip" + android:paddingLeft="30dip" + android:paddingTop="5dip" + android:paddingBottom="5dip" + android:gravity="center_vertical" + android:singleLine="true" + android:text="@string/status_bar_input_method_settings_configure_input_methods" + android:textAppearance="?android:attr/textAppearanceMedium" + android:ellipsize="marquee" /> + </LinearLayout> + </FrameLayout> +</com.android.systemui.statusbar.tablet.InputMethodsPanel>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index caafbdb38fb8..53d06c0dcdcd 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -109,5 +109,7 @@ <string name="recent_tasks_app_label">Apps</string> <!-- Network connection string for Bluetooth Reverse Tethering --> - <string name="bluetooth_tethered">Bluetooth tethered"</string> + <string name="bluetooth_tethered">Bluetooth tethered</string> + <!-- Title of a button to open the settings for input methods [CHAR LIMIT=30] --> + <string name="status_bar_input_method_settings_configure_input_methods">Configure input methods</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java index df4bfa1a5a6f..69bc161fea7c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java @@ -19,11 +19,9 @@ package com.android.systemui.statusbar.tablet; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; -import android.os.Handler; import android.os.IBinder; import android.provider.Settings; import android.util.Log; -import android.util.Slog; import android.util.AttributeSet; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -31,11 +29,8 @@ import android.view.inputmethod.InputMethodSubtype; import android.view.View; import android.widget.ImageView; -import com.android.server.InputMethodManagerService; import com.android.systemui.R; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -56,9 +51,6 @@ public class InputMethodButton extends ImageView { // other services we wish to talk to private final InputMethodManager mImm; private final int mId; - // Cache of InputMethodsInfo - private final HashMap<String, InputMethodInfo> mInputMethodsInfo = - new HashMap<String, InputMethodInfo>(); private ImageView mIcon; private IBinder mToken; private boolean mKeyboardVisible = false; @@ -102,20 +94,6 @@ public class InputMethodButton extends ImageView { refreshStatusIcon(); } - private InputMethodInfo getCurrentInputMethodInfo() { - String curInputMethodId = Settings.Secure.getString(getContext() - .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); - if (!mInputMethodsInfo.containsKey(curInputMethodId)) { - mInputMethodsInfo.clear(); - List<InputMethodInfo> imis = mImm.getInputMethodList(); - for (int i = 0; i < imis.size(); ++i) { - InputMethodInfo imi = imis.get(i); - mInputMethodsInfo.put(imi.getId(), imi); - } - } - return mInputMethodsInfo.get(curInputMethodId); - } - // TODO: Need to show an appropriate drawable for this shortcut button, // if there are two or more shortcut input methods contained in this button. // And need to add other methods to handle multiple shortcuts as appropriate. @@ -141,8 +119,7 @@ public class InputMethodButton extends ImageView { final PackageManager pm = getContext().getPackageManager(); if (imi != null) { if (DEBUG) { - Log.d(TAG, "Update icons of IME: " + imi.getPackageName() + "," - + subtype.getLocale() + "," + subtype.getMode()); + Log.d(TAG, "Update icons of IME: " + imi.getPackageName()); } if (subtype != null) { return pm.getDrawable(imi.getPackageName(), subtype.getIconResId(), @@ -188,25 +165,19 @@ public class InputMethodButton extends ImageView { return; } if (!needsToShowIMEButton()) { - setVisibility(View.INVISIBLE); + setVisibility(View.GONE); return; } else { setVisibility(View.VISIBLE); } Drawable icon = null; switch (mId) { - case ID_IME_SWITCH_BUTTON: - // TODO: Just showing the first shortcut IME subtype for now. Should handle all - // shortcuts as appropriate. - icon = getSubtypeIcon(getCurrentInputMethodInfo(), - mImm.getCurrentInputMethodSubtype()); - break; case ID_IME_SHORTCUT_BUTTON: icon = getShortcutInputMethodAndSubtypeDrawable(); break; } if (icon == null) { - mIcon.setImageResource(R.drawable.ic_sysbar_ime_default); + mIcon.setImageResource(R.drawable.ic_sysbar_ime); } else { mIcon.setImageDrawable(icon); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java new file mode 100644 index 000000000000..d4ba6930d61c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2011 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.tablet; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.IBinder; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Pair; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.TextView; + +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import com.android.systemui.R; + +public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, OnClickListener { + private static final boolean DEBUG = TabletStatusBar.DEBUG; + private static final String TAG = "InputMethodsPanel"; + + private final InputMethodManager mImm; + private final HashMap<InputMethodInfo, List<InputMethodSubtype>> + mEnabledInputMethodAndSubtypesCache = + new HashMap<InputMethodInfo, List<InputMethodSubtype>>(); + private final HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>> mRadioViewAndImiMap = + new HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>>(); + private final PackageManager mPackageManager; + + private Context mContext; + private IBinder mToken; + private LinearLayout mInputMethodMenuList; + private String mEnabledInputMethodAndSubtypesCacheStr; + private View mConfigureImeShortcut; + + public InputMethodsPanel(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public InputMethodsPanel(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mContext = context; + mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + mPackageManager = context.getPackageManager(); + } + + @Override + public void onFinishInflate() { + mInputMethodMenuList = (LinearLayout) findViewById(R.id.input_method_menu_list); + mConfigureImeShortcut = ((View) findViewById(R.id.ime_settings_shortcut)); + mConfigureImeShortcut.setOnClickListener(this); + // TODO: If configurations for IME are not changed, do not update + // by checking onConfigurationChanged. + updateUiElements(); + } + + @Override + public boolean isInContentArea(int x, int y) { + return false; + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if (visibility == View.VISIBLE && changedView == this) { + updateUiElements(); + } + } + + @Override + public void onClick(View view) { + if (view == mConfigureImeShortcut) { + showConfigureInputMethods(); + onFinishPanel(true); + return; + } + } + + private void onFinishPanel(boolean closeKeyboard) { + setVisibility(View.GONE); + if (closeKeyboard) { + mImm.hideSoftInputFromWindow(getWindowToken(), 0); + } + } + + private void startActivity(Intent intent) { + mContext.startActivity(intent); + } + + private void showConfigureInputMethods() { + Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + } + + private View createInputMethodItem( + final InputMethodInfo imi, final InputMethodSubtype subtype) { + CharSequence subtypeName = getSubtypeName(imi, subtype); + CharSequence imiName = getIMIName(imi); + Drawable icon = getSubtypeIcon(imi, subtype); + View view = View.inflate(mContext, R.layout.status_bar_input_methods_item, null); + ImageView subtypeIcon = (ImageView)view.findViewById(R.id.item_icon); + TextView itemTitle = (TextView)view.findViewById(R.id.item_title); + TextView itemSubtitle = (TextView)view.findViewById(R.id.item_subtitle); + ImageView settingsIcon = (ImageView)view.findViewById(R.id.item_settings_icon); + View subtypeView = view.findViewById(R.id.item_subtype); + if (subtypeName == null) { + itemTitle.setText(imiName); + itemSubtitle.setVisibility(View.GONE); + } else { + itemTitle.setText(subtypeName); + itemSubtitle.setVisibility(View.VISIBLE); + itemSubtitle.setText(imiName); + } + subtypeIcon.setImageDrawable(icon); + final String settingsActivity = imi.getSettingsActivity(); + if (!TextUtils.isEmpty(settingsActivity)) { + settingsIcon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClassName(imi.getPackageName(), settingsActivity); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + onFinishPanel(true); + } + }); + } else { + // Do not show the settings icon if the IME does not have a settings preference + view.findViewById(R.id.item_vertical_separator).setVisibility(View.GONE); + settingsIcon.setVisibility(View.GONE); + } + mRadioViewAndImiMap.put( + subtypeView, new Pair<InputMethodInfo, InputMethodSubtype> (imi, subtype)); + subtypeView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype = + updateRadioButtonsByView(view); + onFinishPanel(false); + setInputMethodAndSubtype(imiAndSubtype.first, imiAndSubtype.second); + } + }); + return view; + } + + private void updateUiElements() { + // TODO: Reuse subtype views. + mInputMethodMenuList.removeAllViews(); + mRadioViewAndImiMap.clear(); + HashMap<InputMethodInfo, List<InputMethodSubtype>> enabledIMIs + = getEnabledInputMethodAndSubtypeList(); + // TODO: Sort by alphabet and mode. + Set<InputMethodInfo> cachedImiSet = enabledIMIs.keySet(); + for (InputMethodInfo imi: cachedImiSet) { + List<InputMethodSubtype> subtypes = enabledIMIs.get(imi); + if (subtypes == null || subtypes.size() == 0) { + mInputMethodMenuList.addView( + createInputMethodItem(imi, null)); + continue; + } + for (InputMethodSubtype subtype: subtypes) { + mInputMethodMenuList.addView(createInputMethodItem(imi, subtype)); + } + } + updateRadioButtons(); + } + + public void setIMEToken(IBinder token) { + mToken = token; + } + + private void setInputMethodAndSubtype(InputMethodInfo imi, InputMethodSubtype subtype) { + if (mToken != null) { + mImm.setInputMethodAndSubtype(mToken, imi.getId(), subtype); + } else { + Log.w(TAG, "IME Token is not set yet."); + } + } + + // Turn on the selected radio button when the user chooses the item + private Pair<InputMethodInfo, InputMethodSubtype> updateRadioButtonsByView(View selectedView) { + Pair<InputMethodInfo, InputMethodSubtype> selectedImiAndSubtype = null; + if (mRadioViewAndImiMap.containsKey(selectedView)) { + for (View radioView: mRadioViewAndImiMap.keySet()) { + RadioButton subtypeRadioButton = + (RadioButton) radioView.findViewById(R.id.item_radio); + if (subtypeRadioButton == null) { + Log.w(TAG, "RadioButton was not found in the selected subtype view"); + return null; + } + if (radioView == selectedView) { + Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype = + mRadioViewAndImiMap.get(radioView); + selectedImiAndSubtype = imiAndSubtype; + subtypeRadioButton.setChecked(true); + } else { + subtypeRadioButton.setChecked(false); + } + } + } + return selectedImiAndSubtype; + } + + private void updateRadioButtons() { + updateRadioButtonsByImiAndSubtype( + getCurrentInputMethodInfo(), mImm.getCurrentInputMethodSubtype()); + } + + // Turn on the selected radio button at startup + private void updateRadioButtonsByImiAndSubtype( + InputMethodInfo imi, InputMethodSubtype subtype) { + if (DEBUG) { + Log.d(TAG, "Update radio buttons by " + imi.getId() + ", " + subtype); + } + for (View radioView: mRadioViewAndImiMap.keySet()) { + RadioButton subtypeRadioButton = + (RadioButton) radioView.findViewById(R.id.item_radio); + if (subtypeRadioButton == null) { + Log.w(TAG, "RadioButton was not found in the selected subtype view"); + return; + } + Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype = + mRadioViewAndImiMap.get(radioView); + if (imiAndSubtype.first.getId().equals(imi.getId()) + && (imiAndSubtype.second == null || imiAndSubtype.second.equals(subtype))) { + subtypeRadioButton.setChecked(true); + } else { + subtypeRadioButton.setChecked(false); + } + } + } + + private HashMap<InputMethodInfo, List<InputMethodSubtype>> + getEnabledInputMethodAndSubtypeList() { + String newEnabledIMIs = Settings.Secure.getString( + mContext.getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS); + if (mEnabledInputMethodAndSubtypesCacheStr == null + || !mEnabledInputMethodAndSubtypesCacheStr.equals(newEnabledIMIs)) { + mEnabledInputMethodAndSubtypesCache.clear(); + final List<InputMethodInfo> imis = mImm.getEnabledInputMethodList(); + for (InputMethodInfo imi: imis) { + mEnabledInputMethodAndSubtypesCache.put(imi, + mImm.getEnabledInputMethodSubtypeList(imi, true)); + } + mEnabledInputMethodAndSubtypesCacheStr = newEnabledIMIs; + } + return mEnabledInputMethodAndSubtypesCache; + } + + private InputMethodInfo getCurrentInputMethodInfo() { + String curInputMethodId = Settings.Secure.getString(getContext() + .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + Set<InputMethodInfo> cachedImiSet = mEnabledInputMethodAndSubtypesCache.keySet(); + // 1. Search IMI in cache + for (InputMethodInfo imi: cachedImiSet) { + if (imi.getId().equals(curInputMethodId)) { + return imi; + } + } + // 2. Get current enabled IMEs and search IMI + cachedImiSet = getEnabledInputMethodAndSubtypeList().keySet(); + for (InputMethodInfo imi: cachedImiSet) { + if (imi.getId().equals(curInputMethodId)) { + return imi; + } + } + return null; + } + + private CharSequence getIMIName(InputMethodInfo imi) { + if (imi == null) return null; + return mPackageManager.getApplicationLabel(imi.getServiceInfo().applicationInfo); + } + + private CharSequence getSubtypeName(InputMethodInfo imi, InputMethodSubtype subtype) { + if (imi == null || subtype == null) return null; + // TODO: Change the language of subtype name according to subtype's locale. + return mPackageManager.getText( + imi.getPackageName(), subtype.getNameResId(), imi.getServiceInfo().applicationInfo); + } + + private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) { + if (imi != null) { + if (DEBUG) { + Log.d(TAG, "Update icons of IME: " + imi.getPackageName()); + if (subtype != null) { + Log.d(TAG, "subtype =" + subtype.getLocale() + "," + subtype.getMode()); + } + } + if (subtype != null) { + return mPackageManager.getDrawable(imi.getPackageName(), subtype.getIconResId(), + imi.getServiceInfo().applicationInfo); + } else if (imi.getSubtypes().size() > 0) { + return mPackageManager.getDrawable(imi.getPackageName(), + imi.getSubtypes().get(0).getIconResId(), + imi.getServiceInfo().applicationInfo); + } else { + try { + return mPackageManager.getApplicationInfo( + imi.getPackageName(), 0).loadIcon(mPackageManager); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "IME can't be found: " + imi.getPackageName()); + } + } + } + return null; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 020b9553c8fb..af730fef300f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -80,6 +80,8 @@ public class TabletStatusBar extends StatusBar implements public static final String TAG = "TabletStatusBar"; public static final int MAX_NOTIFICATION_ICONS = 5; + // IME switcher icon is big and occupy width of two icons + public static final int MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE = MAX_NOTIFICATION_ICONS - 2; public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001; @@ -89,6 +91,8 @@ public class TabletStatusBar extends StatusBar implements public static final int MSG_CLOSE_RECENTS_PANEL = 1021; public static final int MSG_SHOW_CHROME = 1030; public static final int MSG_HIDE_CHROME = 1031; + public static final int MSG_OPEN_INPUT_METHODS_PANEL = 1040; + public static final int MSG_CLOSE_INPUT_METHODS_PANEL = 1041; // Fitts' Law assistance for LatinIME; TODO: replace with a more general approach private static final boolean FAKE_SPACE_BAR = true; @@ -155,6 +159,7 @@ public class TabletStatusBar extends StatusBar implements boolean mNotificationsOn = true; private RecentAppsPanel mRecentsPanel; + private InputMethodsPanel mInputMethodsPanel; public Context getContext() { return mContext; } @@ -260,6 +265,28 @@ public class TabletStatusBar extends StatusBar implements WindowManagerImpl.getDefault().addView(mRecentsPanel, lp); mRecentsPanel.setBar(this); + + // Input methods Panel + mInputMethodsPanel = (InputMethodsPanel) View.inflate(context, + R.layout.status_bar_input_methods_panel, null); + mInputMethodsPanel.setVisibility(View.GONE); + mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener( + MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel)); + mStatusBarView.setIgnoreChildren(3, mInputMethodSwitchButton, mInputMethodsPanel); + lp = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, + PixelFormat.TRANSLUCENT); + lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; + lp.setTitle("InputMethodsPanel"); + lp.windowAnimations = R.style.Animation_RecentPanel; + + WindowManagerImpl.getDefault().addView(mInputMethodsPanel, lp); } @Override @@ -351,6 +378,8 @@ public class TabletStatusBar extends StatusBar implements // The bar contents buttons mNotificationAndImeArea = (ViewGroup)sb.findViewById(R.id.notificationAndImeArea); mInputMethodSwitchButton = (InputMethodButton) sb.findViewById(R.id.imeSwitchButton); + // Overwrite the lister + mInputMethodSwitchButton.setOnClickListener(mOnClickListener); // for redirecting errant bar taps to the IME mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar); @@ -522,6 +551,14 @@ public class TabletStatusBar extends StatusBar implements mRecentsPanel.show(false, true); } break; + case MSG_OPEN_INPUT_METHODS_PANEL: + if (DEBUG) Slog.d(TAG, "opening input methods panel"); + if (mInputMethodsPanel != null) mInputMethodsPanel.setVisibility(View.VISIBLE); + break; + case MSG_CLOSE_INPUT_METHODS_PANEL: + if (DEBUG) Slog.d(TAG, "closing input methods panel"); + if (mInputMethodsPanel != null) mInputMethodsPanel.setVisibility(View.GONE); + break; case MSG_SHOW_CHROME: if (DEBUG) Slog.d(TAG, "hiding shadows (lights on)"); mBarContents.setVisibility(View.VISIBLE); @@ -774,6 +811,8 @@ public class TabletStatusBar extends StatusBar implements mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL); mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); + mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL); + mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL); } // called by StatusBar @@ -803,7 +842,12 @@ public class TabletStatusBar extends StatusBar implements if (DEBUG) { Slog.d(TAG, (visible?"showing":"hiding") + " the IME button"); } + int oldVisibility = mInputMethodSwitchButton.getVisibility(); mInputMethodSwitchButton.setIMEButtonVisible(token, visible); + if (oldVisibility != mInputMethodSwitchButton.getVisibility()) { + updateNotificationIcons(); + } + mInputMethodsPanel.setIMEToken(token); mBackButton.setImageResource( visible ? R.drawable.ic_sysbar_back_ime : R.drawable.ic_sysbar_back); if (FAKE_SPACE_BAR) { @@ -851,6 +895,8 @@ public class TabletStatusBar extends StatusBar implements onClickNotificationTrigger(); } else if (v == mRecentButton) { onClickRecentButton(); + } else if (v == mInputMethodSwitchButton) { + onClickInputMethodSwitchButton(); } } }; @@ -890,6 +936,14 @@ public class TabletStatusBar extends StatusBar implements } } + public void onClickInputMethodSwitchButton() { + if (DEBUG) Slog.d(TAG, "clicked input methods panel; disabled=" + mDisabled); + int msg = (mInputMethodsPanel.getVisibility() == View.GONE) ? + MSG_OPEN_INPUT_METHODS_PANEL : MSG_CLOSE_INPUT_METHODS_PANEL; + mHandler.removeMessages(msg); + mHandler.sendEmptyMessage(msg); + } + public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) { return new NotificationClicker(intent, pkg, tag, id); } @@ -1086,7 +1140,12 @@ public class TabletStatusBar extends StatusBar implements ArrayList<View> toShow = new ArrayList<View>(); - for (int i=0; i<MAX_NOTIFICATION_ICONS; i++) { + // When IME button is visible, the number of notification icons should be decremented + // to fit the upper limit. + final int maxNotificationIconsCount = + (mInputMethodSwitchButton.getVisibility() != View.GONE) ? + MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE : MAX_NOTIFICATION_ICONS; + for (int i=0; i< maxNotificationIconsCount; i++) { if (i>=N) break; toShow.add(mNotns.get(N-i-1).icon); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java index 655076568022..4ee985df1f8e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java @@ -27,9 +27,9 @@ import android.widget.FrameLayout; public class TabletStatusBarView extends FrameLayout { private Handler mHandler; - private View[] mIgnoreChildren = new View[3]; - private View[] mPanels = new View[3]; - private int[] mPos = new int[2]; + private final View[] mIgnoreChildren = new View[4]; + private final View[] mPanels = new View[4]; + private final int[] mPos = new int[2]; public TabletStatusBarView(Context context) { super(context); @@ -39,6 +39,7 @@ public class TabletStatusBarView extends FrameLayout { super(context, attrs); } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { if (TabletStatusBar.DEBUG) { @@ -48,12 +49,16 @@ public class TabletStatusBarView extends FrameLayout { mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL); mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL); mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL); + mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL); + mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL); for (int i=0; i < mPanels.length; i++) { if (mPanels[i] != null && mPanels[i].getVisibility() == View.VISIBLE) { if (eventInside(mIgnoreChildren[i], ev)) { if (TabletStatusBar.DEBUG) { - Slog.d(TabletStatusBar.TAG, "TabletStatusBarView eating event for view: " + mIgnoreChildren[i]); + Slog.d(TabletStatusBar.TAG, + "TabletStatusBarView eating event for view: " + + mIgnoreChildren[i]); } return true; } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 5b560825e1ac..9c80b516fd7e 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -1800,19 +1800,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub }); if (showSubtypes) { - mDialogBuilder.setPositiveButton(com.android.internal.R.string.more_item_label, + mDialogBuilder.setPositiveButton( + com.android.internal.R.string.configure_input_methods, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { showConfigureInputMethods(); } }); } - mDialogBuilder.setNegativeButton(com.android.internal.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - hideInputMethodMenu(); - } - }); mSwitchingDialog = mDialogBuilder.create(); mSwitchingDialog.getWindow().setType( WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); |