Reputation: 5705
I want to create my own emoji keyboard in android. User should be able to select this keyboard as an input method for his android phone.
I tried creating it and I am able to use it in my app but I have no idea how to make this as an input method so this keyboard will be available to all other apps in my phone. I read somewhere that I have to create a service for that so that it bind with input service.Other than that I am not able to understand rest of the thing.
Here is what I did. Though it is different from what I want to do but is start and don't know how to proceed further.
public class MainActivity extends FragmentActivity implements EmoticonsGridAdapter.KeyClickListener {
private static final int NO_OF_EMOTICONS = 100;
private ListView chatList;
private View popUpView;
private ArrayList<Spanned> chats;
private ChatListAdapter mAdapter;
private LinearLayout emoticonsCover;
private PopupWindow popupWindow;
private int keyboardHeight;
private EditText content;
private LinearLayout parentLayout;
private boolean isKeyBoardVisible;
private Bitmap[] emoticons;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chatList = (ListView) findViewById(R.id.chat_list);
parentLayout = (LinearLayout) findViewById(R.id.list_parent);
emoticonsCover = (LinearLayout) findViewById(R.id.footer_for_emoticons);
popUpView = getLayoutInflater().inflate(R.layout.emoticons_popup, null);
// Setting adapter for chat list
chats = new ArrayList<Spanned>();
mAdapter = new ChatListAdapter(getApplicationContext(), chats);
chatList.setAdapter(mAdapter);
chatList.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (popupWindow.isShowing())
popupWindow.dismiss();
return false;
}
});
// Defining default height of keyboard which is equal to 230 dip
final float popUpheight = getResources().getDimension(
R.dimen.keyboard_height);
changeKeyboardHeight((int) popUpheight);
// Showing and Dismissing pop up on clicking emoticons button
ImageView emoticonsButton = (ImageView) findViewById(R.id.emoticons_button);
emoticonsButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (!popupWindow.isShowing()) {
popupWindow.setHeight((int) (keyboardHeight));
if (isKeyBoardVisible) {
emoticonsCover.setVisibility(LinearLayout.GONE);
} else {
emoticonsCover.setVisibility(LinearLayout.VISIBLE);
}
popupWindow.showAtLocation(parentLayout, Gravity.BOTTOM, 0, 0);
} else {
popupWindow.dismiss();
}
}
});
readEmoticons();
enablePopUpView();
checkKeyboardHeight(parentLayout);
enableFooterView();
}
/**
* Reading all emoticons in local cache
*/
private void readEmoticons () {
emoticons = new Bitmap[NO_OF_EMOTICONS];
for (short i = 0; i < NO_OF_EMOTICONS; i++) {
emoticons[i] = getImage((i+1) + ".png");
}
}
/**
* Enabling all content in footer i.e. post window
*/
private void enableFooterView() {
content = (EditText) findViewById(R.id.chat_content);
content.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (popupWindow.isShowing()) {
popupWindow.dismiss();
}
}
});
final Button postButton = (Button) findViewById(R.id.post_button);
postButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (content.getText().toString().length() > 0) {
Spanned sp = content.getText();
chats.add(sp);
content.setText("");
mAdapter.notifyDataSetChanged();
}
}
});
}
/**
* Overriding onKeyDown for dismissing keyboard on key down
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (popupWindow.isShowing()) {
popupWindow.dismiss();
return false;
} else {
return super.onKeyDown(keyCode, event);
}
}
/**
* Checking keyboard height and keyboard visibility
*/
int previousHeightDiffrence = 0;
private void checkKeyboardHeight(final View parentLayout) {
parentLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
parentLayout.getWindowVisibleDisplayFrame(r);
int screenHeight = parentLayout.getRootView()
.getHeight();
int heightDifference = screenHeight - (r.bottom);
if (previousHeightDiffrence - heightDifference > 50) {
popupWindow.dismiss();
}
previousHeightDiffrence = heightDifference;
if (heightDifference > 100) {
isKeyBoardVisible = true;
changeKeyboardHeight(heightDifference);
} else {
isKeyBoardVisible = false;
}
}
});
}
/**
* change height of emoticons keyboard according to height of actual
* keyboard
*
* @param height
* minimum height by which we can make sure actual keyboard is
* open or not
*/
private void changeKeyboardHeight(int height) {
if (height > 100) {
keyboardHeight = height;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, keyboardHeight);
emoticonsCover.setLayoutParams(params);
}
}
/**
* Defining all components of emoticons keyboard
*/
private void enablePopUpView() {
ViewPager pager = (ViewPager) popUpView.findViewById(R.id.emoticons_pager);
pager.setOffscreenPageLimit(3);
pager.setBackgroundColor(Color.WHITE);
ArrayList<String> paths = new ArrayList<String>();
for (short i = 1; i <= NO_OF_EMOTICONS; i++) {
paths.add(i + ".png");
}
EmoticonsPagerAdapter adapter = new EmoticonsPagerAdapter(MainActivity.this, paths, this);
pager.setAdapter(adapter);
// Creating a pop window for emoticons keyboard
popupWindow = new PopupWindow(popUpView, LayoutParams.MATCH_PARENT,
(int) keyboardHeight, false);
/*TextView backSpace = (TextView) popUpView.findViewById(R.id.back);
backSpace.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL);
content.dispatchKeyEvent(event);
}
});*/
popupWindow.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
emoticonsCover.setVisibility(LinearLayout.GONE);
}
});
}
/**
* For loading smileys from assets
*/
private Bitmap getImage(String path) {
AssetManager mngr = getAssets();
InputStream in = null;
try {
in = mngr.open("emoticons/" + path);
} catch (Exception e) {
e.printStackTrace();
}
Bitmap temp = BitmapFactory.decodeStream(in, null, null);
return temp;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
@Override
public void keyClickedIndex(final String index) {
ImageGetter imageGetter = new ImageGetter() {
public Drawable getDrawable(String source) {
StringTokenizer st = new StringTokenizer(index, ".");
Drawable d = new BitmapDrawable(getResources(),emoticons[Integer.parseInt(st.nextToken()) - 1]);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
return d;
}
};
Spanned cs = Html.fromHtml("<img src ='"+ index +"'/>", imageGetter, null);
int cursorPosition = content.getSelectionStart();
content.getText().insert(cursorPosition, cs);
}
}
EDIT: This is the code for custom keyboard that I have implemented but I am unable to find how to add emoji to that keyboard.
public class SimpleIME extends InputMethodService
implements KeyboardView.OnKeyboardActionListener {
private KeyboardView kv;
private Keyboard keyboard;
private View popUpView;
private boolean caps = false;
@Override
public View onCreateInputView() {
kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null);
keyboard = new Keyboard(this, R.xml.qwerty);
kv.setKeyboard(keyboard);
kv.setOnKeyboardActionListener(this);
kv.invalidateAllKeys();
popUpView = getLayoutInflater().inflate(R.layout.emoticons_popup, null);
return kv;
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
InputConnection ic = getCurrentInputConnection();
playClick(primaryCode);
switch(primaryCode){
case Keyboard.KEYCODE_DELETE :
ic.deleteSurroundingText(1, 0);
break;
case Keyboard.KEYCODE_SHIFT:
caps = !caps;
keyboard.setShifted(caps);
kv.invalidateAllKeys();
break;
case Keyboard.KEYCODE_DONE:
ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
break;
case -80 :
Log.d("smiley", "smiley pressed");
break;
default:
char code = (char)primaryCode;
if(Character.isLetter(code) && caps){
code = Character.toUpperCase(code);
}
ic.commitText(String.valueOf(code),1);
}
}
private void playClick(int keyCode){
AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
switch(keyCode){
case 32:
am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
break;
case Keyboard.KEYCODE_DONE:
case 10:
am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
break;
case Keyboard.KEYCODE_DELETE:
am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
break;
default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
}
}
@Override
public void onPress(int primaryCode) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeDown() {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeUp() {
}
}
EDIT: Can we copy an image from images list and paste it where keyboard is open??
Upvotes: 4
Views: 9991
Reputation: 189
The best implementation for an emoji keyboard I found was that of sliding emoji-Keyboard It's a really good implementation, maybe with some redundant code, but still really good for understanding how to implement keyboards that do not fit the normal "button-to-text" keyboards.
UPDATE
Okay, I have now been able to successfully able to integrate the sliding emoji-keyboard into my own project 8Vim after a lot of re-factoring in both of the projects.
Essentially, all you are doing for the emoji keyboard is to create a view of the size of the keyboard and then populating that view with PNG files corresponding to the emoji's. each image acts like a button and delivers the appropriate emoji to the inputConnection.
UPDATE 2
I have extended the sliding emoji-keyboard and created a much cleaner version that should be easier to understand. Take a look at my emoji-keyboard
Upvotes: 3