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