Sunday, February 20, 2011

Android Activity Custom Keyboard

Original Question

The following code demonstrates how to add a custom keyboard to an activity without having to install a third-party keyboard app.

Edit: I have created a project on Google Code which makes the following code obsolete. Please check it out.

Instructions:
  1. add the following files to your project
  2. copy the necessary drawables from \android\platforms\<platform>\data\res\ to your project
  3. profit?

/res/layout/demo.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent" android:layout_height="fill_parent">
 <Button android:id="@+id/button" android:background="@drawable/sym_keyboard_done"
  android:layout_height="fill_parent" android:layout_width="fill_parent" />
 <LinearLayout android:layout_height="wrap_content"
  android:layout_width="wrap_content">
  <android.inputmethodservice.KeyboardView
   android:id="@+id/keyboardView" android:visibility="gone"
   android:focusable="true" android:focusableInTouchMode="true"
   android:layout_height="wrap_content" android:layout_width="wrap_content"
   android:layout_weight="0" />
 </LinearLayout>
</FrameLayout>

/res/xml/qwerty.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
/** 
 *
 * Copyright 2008, 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.
 */
-->

<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="10%p"
    android:horizontalGap="0px"
    android:verticalGap="0px">

    <Row>
        <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
        <Key android:codes="119" android:keyLabel="w"/>
        <Key android:codes="101" android:keyLabel="e"/>
        <Key android:codes="114" android:keyLabel="r"/>
        <Key android:codes="116" android:keyLabel="t"/>
        <Key android:codes="121" android:keyLabel="y"/>
        <Key android:codes="117" android:keyLabel="u"/>
        <Key android:codes="105" android:keyLabel="i"/>
        <Key android:codes="111" android:keyLabel="o"/>
        <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
    </Row>

    <Row>
        <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p" 
                android:keyEdgeFlags="left"/>
        <Key android:codes="115" android:keyLabel="s"/>
        <Key android:codes="100" android:keyLabel="d"/>
        <Key android:codes="102" android:keyLabel="f"/>
        <Key android:codes="103" android:keyLabel="g"/>
        <Key android:codes="104" android:keyLabel="h"/>
        <Key android:codes="106" android:keyLabel="j"/>
        <Key android:codes="107" android:keyLabel="k"/>
        <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
    </Row>

    <Row>
        <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift" 
                android:keyWidth="15%p" android:isModifier="true"
                android:isSticky="true" android:keyEdgeFlags="left"/>
        <Key android:codes="122" android:keyLabel="z"/>
        <Key android:codes="120" android:keyLabel="x"/>
        <Key android:codes="99" android:keyLabel="c"/>
        <Key android:codes="118" android:keyLabel="v"/>
        <Key android:codes="98" android:keyLabel="b"/>
        <Key android:codes="110" android:keyLabel="n"/>
        <Key android:codes="109" android:keyLabel="m"/>
        <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete" 
                android:keyWidth="15%p" android:keyEdgeFlags="right"
                android:isRepeatable="true"/>
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key android:codes="-3" android:keyIcon="@drawable/sym_keyboard_done" 
                android:keyWidth="20%p" android:keyEdgeFlags="left"/>
        <Key android:codes="-2" android:keyLabel="123" android:keyWidth="15%p"/>
        <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space" 
                android:keyWidth="30%p" android:isRepeatable="true"/>
        <Key android:codes="46,44" android:keyLabel=". ,"
                android:keyWidth="15%p"/>
        <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return" 
                android:keyWidth="20%p" android:keyEdgeFlags="right"/>
    </Row>
</Keyboard>

public class DemoActivity extends Activity implements OnKeyListener,
  OnKeyboardActionListener {

 private static final String TAG = DemoActivity.class.getName();

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.demo);

  KeyboardView keyboardView = (KeyboardView) findViewById(R.id.keyboardView);
  Keyboard keyboard = new Keyboard(this, R.xml.qwerty);
  keyboardView.setKeyboard(keyboard);
  keyboardView.setEnabled(true);
  keyboardView.setPreviewEnabled(true);
  keyboardView.setOnKeyListener(this);
  keyboardView.setOnKeyboardActionListener(this);

  View button = findViewById(R.id.button);
  button.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    toggleKeyboardVisibility();
   }
  });
 }

 private void toggleKeyboardVisibility() {
  KeyboardView keyboardView = (KeyboardView) findViewById(R.id.keyboardView);
  int visibility = keyboardView.getVisibility();
  switch (visibility) {
   case View.VISIBLE:
    keyboardView.setVisibility(View.INVISIBLE);
    break;
   case View.GONE:
   case View.INVISIBLE:
    keyboardView.setVisibility(View.VISIBLE);
    break;
  }
 }

 @Override
 public boolean onKey(View v, int keyCode, KeyEvent event) {
  Log.d(TAG, "onKey? keyCode=" + keyCode);
  return false;
 }

 @Override
 public void swipeUp() {
  Log.d(TAG, "swipeUp");
 }

 @Override
 public void swipeRight() {
  Log.d(TAG, "swipeRight");
 }

 @Override
 public void swipeLeft() {
  Log.d(TAG, "swipeLeft");
 }

 @Override
 public void swipeDown() {
  Log.d(TAG, "swipeDown");
 }

 @Override
 public void onText(CharSequence text) {
  Log.d(TAG, "onText? \"" + text + "\"");
 }

 @Override
 public void onRelease(int primaryCode) {
  Log.d(TAG, "onRelease? primaryCode=" + primaryCode);
 }

 @Override
 public void onPress(int primaryCode) {
  Log.d(TAG, "onPress? primaryCode=" + primaryCode);
 }

 @Override
 public void onKey(int primaryCode, int[] keyCodes) {
  Log.d(TAG, "onKey? primaryCode=" + primaryCode);
  int n1 = 0; // -1 count
  for (int keyCode : keyCodes) {
   if (keyCode == -1) {
    n1++;
    continue;
   }
   Log.v(TAG, "keyCode=" + keyCode);
  }
  Log.v(TAG, "keyCode=-1 *" + n1);
 }

}