blob: afc2e04792eea330e6258280f46d32506fabe2c2 [file] [log] [blame]
package org.wordpress.android.widgets;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.MultiAutoCompleteTextView;
import org.wordpress.android.ui.suggestion.util.SuggestionTokenizer;
import org.wordpress.persistentedittext.PersistentEditTextHelper;
public class SuggestionAutoCompleteText extends MultiAutoCompleteTextView {
PersistentEditTextHelper mPersistentEditTextHelper;
private OnEditTextBackListener mBackListener;
public interface OnEditTextBackListener {
void onEditTextBack();
}
public SuggestionAutoCompleteText(Context context) {
super(context, null);
init(context, null);
}
public SuggestionAutoCompleteText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public SuggestionAutoCompleteText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypefaceCache.setCustomTypeface(context, this, attrs);
setTokenizer(new SuggestionTokenizer());
setThreshold(1);
mPersistentEditTextHelper = new PersistentEditTextHelper(context);
// When TYPE_TEXT_FLAG_AUTO_COMPLETE is set, autocorrection is disabled.
setRawInputType(getInputType() & ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
}
public PersistentEditTextHelper getAutoSaveTextHelper() {
return mPersistentEditTextHelper;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (getAutoSaveTextHelper().getUniqueId() == null) {
return;
}
getAutoSaveTextHelper().loadString(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (getAutoSaveTextHelper().getUniqueId() == null) {
return;
}
getAutoSaveTextHelper().saveString(this);
}
public void setOnBackListener(OnEditTextBackListener listener) {
mBackListener = listener;
}
@Override
public Parcelable onSaveInstanceState() {
SavedState savedState = new SavedState(super.onSaveInstanceState());
// store the current Focused state
savedState.isFocused = isFocused();
return savedState;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if(!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState savedState = (SavedState)state;
super.onRestoreInstanceState(savedState.getSuperState());
// if we were focused, setup a properly timed future request for focus
if (savedState.isFocused) {
// this OnLayoutChangeListener will self unregister upon running and it's there so we can properly time the
// on-screen IME opening
addOnLayoutChangeListener(mOneoffFocusRequest);
}
}
private final OnLayoutChangeListener mOneoffFocusRequest = new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
int oldRight, int oldBottom) {
// we're now at a good point in time to launch a focus request
post(new Runnable() {
@Override
public void run() {
// self unregister so we won't auto-request focus again
removeOnLayoutChangeListener(mOneoffFocusRequest);
// request focus
setFocusableInTouchMode(true);
requestFocus();
}
});
}
};
@Override
public boolean performClick() {
// make sure we are focusable otherwise we will not get focused
setFocusableInTouchMode(true);
requestFocus();
return super.performClick();
}
/*
* detect when user hits the back button while soft keyboard is showing (hiding the keyboard)
*/
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
// clear focus but stop being focusable first. This way we won't receive focus if we're the only focusable
// widget on the page
setFocusableInTouchMode(false);
clearFocus();
if (mBackListener != null) {
mBackListener.onEditTextBack();
}
}
return super.dispatchKeyEvent(event);
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
// if no hardware keys are present, associate being focused to having the on-screen keyboard visible
if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) {
InputMethodManager inputMethodManager = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (focused) {
// show the on-screen keybpoard if we got focused
inputMethodManager.showSoftInput(this, 0);
} else {
// stop being focusable so closing the keyboard won't focus us
setFocusableInTouchMode(false);
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
}
}
}
/**
* Local class for holding the EditBox's focused or not state
*/
static class SavedState extends BaseSavedState {
boolean isFocused;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
this.isFocused = (in.readInt() == 1);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(this.isFocused ? 1 : 0);
}
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}