I have a compound component that I created for use in my application. This 
component consists of two textviews and is designed to take character input 
(not using the textviews) and deal with it one character at a time.

Unfortunately, my customers are reporting that the component does not 
respond to the softkeyboard input on the Droid Bionic or Droid X2. This app 
has been in the market place since 2009 and works on every other device I 
have seen/tested it on. Something about these new phones have caused it to 
fail. In order to help me isolate the issue, I created a "debug" version 
that allowed the user to run the app on their Bionic (I don't have access 
to the device) and send me the logging information.

Based on this, I can see that the onKey... events for the component is only 
being reached for events like Menu and Back. The individual key events for 
the character presses are not being triggered. According to the users, the 
keyboard is not prompting them for word choices as they enter characters on 
their keyboards. I thought perhaps the keyboard was in some state like you 
might find when typing a text message. 

I've run out of ideas and would appreciate any help or suggestions you 
might have to offer.

This is a trimmed (somewhat) version of the component I am using. You can 
see that I was toggling between onKeyDown and onKeyListener to see if one 
worked better than the other - no such luck.

public class CompoundComponent extends LinearLayout {

private TextView textview1;
private TextView textview2;

private Context mContext;
private boolean mPunctuation = false;
private boolean mEntryDisabled = false;

public CompoundComponent(Context context, char code) {
super(context);

mContext = context;

buildComponent(code);

}

private void buildComponent(char code) {

// Set up the layout parameters
this.setOrientation(VERTICAL);
this.setOnTouchListener(mOnTouchListener);
this.setOnFocusChangeListener(mOnFocusChangeListener);
// this.setOnKeyListener(mOnKeyListener);
this.setPadding(DisplaySettings.VIEW_LR_PADDING,
DisplaySettings.VIEW_TB_PADDING,
DisplaySettings.VIEW_LR_PADDING,
DisplaySettings.VIEW_TB_PADDING);
this.setOnLongClickListener(mLongClickListener);


textview1 = new TextView(mContext);
textview1.setGravity(Gravity.CENTER_HORIZONTAL);
textview1.setTextSize(DisplaySettings.INSTANCE.getFontSize());
textview1.setTextColor(DisplaySettings.INSTANCE
.getTextColorLetter());
addView(textview1, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));


textview2 = new TextView(mContext);
textview2.setGravity(Gravity.CENTER_HORIZONTAL);
textview2.setTextSize(DisplaySettings.INSTANCE.getFontSize());
textview2.setTextColor(DisplaySettings.INSTANCE.getTextColorCode()); // 
.TEXTCOLOR_CODE);
addView(textview2, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

if (Character.isLetter(code)) {
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.setMinimumWidth(DisplaySettings.INSTANCE.getLetterViewWidth());
textview1.setBackgroundResource(DisplaySettings.INSTANCE
.getBackgroundLetterResId());
textview1.setText(" ");
textview2.setText(Character.toString(code));
mPunctuation = false;
}
else {
this.setFocusable(false);
this.setFocusableInTouchMode(false);
this.setMinimumWidth(DisplaySettings.INSTANCE.getOtherViewWidth());
textview1.setText(Character.toString(code));
textview2.setText("");
mPunctuation = true;
}
}


<snip...>

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

String key = null;
boolean bkspace = false; // used to trigger backspace behavior

if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("keyCode: " + Integer.toString(keyCode));
}
if (LogUtilities.DEBUGGING) {
LogUtilities
.Log_d("Punctuation: " + Boolean.toString(mPunctuation));
}
if (mPunctuation) {
// Can't update punctuation
return false;
}

if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyEvent Action Down");
}

KeyCharacterMap kcm = null;
try {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyCharacterMap Event DeviceId: "
+ Integer.toString(event.getDeviceId()));
}
kcm = KeyCharacterMap.load(event.getDeviceId());
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyCharacterMap Null: "
+ Boolean.toString(kcm == null));
}
}
catch (Exception e) {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyCharacterMap Exception: "
+ e.getMessage());
}
// TODO: Swallowing the exception - just for testing. Make
// sure to remove the whole try catch business from
// production version once this is figured out.
}

if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("kcm isPrintable: "
+ Boolean.toString(kcm.isPrintingKey(keyCode)));
}

char c = kcm.getDisplayLabel(keyCode);

