EditMessage.java

  1package eu.siacs.conversations.ui;
  2
  3import android.content.Context;
  4import android.os.Build;
  5import android.os.Handler;
  6import android.text.Editable;
  7import android.text.InputFilter;
  8import android.text.Spanned;
  9import android.util.AttributeSet;
 10import android.view.KeyEvent;
 11import android.widget.EditText;
 12
 13import eu.siacs.conversations.Config;
 14
 15public class EditMessage extends EditText {
 16
 17	public EditMessage(Context context, AttributeSet attrs) {
 18		super(context, attrs);
 19	}
 20
 21	public EditMessage(Context context) {
 22		super(context);
 23	}
 24
 25	protected Handler mTypingHandler = new Handler();
 26
 27	protected Runnable mTypingTimeout = new Runnable() {
 28		@Override
 29		public void run() {
 30			if (isUserTyping && keyboardListener != null) {
 31				keyboardListener.onTypingStopped();
 32				isUserTyping = false;
 33			}
 34		}
 35	};
 36
 37	private boolean isUserTyping = false;
 38
 39	private boolean lastInputWasTab = false;
 40
 41	protected KeyboardListener keyboardListener;
 42
 43	@Override
 44	public boolean onKeyDown(int keyCode, KeyEvent e) {
 45		if (keyCode == KeyEvent.KEYCODE_ENTER && !e.isShiftPressed()) {
 46			lastInputWasTab = false;
 47			if (keyboardListener != null && keyboardListener.onEnterPressed()) {
 48				return true;
 49			}
 50		} else if (keyCode == KeyEvent.KEYCODE_TAB && !e.isAltPressed() && !e.isCtrlPressed()) {
 51			if (keyboardListener != null && keyboardListener.onTabPressed(this.lastInputWasTab)) {
 52				lastInputWasTab = true;
 53				return true;
 54			}
 55		} else {
 56			lastInputWasTab = false;
 57		}
 58		return super.onKeyDown(keyCode, e);
 59	}
 60
 61	@Override
 62	public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
 63		super.onTextChanged(text,start,lengthBefore,lengthAfter);
 64		lastInputWasTab = false;
 65		if (this.mTypingHandler != null && this.keyboardListener != null) {
 66			this.mTypingHandler.removeCallbacks(mTypingTimeout);
 67			this.mTypingHandler.postDelayed(mTypingTimeout, Config.TYPING_TIMEOUT * 1000);
 68			final int length = text.length();
 69			if (!isUserTyping && length > 0) {
 70				this.isUserTyping = true;
 71				this.keyboardListener.onTypingStarted();
 72			} else if (length == 0) {
 73				this.isUserTyping = false;
 74				this.keyboardListener.onTextDeleted();
 75			}
 76			this.keyboardListener.onTextChanged();
 77		}
 78	}
 79
 80	public void setKeyboardListener(KeyboardListener listener) {
 81		this.keyboardListener = listener;
 82		if (listener != null) {
 83			this.isUserTyping = false;
 84		}
 85	}
 86
 87	public interface KeyboardListener {
 88		boolean onEnterPressed();
 89		void onTypingStarted();
 90		void onTypingStopped();
 91		void onTextDeleted();
 92		void onTextChanged();
 93		boolean onTabPressed(boolean repeated);
 94	}
 95
 96	private static final InputFilter SPAN_FILTER = new InputFilter() {
 97
 98		@Override
 99		public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
100			return source instanceof Spanned ? source.toString() : source;
101		}
102	};
103
104	@Override
105	public boolean onTextContextMenuItem(int id) {
106		if (id == android.R.id.paste) {
107			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
108				return super.onTextContextMenuItem(android.R.id.pasteAsPlainText);
109			} else {
110				Editable editable = getEditableText();
111				InputFilter[] filters = editable.getFilters();
112				InputFilter[] tempFilters = new InputFilter[filters != null ? filters.length + 1 : 1];
113				if (filters != null) {
114					System.arraycopy(filters, 0, tempFilters, 1, filters.length);
115				}
116				tempFilters[0] = SPAN_FILTER;
117				editable.setFilters(tempFilters);
118				try {
119					return super.onTextContextMenuItem(id);
120				} finally {
121					editable.setFilters(filters);
122				}
123			}
124		} else {
125			return super.onTextContextMenuItem(id);
126		}
127	}
128}