mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-06 21:34:00 -05:00
app: reduce JNI overhead when adjusting a selection by creating a special setSelection() fn so we dont have to pass the entire state over the bridge.
This commit is contained in:
@@ -45,7 +45,6 @@ import androidx.core.view.WindowInsetsCompat;
|
||||
import textinput.GameTextInput.Pair;
|
||||
|
||||
public class InputConnection extends BaseInputConnection implements View.OnKeyListener {
|
||||
private static final String TAG = "gti.InputConnection";
|
||||
private final InputMethodManager imm;
|
||||
private final View targetView;
|
||||
private final Settings settings;
|
||||
@@ -53,6 +52,10 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
private Listener listener;
|
||||
private boolean mSoftKeyboardActive;
|
||||
|
||||
private void log(String text) {
|
||||
//Log.d("darkfi", text);
|
||||
}
|
||||
|
||||
/*
|
||||
* This class filters EOL characters from the input. For details of how InputFilter.filter
|
||||
* function works, refer to its documentation. If the suggested change is accepted without
|
||||
@@ -100,7 +103,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
*/
|
||||
public InputConnection(Context ctx, View targetView, Settings settings) {
|
||||
super(targetView, settings.mEditorInfo.inputType != 0);
|
||||
Log.d(TAG, "InputConnection created");
|
||||
log("InputConnection created");
|
||||
|
||||
this.targetView = targetView;
|
||||
this.settings = settings;
|
||||
@@ -143,7 +146,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
* https://developer.android.com/reference/android/view/inputmethod/InputMethodManager#showSoftInput(android.view.View,%20int)
|
||||
*/
|
||||
public final void setSoftKeyboardActive(boolean active, int flags) {
|
||||
Log.d(TAG, "setSoftKeyboardActive, active: " + active);
|
||||
log("setSoftKeyboardActive, active: " + active);
|
||||
|
||||
this.mSoftKeyboardActive = active;
|
||||
if (active) {
|
||||
@@ -171,7 +174,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
* @param editorInfo The EditorInfo to use
|
||||
*/
|
||||
public final void setEditorInfo(EditorInfo editorInfo) {
|
||||
Log.d(TAG, "setEditorInfo");
|
||||
log("setEditorInfo");
|
||||
settings.mEditorInfo = editorInfo;
|
||||
|
||||
// Depending on the multiline state, we might need a different set of filters.
|
||||
@@ -195,7 +198,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
public final void setState(State state) {
|
||||
if (state == null)
|
||||
return;
|
||||
Log.d(TAG,
|
||||
log(
|
||||
"setState: '" + state.text + "', selection=(" + state.selectionStart + ","
|
||||
+ state.selectionEnd + "), composing region=(" + state.composingRegionStart + ","
|
||||
+ state.composingRegionEnd + ")");
|
||||
@@ -232,7 +235,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
// From View.OnKeyListener
|
||||
@Override
|
||||
public boolean onKey(View view, int i, KeyEvent keyEvent) {
|
||||
Log.d(TAG, "onKey: " + keyEvent);
|
||||
log("onKey: " + keyEvent);
|
||||
if (!getSoftKeyboardActive()) {
|
||||
return false;
|
||||
}
|
||||
@@ -251,22 +254,22 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public Editable getEditable() {
|
||||
Log.d(TAG, "getEditable");
|
||||
log("getEditable");
|
||||
return mEditable;
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean setSelection(int start, int end) {
|
||||
Log.d(TAG, "setSelection: " + start + ":" + end);
|
||||
log("setSelection: " + start + ":" + end);
|
||||
return super.setSelection(start, end);
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
Log.d(
|
||||
TAG, String.format("setComposingText='%s' newCursorPosition=%d", text, newCursorPosition));
|
||||
log(
|
||||
"setComposingText='" + text + "' newCursorPosition=" + newCursorPosition);
|
||||
if (text == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -275,40 +278,40 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
|
||||
@Override
|
||||
public boolean setComposingRegion(int start, int end) {
|
||||
Log.d(TAG, "setComposingRegion: " + start + ":" + end);
|
||||
log("setComposingRegion: " + start + ":" + end);
|
||||
return super.setComposingRegion(start, end);
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean finishComposingText() {
|
||||
Log.d(TAG, "finishComposingText");
|
||||
log("finishComposingText");
|
||||
return super.finishComposingText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean endBatchEdit() {
|
||||
Log.d(TAG, "endBatchEdit");
|
||||
log("endBatchEdit");
|
||||
stateUpdated();
|
||||
return super.endBatchEdit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitCompletion(CompletionInfo text) {
|
||||
Log.d(TAG, "commitCompletion");
|
||||
log("commitCompletion");
|
||||
return super.commitCompletion(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitCorrection(CorrectionInfo text) {
|
||||
Log.d(TAG, "commitCompletion");
|
||||
log("commitCompletion");
|
||||
return super.commitCorrection(text);
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
Log.d(TAG,
|
||||
log(
|
||||
(new StringBuilder())
|
||||
.append("commitText: ")
|
||||
.append(text)
|
||||
@@ -321,21 +324,21 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
Log.d(TAG, "deleteSurroundingText: " + beforeLength + ":" + afterLength);
|
||||
log("deleteSurroundingText: " + beforeLength + ":" + afterLength);
|
||||
return super.deleteSurroundingText(beforeLength, afterLength);
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
|
||||
Log.d(TAG, "deleteSurroundingTextInCodePoints: " + beforeLength + ":" + afterLength);
|
||||
log("deleteSurroundingTextInCodePoints: " + beforeLength + ":" + afterLength);
|
||||
return super.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean sendKeyEvent(KeyEvent event) {
|
||||
Log.d(TAG, "sendKeyEvent: " + event);
|
||||
log("sendKeyEvent: " + event);
|
||||
return super.sendKeyEvent(event);
|
||||
}
|
||||
|
||||
@@ -346,16 +349,16 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
if (result == null) {
|
||||
result = "";
|
||||
}
|
||||
Log.d(TAG, "getSelectedText: " + flags + ", result: " + result);
|
||||
log("getSelectedText: " + flags + ", result: " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public CharSequence getTextAfterCursor(int length, int flags) {
|
||||
Log.d(TAG, "getTextAfterCursor: " + length + ":" + flags);
|
||||
log("getTextAfterCursor: " + length + ":" + flags);
|
||||
if (length < 0) {
|
||||
Log.i(TAG, "getTextAfterCursor: returning null to due to an invalid length=" + length);
|
||||
Log.i("darkfi", "getTextAfterCursor: returning null to due to an invalid length=" + length);
|
||||
return null;
|
||||
}
|
||||
return super.getTextAfterCursor(length, flags);
|
||||
@@ -364,9 +367,9 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public CharSequence getTextBeforeCursor(int length, int flags) {
|
||||
Log.d(TAG, "getTextBeforeCursor: " + length + ", flags=" + flags);
|
||||
log("getTextBeforeCursor: " + length + ", flags=" + flags);
|
||||
if (length < 0) {
|
||||
Log.i(TAG, "getTextBeforeCursor: returning null to due to an invalid length=" + length);
|
||||
Log.i("darkfi", "getTextBeforeCursor: returning null to due to an invalid length=" + length);
|
||||
return null;
|
||||
}
|
||||
return super.getTextBeforeCursor(length, flags);
|
||||
@@ -375,39 +378,39 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public boolean requestCursorUpdates(int cursorUpdateMode) {
|
||||
Log.d(TAG, "Request cursor updates: " + cursorUpdateMode);
|
||||
log("Request cursor updates: " + cursorUpdateMode);
|
||||
return super.requestCursorUpdates(cursorUpdateMode);
|
||||
}
|
||||
|
||||
// From BaseInputConnection
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
Log.d(TAG, "closeConnection");
|
||||
log("closeConnection");
|
||||
super.closeConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setImeConsumesInput(boolean imeConsumesInput) {
|
||||
Log.d(TAG, "setImeConsumesInput: " + imeConsumesInput);
|
||||
log("setImeConsumesInput: " + imeConsumesInput);
|
||||
return super.setImeConsumesInput(imeConsumesInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
|
||||
Log.d(TAG, "getExtractedText");
|
||||
log("getExtractedText");
|
||||
return super.getExtractedText(request, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performPrivateCommand(String action, Bundle data) {
|
||||
Log.d(TAG, "performPrivateCommand");
|
||||
log("performPrivateCommand");
|
||||
return super.performPrivateCommand(action, data);
|
||||
}
|
||||
|
||||
private void immUpdateSelection() {
|
||||
Pair selection = this.getSelection();
|
||||
Pair cr = this.getComposingRegion();
|
||||
Log.d(TAG,
|
||||
log(
|
||||
"immUpdateSelection: " + selection.first + "," + selection.second + ". " + cr.first + ","
|
||||
+ cr.second);
|
||||
settings.mEditorInfo.initialSelStart = selection.first;
|
||||
@@ -428,8 +431,8 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
return false;
|
||||
}
|
||||
int keyCode = event.getKeyCode();
|
||||
Log.d(
|
||||
TAG, String.format("processKeyEvent(key=%d) text=%s", keyCode, this.mEditable.toString()));
|
||||
log(
|
||||
"processKeyEvent(key=" + keyCode + ") text=" + this.mEditable.toString());
|
||||
// Filter out Enter keys if multi-line mode is disabled.
|
||||
if ((settings.mEditorInfo.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0
|
||||
&& (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER)
|
||||
@@ -503,7 +506,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
}
|
||||
|
||||
if (selection.first != selection.second) {
|
||||
Log.d(TAG, String.format("processKeyEvent: deleting selection"));
|
||||
log("processKeyEvent: deleting selection");
|
||||
this.mEditable.delete(selection.first, selection.second);
|
||||
}
|
||||
|
||||
@@ -525,7 +528,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
this.setComposingRegion(composingRegion.first, composingRegion.second);
|
||||
int new_cursor = selection.first + charsToInsert.length();
|
||||
setSelection(new_cursor, new_cursor);
|
||||
Log.d(TAG, String.format("processKeyEvent: exit, text=%s", this.mEditable.toString()));
|
||||
log("processKeyEvent: exit, text=" + this.mEditable.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -594,7 +597,7 @@ public class InputConnection extends BaseInputConnection implements View.OnKeyLi
|
||||
*/
|
||||
@Override
|
||||
public boolean performEditorAction(int action) {
|
||||
Log.d(TAG, "performEditorAction, action=" + action);
|
||||
log("performEditorAction, action=" + action);
|
||||
if (action == IME_ACTION_UNSPECIFIED) {
|
||||
// Super emulates Enter key press/release
|
||||
return super.performEditorAction(action);
|
||||
|
||||
@@ -173,8 +173,11 @@ impl GameTextInput {
|
||||
let mut new_focus = state.lock();
|
||||
// Mark new state as active
|
||||
new_focus.is_active = true;
|
||||
let new_state = new_focus.state.clone();
|
||||
drop(new_focus);
|
||||
|
||||
// Push changes to the Java side
|
||||
self.push_update(&new_focus.state);
|
||||
self.push_update(&new_state);
|
||||
}
|
||||
|
||||
pub fn push_update(&self, state: &AndroidTextInputState) {
|
||||
@@ -192,6 +195,21 @@ impl GameTextInput {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_select(&self, start: i32, end: i32) -> Result<(), ()> {
|
||||
let Some(input_connection) = *self.input_connection.read() else {
|
||||
w!("push_update() - no input_connection set");
|
||||
return Err(())
|
||||
};
|
||||
let is_success = unsafe {
|
||||
let env = android::attach_jni_env();
|
||||
call_bool_method!(env, input_connection, "setSelection", "(II)Z", start, end)
|
||||
};
|
||||
if is_success == 0u8 {
|
||||
return Err(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_input_connection(&self, input_connection: ndk_sys::jobject) {
|
||||
unsafe {
|
||||
let env = android::attach_jni_env();
|
||||
|
||||
@@ -87,4 +87,22 @@ impl AndroidTextInput {
|
||||
gti.push_update(&state);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_select(&self, select_start: usize, select_end: usize) {
|
||||
//t!("set_select({select_start}, {select_end})");
|
||||
// Always update our own state.
|
||||
let mut ours = self.state.lock();
|
||||
let state = &mut ours.state;
|
||||
assert!(select_start <= state.text.len());
|
||||
assert!(select_end <= state.text.len());
|
||||
state.select = (select_start, select_end);
|
||||
let is_active = ours.is_active;
|
||||
drop(ours);
|
||||
|
||||
// Only update java state when this input is active
|
||||
if is_active {
|
||||
let gti = GAME_TEXT_INPUT.get().unwrap();
|
||||
gti.set_select(select_start as i32, select_end as i32).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1559,13 +1559,19 @@ pub async fn make(
|
||||
let atom = &mut render_api.make_guard(gfxtag!("edit select task"));
|
||||
if editz_select_text.is_null(0).unwrap() {
|
||||
info!(target: "app::chat", "selection changed: null");
|
||||
actions_is_visible.set(atom, false);
|
||||
pasta_is_visible2.set(atom, false);
|
||||
// Avoid triggering unecessary redraws
|
||||
if actions_is_visible.get() {
|
||||
actions_is_visible.set(atom, false);
|
||||
pasta_is_visible2.set(atom, false);
|
||||
}
|
||||
} else {
|
||||
let select_text = editz_select_text.get_str(0).unwrap();
|
||||
info!(target: "app::chat", "selection changed: {select_text}");
|
||||
actions_is_visible.set(atom, true);
|
||||
pasta_is_visible2.set(atom, false);
|
||||
// Avoid triggering unecessary redraws
|
||||
if !actions_is_visible.get() {
|
||||
actions_is_visible.set(atom, true);
|
||||
pasta_is_visible2.set(atom, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -529,15 +529,23 @@ pub async fn make(app: &App, window: SceneNodePtr, i18n_fish: &I18nBabelFish) {
|
||||
|
||||
let chatdb_path = get_chatdb_path();
|
||||
let db = sled::open(chatdb_path).expect("cannot open sleddb");
|
||||
//for channel in CHANNELS {
|
||||
chat::make(app, content.clone(), "dev", &db, i18n_fish, emoji_meshes.clone(), is_first_time)
|
||||
for channel in CHANNELS {
|
||||
chat::make(
|
||||
app,
|
||||
content.clone(),
|
||||
channel,
|
||||
&db,
|
||||
i18n_fish,
|
||||
emoji_meshes.clone(),
|
||||
is_first_time,
|
||||
)
|
||||
.await;
|
||||
//}
|
||||
//menu::make(app, content.clone(), i18n_fish).await;
|
||||
}
|
||||
menu::make(app, content.clone(), i18n_fish).await;
|
||||
|
||||
// @@@ Debug stuff @@@
|
||||
let chatview_node = app.sg_root.lookup_node("/window/content/dev_chat_layer").unwrap();
|
||||
chatview_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
|
||||
//let chatview_node = app.sg_root.lookup_node("/window/content/dev_chat_layer").unwrap();
|
||||
//chatview_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
|
||||
//let menu_node = app.sg_root.lookup_node("/window/content/menu_layer").unwrap();
|
||||
//menu_node.set_property_bool(atom, Role::App, "is_visible", false).unwrap();
|
||||
}
|
||||
|
||||
@@ -132,9 +132,10 @@ impl Editor {
|
||||
let cursor_idx = cursor.index();
|
||||
t!(" move_to_pos: {cursor_idx}");
|
||||
assert!(cursor_idx <= self.state.text.len());
|
||||
assert_eq!(self.state.text, self.text.get());
|
||||
self.state.select = (cursor_idx, cursor_idx);
|
||||
self.state.compose = None;
|
||||
self.input.set_state(self.state.clone());
|
||||
self.input.set_select(cursor_idx, cursor_idx);
|
||||
}
|
||||
|
||||
pub async fn select_word_at_point(&mut self, pos: Point) {
|
||||
@@ -216,10 +217,12 @@ impl Editor {
|
||||
parley::Selection::new(anchor, focus)
|
||||
}
|
||||
pub async fn set_selection(&mut self, select_start: usize, select_end: usize) {
|
||||
self.state.text = self.text.get();
|
||||
assert!(select_start <= self.state.text.len());
|
||||
assert!(select_end <= self.state.text.len());
|
||||
assert_eq!(self.state.text, self.text.get());
|
||||
self.state.select = (select_start, select_end);
|
||||
self.state.compose = None;
|
||||
self.input.set_state(self.state.clone());
|
||||
self.input.set_select(select_start, select_end);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
@@ -1363,16 +1363,17 @@ impl UIObject for BaseEdit {
|
||||
fn init(&self) {
|
||||
let mut guard = self.editor.lock_blocking();
|
||||
assert!(guard.is_none());
|
||||
let mut editor = Editor::new(
|
||||
let editor = Editor::new(
|
||||
self.text.clone(),
|
||||
self.font_size.clone(),
|
||||
self.text_color.clone(),
|
||||
self.window_scale.clone(),
|
||||
self.lineheight.clone(),
|
||||
);
|
||||
let atom = &mut PropertyAtomicGuard::none();
|
||||
self.text.set(atom, "the quick brown fox jumped over the");
|
||||
smol::block_on(editor.on_text_prop_changed());
|
||||
// For Android you can do this:
|
||||
//let atom = &mut PropertyAtomicGuard::none();
|
||||
//self.text.set(atom, "the quick brown fox jumped over the");
|
||||
//smol::block_on(editor.on_text_prop_changed());
|
||||
*guard = Some(editor);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user