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