From 1c65d017fb01cb2410a7be0ad35797893ae7d43b Mon Sep 17 00:00:00 2001 From: Yuriy Liskov Date: Tue, 20 Mar 2018 15:48:41 +0200 Subject: [PATCH] add keyboard chooser dialog --- .../ime/LeanbackKeyboardContainer.java | 8 ++ .../inputchooser/ChooseKeyboardDialog.java | 131 ++++++++++++++++++ .../inputchooser/SettingsActivity.java | 1 + .../keyboardaddons/KeyboardFactory.java | 1 + .../keyboardaddons/KeyboardInfo.java | 10 ++ .../keyboardaddons/KeyboardManager.java | 19 ++- .../keyboards/ApkLangKeyboardFactory.java | 6 + .../reslangfactory/ResKeyboardFactory.java | 19 ++- .../reslangfactory/ResKeyboardInfo.java | 91 ++++++++++++ .../reslangfactory/ResKeyboardManager.java | 11 ++ .../main/res/layout/lang_selection_dialog.xml | 25 ++++ .../src/main/res/values/dimens.xml | 1 + .../src/main/res/values/strings.xml | 1 + 13 files changed, 314 insertions(+), 10 deletions(-) create mode 100644 leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/ChooseKeyboardDialog.java create mode 100644 leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardInfo.java create mode 100644 leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardInfo.java create mode 100644 leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardManager.java create mode 100644 leankeykeyboard/src/main/res/layout/lang_selection_dialog.xml diff --git a/leankeykeyboard/src/main/java/com/google/android/leanback/ime/LeanbackKeyboardContainer.java b/leankeykeyboard/src/main/java/com/google/android/leanback/ime/LeanbackKeyboardContainer.java index 8a5215b..44170e1 100644 --- a/leankeykeyboard/src/main/java/com/google/android/leanback/ime/LeanbackKeyboardContainer.java +++ b/leankeykeyboard/src/main/java/com/google/android/leanback/ime/LeanbackKeyboardContainer.java @@ -36,6 +36,8 @@ import android.widget.RelativeLayout.LayoutParams; import com.google.android.leanback.ime.voice.RecognizerView; import com.google.android.leanback.ime.voice.SpeechLevelSource; import com.google.leanback.ime.LeanbackImeService; +import com.liskovsoft.inputchooser.ChooseKeyboardDialog; +import com.liskovsoft.inputchooser.SettingsActivity; import com.liskovsoft.keyboardaddons.KeyboardManager; import com.liskovsoft.leankeykeyboard.R; @@ -868,6 +870,12 @@ public class LeanbackKeyboardContainer { switchToNextKeyboard(); setTouchState(LeanbackKeyboardContainer.TOUCH_STATE_NO_TOUCH); return true; + } else if (keyCode == LeanbackKeyboardView.KEYCODE_LANG_TOGGLE) { + //Intent intent = new Intent(mContext, SettingsActivity.class); + //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + //mContext.startActivity(intent); + new ChooseKeyboardDialog(mContext, mMainKeyboardView).run(); + return true; } else { if (mCurrKeyInfo.type == KeyFocus.TYPE_MAIN) { mMainKeyboardView.onKeyLongPress(); diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/ChooseKeyboardDialog.java b/leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/ChooseKeyboardDialog.java new file mode 100644 index 0000000..96d8fcb --- /dev/null +++ b/leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/ChooseKeyboardDialog.java @@ -0,0 +1,131 @@ +package com.liskovsoft.inputchooser; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnDismissListener; +import android.content.res.TypedArray; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.CheckedTextView; +import com.liskovsoft.keyboardaddons.KeyboardInfo; +import com.liskovsoft.keyboardaddons.reslangfactory.ResKeyboardInfo; +import com.liskovsoft.leankeykeyboard.R; + +import java.util.ArrayList; +import java.util.List; + +public class ChooseKeyboardDialog implements OnClickListener { + private final View mInputView; + private final Context mContext; + private final List mInfos; + private AlertDialog alertDialog; + private ArrayList mLangViews; + + /** + * Main constructor. Use it in most of the cases. + * @param ctx context + */ + public ChooseKeyboardDialog(Context ctx) { + this(ctx, null); + } + + /** + * Special constructor. Useful when others didn't work. E.g. when running dialog within input method. + * @param ctx context + * @param inputView view to get token + */ + public ChooseKeyboardDialog(Context ctx, View inputView) { + mContext = ctx; + mInfos = ResKeyboardInfo.getAllKeyboardInfos(ctx); + mInputView = inputView; + } + + public void run() { + showDialog(); + } + + @TargetApi(17) + private void showDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + alertDialog = builder + .setTitle(R.string.language_dialog_title) + .setView(buildView(builder.getContext())) + .setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialogInterface) { + ResKeyboardInfo.updateAllKeyboardInfos(mContext, mInfos); + } + }) + .create(); + if (mInputView != null) { + initDialog(); // prepare to run from IME + } + alertDialog.show(); + } + + private void initDialog() { + Window window = alertDialog.getWindow(); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.token = mInputView.getWindowToken(); + lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; + window.setAttributes(lp); + window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + } + + @SuppressLint("InflateParams") + private View buildView(Context context) { + LayoutInflater inflater = LayoutInflater.from(context); + View view = inflater.inflate(R.layout.lang_selection_dialog, null); + ViewGroup root = view.findViewById(R.id.root); + + TypedArray attributeArray = context.getTheme().obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground}); + int selectableItemBackgroundResourceId = attributeArray.getResourceId(0, 0); + attributeArray.recycle(); + + mLangViews = new ArrayList<>(); + + for (KeyboardInfo info : mInfos) { + CheckedTextView langView = (CheckedTextView) inflater.inflate(android.R.layout.simple_list_item_multiple_choice, root, false); + langView.setBackgroundResource(selectableItemBackgroundResourceId); + langView.setText(info.getLangName()); + + langView.setFocusable(true); + langView.setTag(info); // our TAG + langView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources().getDimension(R.dimen.text_size_dp)); + langView.setOnClickListener(this); + mLangViews.add(langView); + root.addView(langView); + } + + updateViews(); + + return view; + } + + private void updateViews() { + for (CheckedTextView view : mLangViews) { + KeyboardInfo kbd = (KeyboardInfo) view.getTag(); + if (kbd.isEnabled()) { + view.setChecked(true); + } + } + } + + @Override + public void onClick(View view) { + KeyboardInfo kbd = (KeyboardInfo) view.getTag(); + // todo + CheckedTextView checkedView = (CheckedTextView) view; + boolean checked = checkedView.isChecked(); + kbd.setEnabled(!checked); + checkedView.setChecked(!checked); + } +} diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/SettingsActivity.java b/leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/SettingsActivity.java index fe39960..39d5847 100644 --- a/leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/SettingsActivity.java +++ b/leankeykeyboard/src/main/java/com/liskovsoft/inputchooser/SettingsActivity.java @@ -72,6 +72,7 @@ public class SettingsActivity extends Activity protected void onCreate(final Bundle bundle) { super.onCreate(bundle); + // new ChooseKeyboardDialog(this).run(); this.launchApp(); } } diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardFactory.java b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardFactory.java index 249df9a..a2fa627 100644 --- a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardFactory.java +++ b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardFactory.java @@ -6,4 +6,5 @@ import java.util.List; public interface KeyboardFactory { List getAllAvailableKeyboards(Context context); + boolean needUpdate(); } diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardInfo.java b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardInfo.java new file mode 100644 index 0000000..bd5e705 --- /dev/null +++ b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardInfo.java @@ -0,0 +1,10 @@ +package com.liskovsoft.keyboardaddons; + +public interface KeyboardInfo { + boolean isEnabled(); + String getLangCode(); + String getLangName(); + void setLangName(String langName); + void setLangCode(String langCode); + void setEnabled(boolean enabled); +} diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardManager.java b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardManager.java index 0b732a0..cb1de44 100644 --- a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardManager.java +++ b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/KeyboardManager.java @@ -2,7 +2,6 @@ package com.liskovsoft.keyboardaddons; import android.content.Context; import android.inputmethodservice.Keyboard; -import com.liskovsoft.keyboardaddons.apklangfactory.keyboards.ApkLangKeyboardFactory; import com.liskovsoft.keyboardaddons.reslangfactory.ResKeyboardFactory; import java.util.ArrayList; @@ -11,9 +10,9 @@ import java.util.List; public class KeyboardManager { private final Keyboard mEnglishKeyboard; private final Context mContext; - private final List mKeyboardBuilders; - private final List mAllKeyboards; - private final KeyboardFactory mKeyboardFactory; + private List mKeyboardBuilders; + private List mAllKeyboards; + private KeyboardFactory mKeyboardFactory; private int mKeyboardIndex = 0; public KeyboardManager(Context ctx, int keyboardResId) { @@ -23,8 +22,11 @@ public class KeyboardManager { public KeyboardManager(Context ctx, Keyboard englishKeyboard) { mContext = ctx; mEnglishKeyboard = englishKeyboard; - mKeyboardFactory = new ResKeyboardFactory(ctx); + init(); + } + private void init() { + mKeyboardFactory = new ResKeyboardFactory(mContext); mKeyboardBuilders = mKeyboardFactory.getAllAvailableKeyboards(mContext); mAllKeyboards = buildAllKeyboards(); } @@ -45,13 +47,18 @@ public class KeyboardManager { * @return keyboard */ public Keyboard getNextKeyboard() { + if (mKeyboardFactory.needUpdate()) { + init(); + } + + mKeyboardIndex = mKeyboardIndex < mAllKeyboards.size() ? mKeyboardIndex : 0; + Keyboard kbd = mAllKeyboards.get(mKeyboardIndex); if (kbd == null) { throw new IllegalStateException(String.format("Keyboard %s not initialized", mKeyboardIndex)); } ++mKeyboardIndex; - mKeyboardIndex = mKeyboardIndex < mAllKeyboards.size() ? mKeyboardIndex : 0; return kbd; } diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/apklangfactory/keyboards/ApkLangKeyboardFactory.java b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/apklangfactory/keyboards/ApkLangKeyboardFactory.java index edeaa1c..1711531 100644 --- a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/apklangfactory/keyboards/ApkLangKeyboardFactory.java +++ b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/apklangfactory/keyboards/ApkLangKeyboardFactory.java @@ -57,6 +57,12 @@ public class ApkLangKeyboardFactory extends AddOnsFactory getEnabledKeyboards(Context askContext) { final List allAddOns = getAllAddOns(askContext); Logger.i(TAG, "Creating enabled addons list. I have a total of " + allAddOns.size() + " addons"); diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardFactory.java b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardFactory.java index f6016c8..d08e312 100644 --- a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardFactory.java +++ b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardFactory.java @@ -6,6 +6,7 @@ import android.inputmethodservice.Keyboard; import android.support.annotation.Nullable; import com.liskovsoft.keyboardaddons.KeyboardBuilder; import com.liskovsoft.keyboardaddons.KeyboardFactory; +import com.liskovsoft.keyboardaddons.KeyboardInfo; import com.liskovsoft.leankeykeyboard.R; import java.util.ArrayList; @@ -21,18 +22,28 @@ public class ResKeyboardFactory implements KeyboardFactory { @Override public List getAllAvailableKeyboards(Context context) { List result = new ArrayList<>(); - String[] langs = mContext.getResources().getStringArray(R.array.additional_languages); + + List infos = ResKeyboardInfo.getAllKeyboardInfos(context); final Resources resources = mContext.getResources(); - for (final String langPair : langs) { - final String langCode = langPair.split("\\|")[1]; + + for (final KeyboardInfo info : infos) { + if (!info.isEnabled()) { + continue; + } + result.add(new KeyboardBuilder() { @Nullable @Override public Keyboard createKeyboard() { - return new Keyboard(mContext, resources.getIdentifier("qwerty_" + langCode, "xml", mContext.getPackageName())); + return new Keyboard(mContext, resources.getIdentifier("qwerty_" + info.getLangCode(), "xml", mContext.getPackageName())); } }); } return result; } + + @Override + public boolean needUpdate() { + return ResKeyboardInfo.needUpdate(); + } } diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardInfo.java b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardInfo.java new file mode 100644 index 0000000..c0eda0b --- /dev/null +++ b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardInfo.java @@ -0,0 +1,91 @@ +package com.liskovsoft.keyboardaddons.reslangfactory; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import com.liskovsoft.keyboardaddons.KeyboardInfo; +import com.liskovsoft.leankeykeyboard.R; + +import java.util.ArrayList; +import java.util.List; + +public class ResKeyboardInfo implements KeyboardInfo { + private static boolean sNeedUpdate; + private boolean mEnabled; + private String mLangCode; + private String mLangName; + + public static List getAllKeyboardInfos(Context ctx) { + List result = new ArrayList<>(); + String[] langs = ctx.getResources().getStringArray(R.array.additional_languages); + for (final String langPair : langs) { + String[] pairs = langPair.split("\\|"); + final String langName = pairs[0]; + final String langCode = pairs[1]; + KeyboardInfo info = new ResKeyboardInfo(); + info.setLangName(langName); + info.setLangCode(langCode); + // sync with prefs + syncWithPrefs(ctx, info); + result.add(info); + } + sNeedUpdate = false; + return result; + } + + public static void updateAllKeyboardInfos(Context ctx, List infos) { + for (KeyboardInfo info : infos) { + // update prefs + updatePrefs(ctx, info); + } + sNeedUpdate = true; + } + + private static void syncWithPrefs(Context ctx, KeyboardInfo info) { + final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx); + final boolean kbdEnabled = sharedPreferences.getBoolean(info.getLangCode(), false); + info.setEnabled(kbdEnabled); + } + + private static void updatePrefs(Context ctx, KeyboardInfo info) { + final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx); + + final SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(info.getLangCode(), info.isEnabled()); + editor.apply(); + } + + public static boolean needUpdate() { + return sNeedUpdate; + } + + @Override + public boolean isEnabled() { + return mEnabled; + } + + @Override + public String getLangCode() { + return mLangCode; + } + + @Override + public String getLangName() { + return mLangName; + } + + @Override + public void setLangName(String langName) { + mLangName = langName; + } + + @Override + public void setLangCode(String langCode) { + mLangCode = langCode; + } + + @Override + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } +} diff --git a/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardManager.java b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardManager.java new file mode 100644 index 0000000..6f2f514 --- /dev/null +++ b/leankeykeyboard/src/main/java/com/liskovsoft/keyboardaddons/reslangfactory/ResKeyboardManager.java @@ -0,0 +1,11 @@ +package com.liskovsoft.keyboardaddons.reslangfactory; + +import com.liskovsoft.keyboardaddons.KeyboardInfo; + +import java.util.List; + +public class ResKeyboardManager { + public List getAllKeyboardInfos() { + return null; + } +} diff --git a/leankeykeyboard/src/main/res/layout/lang_selection_dialog.xml b/leankeykeyboard/src/main/res/layout/lang_selection_dialog.xml new file mode 100644 index 0000000..b4fd9be --- /dev/null +++ b/leankeykeyboard/src/main/res/layout/lang_selection_dialog.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/leankeykeyboard/src/main/res/values/dimens.xml b/leankeykeyboard/src/main/res/values/dimens.xml index 0c9da27..b3f860e 100644 --- a/leankeykeyboard/src/main/res/values/dimens.xml +++ b/leankeykeyboard/src/main/res/values/dimens.xml @@ -27,4 +27,5 @@ 18.0sp 16.0sp 12.0dip + 15dp diff --git a/leankeykeyboard/src/main/res/values/strings.xml b/leankeykeyboard/src/main/res/values/strings.xml index 935f2d0..c6957f8 100644 --- a/leankeykeyboard/src/main/res/values/strings.xml +++ b/leankeykeyboard/src/main/res/values/strings.xml @@ -24,4 +24,5 @@ Right Plug in a headset to hear password keys spoken. Dot. + Select desired keyboards