run keyboard listeners on background executor
This commit is contained in:
		
							parent
							
								
									39bc067405
								
							
						
					
					
						commit
						7a825231fb
					
				| @ -19,176 +19,184 @@ import android.view.KeyEvent; | ||||
| import android.view.inputmethod.EditorInfo; | ||||
| import android.view.inputmethod.InputConnection; | ||||
| 
 | ||||
| import java.util.concurrent.ExecutorService; | ||||
| import java.util.concurrent.Executors; | ||||
| 
 | ||||
| import eu.siacs.conversations.Config; | ||||
| import eu.siacs.conversations.R; | ||||
| 
 | ||||
| public class EditMessage extends EmojiWrapperEditText { | ||||
| 
 | ||||
| 	private static final InputFilter SPAN_FILTER = (source, start, end, dest, dstart, dend) -> source instanceof Spanned ? source.toString() : source; | ||||
| 	protected Handler mTypingHandler = new Handler(); | ||||
| 	protected KeyboardListener keyboardListener; | ||||
| 	private OnCommitContentListener mCommitContentListener = null; | ||||
| 	private String[] mimeTypes = null; | ||||
| 	private boolean isUserTyping = false; | ||||
| 	protected Runnable mTypingTimeout = new Runnable() { | ||||
| 		@Override | ||||
| 		public void run() { | ||||
| 			if (isUserTyping && keyboardListener != null) { | ||||
| 				keyboardListener.onTypingStopped(); | ||||
| 				isUserTyping = false; | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
| 	private boolean lastInputWasTab = false; | ||||
|     private static final InputFilter SPAN_FILTER = (source, start, end, dest, dstart, dend) -> source instanceof Spanned ? source.toString() : source; | ||||
|     private final ExecutorService executor = Executors.newSingleThreadExecutor(); | ||||
|     protected Handler mTypingHandler = new Handler(); | ||||
|     protected KeyboardListener keyboardListener; | ||||
|     private OnCommitContentListener mCommitContentListener = null; | ||||
|     private String[] mimeTypes = null; | ||||
|     private boolean isUserTyping = false; | ||||
|     private final Runnable mTypingTimeout = new Runnable() { | ||||
|         @Override | ||||
|         public void run() { | ||||
|             if (isUserTyping && keyboardListener != null) { | ||||
|                 keyboardListener.onTypingStopped(); | ||||
|                 isUserTyping = false; | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|     private boolean lastInputWasTab = false; | ||||
| 
 | ||||
| 	public EditMessage(Context context, AttributeSet attrs) { | ||||
| 		super(context, attrs); | ||||
| 	} | ||||
|     public EditMessage(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|     } | ||||
| 
 | ||||
| 	public EditMessage(Context context) { | ||||
| 		super(context); | ||||
| 	} | ||||
|     public EditMessage(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public boolean onKeyDown(int keyCode, KeyEvent e) { | ||||
| 		if (keyCode == KeyEvent.KEYCODE_ENTER && !e.isShiftPressed()) { | ||||
| 			lastInputWasTab = false; | ||||
| 			if (keyboardListener != null && keyboardListener.onEnterPressed()) { | ||||
| 				return true; | ||||
| 			} | ||||
| 		} else if (keyCode == KeyEvent.KEYCODE_TAB && !e.isAltPressed() && !e.isCtrlPressed()) { | ||||
| 			if (keyboardListener != null && keyboardListener.onTabPressed(this.lastInputWasTab)) { | ||||
| 				lastInputWasTab = true; | ||||
| 				return true; | ||||
| 			} | ||||
| 		} else { | ||||
| 			lastInputWasTab = false; | ||||
| 		} | ||||
| 		return super.onKeyDown(keyCode, e); | ||||
| 	} | ||||
|     @Override | ||||
|     public boolean onKeyDown(int keyCode, KeyEvent e) { | ||||
|         if (keyCode == KeyEvent.KEYCODE_ENTER && !e.isShiftPressed()) { | ||||
|             lastInputWasTab = false; | ||||
|             if (keyboardListener != null && keyboardListener.onEnterPressed()) { | ||||
|                 return true; | ||||
|             } | ||||
|         } else if (keyCode == KeyEvent.KEYCODE_TAB && !e.isAltPressed() && !e.isCtrlPressed()) { | ||||
|             if (keyboardListener != null && keyboardListener.onTabPressed(this.lastInputWasTab)) { | ||||
|                 lastInputWasTab = true; | ||||
|                 return true; | ||||
|             } | ||||
|         } else { | ||||
|             lastInputWasTab = false; | ||||
|         } | ||||
|         return super.onKeyDown(keyCode, e); | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public int getAutofillType() { | ||||
| 		return AUTOFILL_TYPE_NONE; | ||||
| 	} | ||||
|     @Override | ||||
|     public int getAutofillType() { | ||||
|         return AUTOFILL_TYPE_NONE; | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { | ||||
| 		super.onTextChanged(text, start, lengthBefore, lengthAfter); | ||||
| 		lastInputWasTab = false; | ||||
| 		if (this.mTypingHandler != null && this.keyboardListener != null) { | ||||
| 			this.mTypingHandler.removeCallbacks(mTypingTimeout); | ||||
| 			this.mTypingHandler.postDelayed(mTypingTimeout, Config.TYPING_TIMEOUT * 1000); | ||||
| 			final int length = text.length(); | ||||
| 			if (!isUserTyping && length > 0) { | ||||
| 				this.isUserTyping = true; | ||||
| 				this.keyboardListener.onTypingStarted(); | ||||
| 			} else if (length == 0) { | ||||
| 				this.isUserTyping = false; | ||||
| 				this.keyboardListener.onTextDeleted(); | ||||
| 			} | ||||
| 			this.keyboardListener.onTextChanged(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void setKeyboardListener(KeyboardListener listener) { | ||||
| 		this.keyboardListener = listener; | ||||
| 		if (listener != null) { | ||||
| 			this.isUserTyping = false; | ||||
| 		} | ||||
| 	} | ||||
|     @Override | ||||
|     public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { | ||||
|         super.onTextChanged(text, start, lengthBefore, lengthAfter); | ||||
|         lastInputWasTab = false; | ||||
|         if (this.mTypingHandler != null && this.keyboardListener != null) { | ||||
|             executor.execute(() -> triggerKeyboardEvents(text.length())); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public boolean onTextContextMenuItem(int id) { | ||||
| 		if (id == android.R.id.paste) { | ||||
| 			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
| 				return super.onTextContextMenuItem(android.R.id.pasteAsPlainText); | ||||
| 			} else { | ||||
| 				Editable editable = getEditableText(); | ||||
| 				InputFilter[] filters = editable.getFilters(); | ||||
| 				InputFilter[] tempFilters = new InputFilter[filters != null ? filters.length + 1 : 1]; | ||||
| 				if (filters != null) { | ||||
| 					System.arraycopy(filters, 0, tempFilters, 1, filters.length); | ||||
| 				} | ||||
| 				tempFilters[0] = SPAN_FILTER; | ||||
| 				editable.setFilters(tempFilters); | ||||
| 				try { | ||||
| 					return super.onTextContextMenuItem(id); | ||||
| 				} finally { | ||||
| 					editable.setFilters(filters); | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			return super.onTextContextMenuItem(id); | ||||
| 		} | ||||
| 	} | ||||
|     private void triggerKeyboardEvents(final int length) { | ||||
|         this.mTypingHandler.removeCallbacks(mTypingTimeout); | ||||
|         this.mTypingHandler.postDelayed(mTypingTimeout, Config.TYPING_TIMEOUT * 1000); | ||||
|         if (!isUserTyping && length > 0) { | ||||
|             this.isUserTyping = true; | ||||
|             this.keyboardListener.onTypingStarted(); | ||||
|         } else if (length == 0) { | ||||
|             this.isUserTyping = false; | ||||
|             this.keyboardListener.onTextDeleted(); | ||||
|         } | ||||
|         this.keyboardListener.onTextChanged(); | ||||
|     } | ||||
| 
 | ||||
| 	public void setRichContentListener(String[] mimeTypes, OnCommitContentListener listener) { | ||||
| 		this.mimeTypes = mimeTypes; | ||||
| 		this.mCommitContentListener = listener; | ||||
| 	} | ||||
|     public void setKeyboardListener(KeyboardListener listener) { | ||||
|         this.keyboardListener = listener; | ||||
|         if (listener != null) { | ||||
|             this.isUserTyping = false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	public void insertAsQuote(String text) { | ||||
| 		text = text.replaceAll("(\n *){2,}", "\n").replaceAll("(^|\n)", "$1> ").replaceAll("\n$", ""); | ||||
| 		Editable editable = getEditableText(); | ||||
| 		int position = getSelectionEnd(); | ||||
| 		if (position == -1) position = editable.length(); | ||||
| 		if (position > 0 && editable.charAt(position - 1) != '\n') { | ||||
| 			editable.insert(position++, "\n"); | ||||
| 		} | ||||
| 		editable.insert(position, text); | ||||
| 		position += text.length(); | ||||
| 		editable.insert(position++, "\n"); | ||||
| 		if (position < editable.length() && editable.charAt(position) != '\n') { | ||||
| 			editable.insert(position, "\n"); | ||||
| 		} | ||||
| 		setSelection(position); | ||||
| 	} | ||||
|     @Override | ||||
|     public boolean onTextContextMenuItem(int id) { | ||||
|         if (id == android.R.id.paste) { | ||||
|             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
|                 return super.onTextContextMenuItem(android.R.id.pasteAsPlainText); | ||||
|             } else { | ||||
|                 Editable editable = getEditableText(); | ||||
|                 InputFilter[] filters = editable.getFilters(); | ||||
|                 InputFilter[] tempFilters = new InputFilter[filters != null ? filters.length + 1 : 1]; | ||||
|                 if (filters != null) { | ||||
|                     System.arraycopy(filters, 0, tempFilters, 1, filters.length); | ||||
|                 } | ||||
|                 tempFilters[0] = SPAN_FILTER; | ||||
|                 editable.setFilters(tempFilters); | ||||
|                 try { | ||||
|                     return super.onTextContextMenuItem(id); | ||||
|                 } finally { | ||||
|                     editable.setFilters(filters); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             return super.onTextContextMenuItem(id); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public InputConnection onCreateInputConnection(EditorInfo editorInfo) { | ||||
| 		final InputConnection ic = super.onCreateInputConnection(editorInfo); | ||||
|     public void setRichContentListener(String[] mimeTypes, OnCommitContentListener listener) { | ||||
|         this.mimeTypes = mimeTypes; | ||||
|         this.mCommitContentListener = listener; | ||||
|     } | ||||
| 
 | ||||
| 		if (mimeTypes != null && mCommitContentListener != null && ic != null) { | ||||
| 			EditorInfoCompat.setContentMimeTypes(editorInfo, mimeTypes); | ||||
| 			return InputConnectionCompat.createWrapper(ic, editorInfo, (inputContentInfo, flags, opts) -> EditMessage.this.mCommitContentListener.onCommitContent(inputContentInfo, flags, opts, mimeTypes)); | ||||
| 		} else { | ||||
| 			return ic; | ||||
| 		} | ||||
| 	} | ||||
|     public void insertAsQuote(String text) { | ||||
|         text = text.replaceAll("(\n *){2,}", "\n").replaceAll("(^|\n)", "$1> ").replaceAll("\n$", ""); | ||||
|         Editable editable = getEditableText(); | ||||
|         int position = getSelectionEnd(); | ||||
|         if (position == -1) position = editable.length(); | ||||
|         if (position > 0 && editable.charAt(position - 1) != '\n') { | ||||
|             editable.insert(position++, "\n"); | ||||
|         } | ||||
|         editable.insert(position, text); | ||||
|         position += text.length(); | ||||
|         editable.insert(position++, "\n"); | ||||
|         if (position < editable.length() && editable.charAt(position) != '\n') { | ||||
|             editable.insert(position, "\n"); | ||||
|         } | ||||
|         setSelection(position); | ||||
|     } | ||||
| 
 | ||||
| 	public void refreshIme() { | ||||
| 		SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(getContext()); | ||||
| 		final boolean usingEnterKey = p.getBoolean("display_enter_key", getResources().getBoolean(R.bool.display_enter_key)); | ||||
| 		final boolean enterIsSend = p.getBoolean("enter_is_send", getResources().getBoolean(R.bool.enter_is_send)); | ||||
|     @Override | ||||
|     public InputConnection onCreateInputConnection(EditorInfo editorInfo) { | ||||
|         final InputConnection ic = super.onCreateInputConnection(editorInfo); | ||||
| 
 | ||||
| 		if (usingEnterKey && enterIsSend) { | ||||
| 			setInputType(getInputType() & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE)); | ||||
| 			setInputType(getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)); | ||||
| 		} else if (usingEnterKey) { | ||||
| 			setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE); | ||||
| 			setInputType(getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)); | ||||
| 		} else { | ||||
| 			setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE); | ||||
| 			setInputType(getInputType() | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE); | ||||
| 		} | ||||
| 	} | ||||
|         if (mimeTypes != null && mCommitContentListener != null && ic != null) { | ||||
|             EditorInfoCompat.setContentMimeTypes(editorInfo, mimeTypes); | ||||
|             return InputConnectionCompat.createWrapper(ic, editorInfo, (inputContentInfo, flags, opts) -> EditMessage.this.mCommitContentListener.onCommitContent(inputContentInfo, flags, opts, mimeTypes)); | ||||
|         } else { | ||||
|             return ic; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	public interface OnCommitContentListener { | ||||
| 		boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts, String[] mimeTypes); | ||||
| 	} | ||||
|     public void refreshIme() { | ||||
|         SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(getContext()); | ||||
|         final boolean usingEnterKey = p.getBoolean("display_enter_key", getResources().getBoolean(R.bool.display_enter_key)); | ||||
|         final boolean enterIsSend = p.getBoolean("enter_is_send", getResources().getBoolean(R.bool.enter_is_send)); | ||||
| 
 | ||||
| 	public interface KeyboardListener { | ||||
| 		boolean onEnterPressed(); | ||||
|         if (usingEnterKey && enterIsSend) { | ||||
|             setInputType(getInputType() & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE)); | ||||
|             setInputType(getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)); | ||||
|         } else if (usingEnterKey) { | ||||
|             setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE); | ||||
|             setInputType(getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)); | ||||
|         } else { | ||||
|             setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE); | ||||
|             setInputType(getInputType() | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 		void onTypingStarted(); | ||||
|     public interface OnCommitContentListener { | ||||
|         boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts, String[] mimeTypes); | ||||
|     } | ||||
| 
 | ||||
| 		void onTypingStopped(); | ||||
|     public interface KeyboardListener { | ||||
|         boolean onEnterPressed(); | ||||
| 
 | ||||
| 		void onTextDeleted(); | ||||
|         void onTypingStarted(); | ||||
| 
 | ||||
| 		void onTextChanged(); | ||||
|         void onTypingStopped(); | ||||
| 
 | ||||
| 		boolean onTabPressed(boolean repeated); | ||||
| 	} | ||||
|         void onTextDeleted(); | ||||
| 
 | ||||
|         void onTextChanged(); | ||||
| 
 | ||||
|         boolean onTabPressed(boolean repeated); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Daniel Gultsch
						Daniel Gultsch