make list selection manager work with app compat
This commit is contained in:
		
							parent
							
								
									f9e1e856d2
								
							
						
					
					
						commit
						11736ce48c
					
				| @ -1,8 +1,5 @@ | |||||||
| package eu.siacs.conversations.ui.widget; | package eu.siacs.conversations.ui.widget; | ||||||
| 
 | 
 | ||||||
| import java.lang.reflect.Field; |  | ||||||
| import java.lang.reflect.Method; |  | ||||||
| 
 |  | ||||||
| import android.os.Handler; | import android.os.Handler; | ||||||
| import android.os.Looper; | import android.os.Looper; | ||||||
| import android.os.Message; | import android.os.Message; | ||||||
| @ -13,12 +10,17 @@ import android.view.Menu; | |||||||
| import android.view.MenuItem; | import android.view.MenuItem; | ||||||
| import android.widget.TextView; | import android.widget.TextView; | ||||||
| 
 | 
 | ||||||
|  | import java.lang.reflect.Field; | ||||||
|  | import java.lang.reflect.Method; | ||||||
|  | 
 | ||||||
| public class ListSelectionManager { | public class ListSelectionManager { | ||||||
| 
 | 
 | ||||||
|     private static final int MESSAGE_SEND_RESET = 1; |     private static final int MESSAGE_SEND_RESET = 1; | ||||||
|     private static final int MESSAGE_RESET = 2; |     private static final int MESSAGE_RESET = 2; | ||||||
|     private static final int MESSAGE_START_SELECTION = 3; |     private static final int MESSAGE_START_SELECTION = 3; | ||||||
| 
 |     private static final Field FIELD_EDITOR; | ||||||
|  |     private static final Method METHOD_START_SELECTION; | ||||||
|  |     private static final boolean SUPPORTED; | ||||||
|     private static final Handler HANDLER = new Handler(Looper.getMainLooper(), new Handler.Callback() { |     private static final Handler HANDLER = new Handler(Looper.getMainLooper(), new Handler.Callback() { | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
| @ -45,30 +47,58 @@ public class ListSelectionManager { | |||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| 	private static class StartSelectionHolder { |     static { | ||||||
| 
 |         Field editor; | ||||||
| 		public final ListSelectionManager listSelectionManager; |         try { | ||||||
| 		public final TextView textView; |             editor = TextView.class.getDeclaredField("mEditor"); | ||||||
| 		public final int start; |             editor.setAccessible(true); | ||||||
| 		public final int end; |         } catch (Exception e) { | ||||||
| 
 |             editor = null; | ||||||
| 		public StartSelectionHolder(ListSelectionManager listSelectionManager, TextView textView, |  | ||||||
| 				int start, int end) { |  | ||||||
| 			this.listSelectionManager = listSelectionManager; |  | ||||||
| 			this.textView = textView; |  | ||||||
| 			this.start = start; |  | ||||||
| 			this.end = end; |  | ||||||
|         } |         } | ||||||
|  |         FIELD_EDITOR = editor; | ||||||
|  |         Method startSelection = null; | ||||||
|  |         if (editor != null) { | ||||||
|  |             String[] startSelectionNames = {"startSelectionActionMode", "startSelectionActionModeWithSelection"}; | ||||||
|  |             for (String startSelectionName : startSelectionNames) { | ||||||
|  |                 try { | ||||||
|  |                     startSelection = editor.getType().getDeclaredMethod(startSelectionName); | ||||||
|  |                     startSelection.setAccessible(true); | ||||||
|  |                     break; | ||||||
|  |                 } catch (Exception e) { | ||||||
|  |                     startSelection = null; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         METHOD_START_SELECTION = startSelection; | ||||||
|  |         SUPPORTED = FIELD_EDITOR != null && METHOD_START_SELECTION != null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private ActionMode selectionActionMode; |     private ActionMode selectionActionMode; | ||||||
|     private Object selectionIdentifier; |     private Object selectionIdentifier; | ||||||
|     private TextView selectionTextView; |     private TextView selectionTextView; | ||||||
| 
 |  | ||||||
|     private Object futureSelectionIdentifier; |     private Object futureSelectionIdentifier; | ||||||
|     private int futureSelectionStart; |     private int futureSelectionStart; | ||||||
|     private int futureSelectionEnd; |     private int futureSelectionEnd; | ||||||
| 
 | 
 | ||||||
|  |     public static boolean isSupported() { | ||||||
|  |         return SUPPORTED; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static void startSelection(TextView textView, int start, int end) { | ||||||
|  |         final CharSequence text = textView.getText(); | ||||||
|  |         if (SUPPORTED && start >= 0 && end > start && textView.isTextSelectable() && text instanceof Spannable) { | ||||||
|  |             final Spannable spannable = (Spannable) text; | ||||||
|  |             start = Math.min(start, spannable.length()); | ||||||
|  |             end = Math.min(end, spannable.length()); | ||||||
|  |             Selection.setSelection(spannable, start, end); | ||||||
|  |             try { | ||||||
|  |                 final Object editor = FIELD_EDITOR != null ? FIELD_EDITOR.get(textView) : textView; | ||||||
|  |                 METHOD_START_SELECTION.invoke(editor); | ||||||
|  |             } catch (Exception e) { | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public void onCreate(TextView textView, ActionMode.Callback additionalCallback) { |     public void onCreate(TextView textView, ActionMode.Callback additionalCallback) { | ||||||
|         final CustomCallback callback = new CustomCallback(textView, additionalCallback); |         final CustomCallback callback = new CustomCallback(textView, additionalCallback); | ||||||
|         textView.setCustomSelectionActionModeCallback(callback); |         textView.setCustomSelectionActionModeCallback(callback); | ||||||
| @ -76,14 +106,17 @@ public class ListSelectionManager { | |||||||
| 
 | 
 | ||||||
|     public void onUpdate(TextView textView, Object identifier) { |     public void onUpdate(TextView textView, Object identifier) { | ||||||
|         if (SUPPORTED) { |         if (SUPPORTED) { | ||||||
| 			CustomCallback callback = (CustomCallback) textView.getCustomSelectionActionModeCallback(); |             final ActionMode.Callback callback = textView.getCustomSelectionActionModeCallback(); | ||||||
| 			callback.identifier = identifier; |             if (callback instanceof CustomCallback) { | ||||||
|  |                 final CustomCallback customCallback = (CustomCallback) textView.getCustomSelectionActionModeCallback(); | ||||||
|  |                 customCallback.identifier = identifier; | ||||||
|                 if (futureSelectionIdentifier == identifier) { |                 if (futureSelectionIdentifier == identifier) { | ||||||
|                     HANDLER.obtainMessage(MESSAGE_START_SELECTION, new StartSelectionHolder(this, |                     HANDLER.obtainMessage(MESSAGE_START_SELECTION, new StartSelectionHolder(this, | ||||||
|                             textView, futureSelectionStart, futureSelectionEnd)).sendToTarget(); |                             textView, futureSelectionStart, futureSelectionEnd)).sendToTarget(); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     public void onBeforeNotifyDataSetChanged() { |     public void onBeforeNotifyDataSetChanged() { | ||||||
|         if (SUPPORTED) { |         if (SUPPORTED) { | ||||||
| @ -109,13 +142,29 @@ public class ListSelectionManager { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private static class StartSelectionHolder { | ||||||
|  | 
 | ||||||
|  |         final ListSelectionManager listSelectionManager; | ||||||
|  |         final TextView textView; | ||||||
|  |         public final int start; | ||||||
|  |         public final int end; | ||||||
|  | 
 | ||||||
|  |         StartSelectionHolder(ListSelectionManager listSelectionManager, TextView textView, | ||||||
|  |                                     int start, int end) { | ||||||
|  |             this.listSelectionManager = listSelectionManager; | ||||||
|  |             this.textView = textView; | ||||||
|  |             this.start = start; | ||||||
|  |             this.end = end; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private class CustomCallback implements ActionMode.Callback { |     private class CustomCallback implements ActionMode.Callback { | ||||||
| 
 | 
 | ||||||
|         private final TextView textView; |         private final TextView textView; | ||||||
|         private final ActionMode.Callback additionalCallback; |         private final ActionMode.Callback additionalCallback; | ||||||
| 		public Object identifier; |         Object identifier; | ||||||
| 
 | 
 | ||||||
| 		public CustomCallback(TextView textView, ActionMode.Callback additionalCallback) { |         CustomCallback(TextView textView, ActionMode.Callback additionalCallback) { | ||||||
|             this.textView = textView; |             this.textView = textView; | ||||||
|             this.additionalCallback = additionalCallback; |             this.additionalCallback = additionalCallback; | ||||||
|         } |         } | ||||||
| @ -159,53 +208,4 @@ public class ListSelectionManager { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| 	private static final Field FIELD_EDITOR; |  | ||||||
| 	private static final Method METHOD_START_SELECTION; |  | ||||||
| 	private static final boolean SUPPORTED; |  | ||||||
| 
 |  | ||||||
| 	static { |  | ||||||
| 		Field editor; |  | ||||||
| 		try { |  | ||||||
| 			editor = TextView.class.getDeclaredField("mEditor"); |  | ||||||
| 			editor.setAccessible(true); |  | ||||||
| 		} catch (Exception e) { |  | ||||||
| 			editor = null; |  | ||||||
| 		} |  | ||||||
| 		FIELD_EDITOR = editor; |  | ||||||
| 		Method startSelection = null; |  | ||||||
| 		if (editor != null) { |  | ||||||
| 			String[] startSelectionNames = {"startSelectionActionMode", "startSelectionActionModeWithSelection"}; |  | ||||||
| 			for (String startSelectionName : startSelectionNames) { |  | ||||||
| 				try { |  | ||||||
| 					startSelection = editor.getType().getDeclaredMethod(startSelectionName); |  | ||||||
| 					startSelection.setAccessible(true); |  | ||||||
| 					break; |  | ||||||
| 				} catch (Exception e) { |  | ||||||
| 					startSelection = null; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		METHOD_START_SELECTION = startSelection; |  | ||||||
| 		SUPPORTED = FIELD_EDITOR != null && METHOD_START_SELECTION != null; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public static boolean isSupported() { |  | ||||||
| 		return SUPPORTED; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public static void startSelection(TextView textView, int start, int end) { |  | ||||||
| 		final CharSequence text = textView.getText(); |  | ||||||
| 		if (SUPPORTED && start >= 0 && end > start && textView.isTextSelectable() && text instanceof Spannable) { |  | ||||||
| 			final Spannable spannable = (Spannable) text; |  | ||||||
| 			start = Math.min(start, spannable.length()); |  | ||||||
| 			end = Math.min(end, spannable.length()); |  | ||||||
| 			Selection.setSelection(spannable, start, end); |  | ||||||
| 			try { |  | ||||||
| 				final Object editor = FIELD_EDITOR != null ? FIELD_EDITOR.get(textView) : textView; |  | ||||||
| 				METHOD_START_SELECTION.invoke(editor); |  | ||||||
| 			} catch (Exception e) { |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Daniel Gultsch
						Daniel Gultsch