AlphaNERD
AlphaNERD

Reputation: 385

Apply theme dynamically for Android Keyboard

Hello people at StackOverflow,

i have encountered a problem while programming a soft keyboard :

What i want to achieve is that the soft keyboard loads dynamically a theme/style optimized for typing at night and a theme/style for typing in sunlight. The styles are already defined and i can already switch them easily by only changing the style in input.xml.

import ... /*Not quite relevant (yet)*/

public class LatinKeyboardView extends KeyboardView {

public LatinKeyboardView(Context context, AttributeSet attrs) {
    this(context, attrs, loadColor());
}

public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle)                 {
    super(context, attrs, defStyle);

}

public static int loadColor() {

    String dbg = android.os.Debug.isDebuggerConnected() ? "Y" : "N";

    android.util.Log.d("loadColor", "Debugger connected: " +  dbg);

    android.os.Debug.waitForDebugger();

    int temp = 0;
    int id = 0;

    if (temp == 1)
    {
        id = R.style.KeyStyle_Day;
    }
    else
    {
        id =  R.style.KeyStyle_Night;
    }

    android.util.Log.d("loadColor", Integer.toString(id));
    return id;
}

When i redirect the call from the first constructor to the second constructor (as seen in Hacker's Keyboard source code), the soft keyboard loads successfully the style id in loadColor(), but after it, there happens internally an exception which i can't manage to trace back, even with the stack trace :

03-19 08:32:48.313  18630-18630/com.alphanerd.eztype.keyboard E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.alphanerd.eztype.keyboard, PID: 18630
    android.view.InflateException: Binary XML file line #21: Error inflating class com.alphanerd.eztype.keyboard.LatinKeyboardView
            at android.view.LayoutInflater.createView(LayoutInflater.java:626)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:470)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
            at com.alphanerd.eztype.keyboard.EZTypeKeyboard.onCreateInputView(EZTypeKeyboard.java:125)
            at android.inputmethodservice.InputMethodService.updateInputViewShown(InputMethodService.java:1594)
            at android.inputmethodservice.InputMethodService.showWindowInner(InputMethodService.java:2220)
            at android.inputmethodservice.InputMethodService.showWindow(InputMethodService.java:2179)
            at android.inputmethodservice.InputMethodService$InputMethodImpl.showSoftInput(InputMethodService.java:712)
            at android.inputmethodservice.IInputMethodWrapper.executeMessage(IInputMethodWrapper.java:214)
            at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:40)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:157)
            at android.app.ActivityThread.main(ActivityThread.java:5335)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.reflect.InvocationTargetException
            at java.lang.reflect.Constructor.constructNative(Native Method)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
            at android.view.LayoutInflater.createView(LayoutInflater.java:600)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:470)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
            at com.alphanerd.eztype.keyboard.EZTypeKeyboard.onCreateInputView(EZTypeKeyboard.java:125)
            at android.inputmethodservice.InputMethodService.updateInputViewShown(InputMethodService.java:1594)
            at android.inputmethodservice.InputMethodService.showWindowInner(InputMethodService.java:2220)
            at android.inputmethodservice.InputMethodService.showWindow(InputMethodService.java:2179)
            at android.inputmethodservice.InputMethodService$InputMethodImpl.showSoftInput(InputMethodService.java:712)
            at android.inputmethodservice.IInputMethodWrapper.executeMessage(IInputMethodWrapper.java:214)
            at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:40)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:157)
            at android.app.ActivityThread.main(ActivityThread.java:5335)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException
            at android.inputmethodservice.KeyboardView.<init>(KeyboardView.java:370)
            at com.alphanerd.eztype.keyboard.LatinKeyboardView.<init>(LatinKeyboardView.java:53)
            at java.lang.reflect.Constructor.constructNative(Native Method)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
            at android.view.LayoutInflater.createView(LayoutInflater.java:600)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:470)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
            at com.alphanerd.eztype.keyboard.EZTypeKeyboard.onCreateInputView(EZTypeKeyboard.java:125)
            at android.inputmethodservice.InputMethodService.updateInputViewShown(InputMethodService.java:1594)
            at android.inputmethodservice.InputMethodService.showWindowInner(InputMethodService.java:2220)
            at android.inputmethodservice.InputMethodService.showWindow(InputMethodService.java:2179)
            at android.inputmethodservice.InputMethodService$InputMethodImpl.showSoftInput(InputMethodService.java:712)
            at android.inputmethodservice.IInputMethodWrapper.executeMessage(IInputMethodWrapper.java:214)
            at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:40)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:157)
            at android.app.ActivityThread.main(ActivityThread.java:5335)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
            at dalvik.system.NativeStart.main(Native Method)

I hope, you can help me with that. The code for dynamically loading the color is currently as dynamic as the int temp; , but later on i'll implement the logic for loading the color from sharedpreferences (the keyboard is actually meant to integrate (optically) with another app my corp is developing)

Thanks in advance for any help :)

Upvotes: 3

Views: 2313

Answers (1)

AlphaNERD
AlphaNERD

Reputation: 385

I found a solution, which i think is very simple as soon as i found it : Instead of hacking any constructor etc., i edited the overridden onCreateInputView :

@Override
public View onCreateInputView() {
    int schema = loadColor();

    //Default code

    //mInputView = (LatinKeyboardView) getLayoutInflater().inflate(
    //      R.layout.input, null);

    mInputView = (LatinKeyboardView) getLayoutInflater().inflate(
            schema, null);

    mInputView.setOnKeyboardActionListener(this);
    mInputView.setKeyboard(mQwertyKeyboard);
    return mInputView;
}

public static int loadColor() {

    String dbg = android.os.Debug.isDebuggerConnected() ? "Y" : "N";

    android.util.Log.d("loadColor", "Debugger attached: " +  dbg);

    //android.os.Debug.waitForDebugger(); //Comment this out before releasing the keyboard

    int temp = 1;
    int id = 0;

    if (temp == 1)
    {
        id = R.layout.input_day;
    }
    else
    {
        id =  R.layout.input;
    }

    android.util.Log.d("loadColor", Integer.toString(id));
    return id;
}

Normally, the LayoutInflater would load the default input layout as intended by google. I can recommend to define multiple input layouts, each with their own style. If your own custom keyboard shall support user - made themes, just create an input layout and refer in there to a style, which refers to the theme images. Place all loaded loaded theme images in a special folder accessible to the themeable input xml.

One last hint : You can debug a soft keyboard by placing android.os.Debug.waitForDebugger(); in the code. The keyboard (or any other app) will wait for the debugger to attach. Remember to remove every waitForDebugger() call before releasing your app, or else the app will stop running everywhere you forgot to remove this line. I hope, i could help anyone reading this.

Thank you and have a nice day :)

Upvotes: 1

Related Questions