if (Character.isLetter(c)) {
key = Character.toString(c).toUpperCase();
if (LogUtilities.DEBUGGING) {
LogUtilities
.Log_d("Character based on keyCode and KeyCharacterMap: "
+ key);
}
}
else {
switch (keyCode) {
// case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_CLEAR:
case KeyEvent.KEYCODE_SPACE:
key = " ";
break;
case KeyEvent.KEYCODE_DEL:
bkspace = true;
key = " ";
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
mLongClickListener.onLongClick(CompoundComponent.this);
return true;

case KeyEvent.KEYCODE_ENTER:
// Do nothing and don't process any further
return true;

default:
return false;
}
}

// If entry disabled, don't update the letter.
// This allows other keys (menu, dpad, back, etc) to be
// processed.
if (!mEntryDisabled) {
textview1.setText(key);
signalValueEntered(bkspace);
}
return true;
}
else {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("Action is not Down: "
+ Integer.toString(event.getAction()));
}
return false;
}
}

<snip...> 

View.OnFocusChangeListener mOnFocusChangeListener = new 
View.OnFocusChangeListener() {

@Override
public void onFocusChange(View v, boolean hasFocus) {

// Allow main routine can highlight all of the cells matching the
// code.
if (hasFocus) {
signalCellSelected();
}

}

};

View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {

CompoundComponent.this.requestFocus();

return false;
}

};

View.OnKeyListener mOnKeyListener = new View.OnKeyListener() {

@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {

String key = null;
boolean bkspace = false; // used to trigger backspace behavior

if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("keyCode: " + Integer.toString(keyCode));
}
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("Punctuation: "
+ Boolean.toString(mPunctuation));
}
if (mPunctuation) {
// Can't update punctuation
return false;
}

if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyEvent Action Down");
}

KeyCharacterMap kcm = null;
try {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyCharacterMap Event DeviceId: "
+ Integer.toString(event.getDeviceId()));
}
kcm = KeyCharacterMap.load(event.getDeviceId());
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyCharacterMap Null: "
+ Boolean.toString(kcm == null));
}
}
catch (Exception e) {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("KeyCharacterMap Exception: "
+ e.getMessage());
}
// TODO: Swallowing the exception - just for testing. Make
// sure to remove the whole try catch business from
// production version once this is figured out.
}

char[] arChar = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '0', '!', '@', '#', '$', '%', '^',
'&', '*', '(', ')', '=', '+', '-', '_', '[', ']', ' ' };

if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("kcm isPrintable: "
+ Boolean.toString(kcm.isPrintingKey(keyCode)));
LogUtilities.Log_d("kcm getMatch: "
+ kcm.getMatch(keyCode, arChar));
}

char c = kcm.getDisplayLabel(keyCode);

if (Character.isLetter(c)) {
key = Character.toString(c).toUpperCase();
if (LogUtilities.DEBUGGING) {
LogUtilities
.Log_d("Character based on keyCode and KeyCharacterMap: "
+ key);
}
}
else {
switch (keyCode) {
// case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_CLEAR:
case KeyEvent.KEYCODE_SPACE:
key = " ";
break;
case KeyEvent.KEYCODE_DEL:
bkspace = true;
key = " ";
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
mLongClickListener.onLongClick(CompoundComponent.this);
return true;

case KeyEvent.KEYCODE_ENTER:
// Do nothing and don't process any further
return true;

default:
return false;
}
}

// If entry disabled, don't update the letter.
// This allows other keys (menu, dpad, back, etc) to be
// processed.
if (!mEntryDisabled) {
textview1.setText(key);
signalValueEntered(bkspace);
}
return true;
}
else {
if (LogUtilities.DEBUGGING) {
LogUtilities.Log_d("Action is not Down: "
+ Integer.toString(event.getAction()));
}
return false;
}
}

};

public View.OnLongClickListener mLongClickListener = new 
View.OnLongClickListener() {

@Override
public boolean onLongClick(View v) {

softKeyboardResults rr = new softKeyboardResults();

Configuration config = CompoundComponent.this.getResources()
.getConfiguration();
if (config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES
|| config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_UNDEFINED) 
{
InputMethodManager imm = (InputMethodManager) 
CompoundComponent.this.mContext
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(CompoundComponent.this,
InputMethodManager.SHOW_IMPLICIT, rr);
}
return false;
}

};

class softKeyboardResults extends ResultReceiver {

public softKeyboardResults() {
super(getHandler());
}

@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);

switch (resultCode) {
case InputMethodManager.RESULT_HIDDEN:
case InputMethodManager.RESULT_SHOWN:
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
break;
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
InputMethodManager imm = (InputMethodManager) 
CompoundComponent.this.mContext
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(CompoundComponent.this,
InputMethodManager.SHOW_FORCED);
break;
default:
break;
}
}

}
}

Thank you in advance.

Best Regards,
Eric

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to