Skip to content

Commit 4d4c22b

Browse files
authored
Merge pull request #1150 from Julow/candidates_view
Candidates view
2 parents dfaf4db + bdb05bc commit 4d4c22b

12 files changed

Lines changed: 391 additions & 17 deletions

res/layout/keyboard.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<juloo.keyboard2.Keyboard2View xmlns:android="http://schemas.android.com/apk/res/android" android:hardwareAccelerated="false" android:background="?attr/colorKeyboard"/>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:hardwareAccelerated="false" android:orientation="vertical" android:background="?attr/colorKeyboard">
3+
<juloo.keyboard2.CandidatesView android:id="@+id/candidates_view" android:layout_width="match_parent" android:layout_height="48dp" android:orientation="horizontal">
4+
<TextView android:id="@+id/candidates_left" style="@style/candidates_item" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/>
5+
<TextView android:id="@+id/candidates_middle" style="@style/candidates_item" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/>
6+
<TextView android:id="@+id/candidates_right" style="@style/candidates_item" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/>
7+
</juloo.keyboard2.CandidatesView>
8+
<juloo.keyboard2.Keyboard2View android:id="@+id/keyboard_view" android:layout_width="match_parent" android:layout_height="wrap_content"/>
9+
</LinearLayout>

res/values/styles.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3+
<!-- Candidates view -->
4+
<style name="candidates_item">
5+
<item name="android:gravity">center</item>
6+
<item name="android:textSize">18sp</item>
7+
<item name="android:textColor">?attr/colorLabel</item>
8+
</style>
39
<!-- Emoji pane -->
410
<style name="emojiTypeButton">
511
<item name="android:padding">1px</item>

res/values/values.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<dimen name="emoji_text_size">28dp</dimen>
77
<dimen name="clipboard_view_height">300dp</dimen>
88
<dimen name="pref_button_size">28dp</dimen>
9+
<dimen name="candidates_spacing">8dp</dimen>
910
<!-- Will be overwritten automatically by Gradle for the debug build variant -->
1011
<bool name="debug_logs">false</bool>
1112
</resources>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package juloo.keyboard2;
2+
3+
import android.content.Context;
4+
import android.text.InputType;
5+
import android.util.AttributeSet;
6+
import android.view.View;
7+
import android.view.inputmethod.EditorInfo;
8+
import android.widget.LinearLayout;
9+
import android.widget.TextView;
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
13+
public class CandidatesView extends LinearLayout
14+
{
15+
static final int NUM_CANDIDATES = 3;
16+
17+
Config _config;
18+
19+
/** Candidates currently visible. Entries can be [null] when there are less
20+
than [NUM_CANDIDATES] suggestions. */
21+
String[] _items = new String[NUM_CANDIDATES];
22+
23+
/** Text views showing the candidates in [_items]. Text views visibility is
24+
set to [GONE] when there are less than [NUM_CANDIDATES] suggestions. */
25+
TextView[] _item_views = new TextView[NUM_CANDIDATES];
26+
27+
public CandidatesView(Context context, AttributeSet attrs)
28+
{
29+
super(context, attrs);
30+
_config = Config.globalConfig();
31+
}
32+
33+
@Override
34+
protected void onFinishInflate()
35+
{
36+
super.onFinishInflate();
37+
setup_item_view(0, R.id.candidates_middle);
38+
setup_item_view(1, R.id.candidates_right);
39+
setup_item_view(2, R.id.candidates_left);
40+
}
41+
42+
public void set_candidates(List<String> suggestions)
43+
{
44+
int s_count = suggestions.size();
45+
for (int i = 0; i < _item_views.length; i++)
46+
{
47+
TextView v = _item_views[i];
48+
if (i < s_count)
49+
{
50+
String it = suggestions.get(i);
51+
_items[i] = it;
52+
v.setText(it);
53+
v.setVisibility(View.VISIBLE);
54+
}
55+
else
56+
{
57+
_items[i] = null;
58+
v.setVisibility(View.GONE);
59+
}
60+
}
61+
}
62+
63+
private void setup_item_view(final int item_index, int item_id)
64+
{
65+
TextView v = (TextView)findViewById(item_id);
66+
v.setOnClickListener(new View.OnClickListener()
67+
{
68+
@Override
69+
public void onClick(View _v)
70+
{
71+
String it = _items[item_index];
72+
if (it != null)
73+
_config.handler.suggestion_entered(it);
74+
}
75+
});
76+
v.setVisibility(View.GONE);
77+
_item_views[item_index] = v;
78+
}
79+
80+
public static boolean should_show(EditorInfo info)
81+
{
82+
int variation = info.inputType & InputType.TYPE_MASK_VARIATION;
83+
int flags = info.inputType & InputType.TYPE_MASK_FLAGS;
84+
switch (info.inputType & InputType.TYPE_MASK_CLASS)
85+
{
86+
case InputType.TYPE_CLASS_TEXT:
87+
switch (variation)
88+
{
89+
case InputType.TYPE_TEXT_VARIATION_PASSWORD:
90+
case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD:
91+
case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD:
92+
return false;
93+
default:
94+
if ((flags & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0)
95+
return false; // Editor requested that we don't show suggestions
96+
return true;
97+
}
98+
case InputType.TYPE_CLASS_NUMBER:
99+
// Beware of TYPE_NUMBER_VARIATION_PASSWORD
100+
return false;
101+
default: return false;
102+
}
103+
}
104+
}

srcs/juloo.keyboard2/Config.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public final class Config
7575
// Dynamically set
7676
/** Configuration options implied by the connected editor. */
7777
public EditorConfig editor_config;
78+
public boolean should_show_candidates_view;
7879
public boolean shouldOfferVoiceTyping;
7980
public ExtraKeys extra_keys_subtype;
8081
public Map<KeyValue, KeyboardData.PreferredPos> extra_keys_param;
@@ -101,6 +102,7 @@ private Config(SharedPreferences prefs, Resources res, IKeyEventHandler h, Boole
101102
// from prefs
102103
refresh(res, foldableUnfolded);
103104
// initialized later
105+
should_show_candidates_view = false;
104106
shouldOfferVoiceTyping = false;
105107
extra_keys_subtype = null;
106108
handler = h;
@@ -291,6 +293,7 @@ public static interface IKeyEventHandler
291293
public void key_down(KeyValue value, boolean is_swipe);
292294
public void key_up(KeyValue value, Pointers.Modifiers mods);
293295
public void mods_changed(Pointers.Modifiers mods);
296+
public void suggestion_entered(String text);
294297
}
295298

296299
/** Config migrations. */
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package juloo.keyboard2;
2+
3+
import android.os.Handler;
4+
import android.view.KeyEvent;
5+
import android.view.inputmethod.EditorInfo;
6+
import android.view.inputmethod.InputConnection;
7+
import java.util.List;
8+
9+
/** Keep track of the word being typed. */
10+
public final class CurrentlyTypedWord
11+
{
12+
InputConnection _ic = null;
13+
Handler _handler;
14+
Callback _callback;
15+
16+
/** The currently typed word. */
17+
StringBuilder _w = new StringBuilder();
18+
/** This can be disabled if the editor doesn't support looking at the text
19+
before the cursor. */
20+
boolean _enabled = false;
21+
/** The current word is empty while the selection is ongoing. */
22+
boolean _has_selection = false;
23+
/** Used to avoid concurrent refreshes in [delayed_refresh()]. */
24+
boolean _refresh_pending = false;
25+
26+
/** The estimated cursor position. Used to avoid expensive IPC calls when the
27+
typed word can be estimated locally with [typed]. When the cursor
28+
position gets out of sync, the text before the cursor is queried again to
29+
the editor. */
30+
int _cursor;
31+
32+
public CurrentlyTypedWord(Handler h, Callback cb)
33+
{
34+
_handler = h;
35+
_callback = cb;
36+
}
37+
38+
public String get()
39+
{
40+
return _w.toString();
41+
}
42+
43+
public void started(Config conf, InputConnection ic)
44+
{
45+
_ic = ic;
46+
_enabled = true;
47+
EditorConfig e = conf.editor_config;
48+
_has_selection = e.initial_sel_start != e.initial_sel_end;
49+
_cursor = e.initial_sel_start;
50+
if (!_has_selection)
51+
set_current_word(e.initial_text_before_cursor);
52+
}
53+
54+
public void typed(String s)
55+
{
56+
if (!_enabled)
57+
return;
58+
_has_selection = false;
59+
type_chars(s);
60+
callback();
61+
}
62+
63+
public void selection_updated(int oldSelStart, int newSelStart, int newSelEnd)
64+
{
65+
// Avoid the expensive [refresh_current_word] call when [typed] was called
66+
// before.
67+
boolean new_has_sel = newSelStart != newSelEnd;
68+
if (!_enabled || (newSelStart == _cursor && new_has_sel == _has_selection))
69+
return;
70+
_has_selection = new_has_sel;
71+
_cursor = newSelStart;
72+
refresh_current_word();
73+
}
74+
75+
public void event_sent(int code, int meta)
76+
{
77+
if (!_enabled)
78+
return;
79+
delayed_refresh();
80+
}
81+
82+
void callback()
83+
{
84+
_callback.currently_typed_word(_w.toString());
85+
}
86+
87+
/** Estimate the currently typed word after [chars] has been typed. */
88+
void type_chars(String s)
89+
{
90+
int len = s.length();
91+
for (int i = 0; i < len;)
92+
{
93+
int c = s.codePointAt(i);
94+
if (Character.isLetter(c))
95+
_w.appendCodePoint(c);
96+
else
97+
_w.setLength(0);
98+
_cursor++;
99+
i += Character.charCount(c);
100+
}
101+
}
102+
103+
/** Refresh the current word by immediately querying the editor. */
104+
void refresh_current_word()
105+
{
106+
_refresh_pending = false;
107+
if (_has_selection)
108+
set_current_word("");
109+
else
110+
set_current_word(_ic.getTextBeforeCursor(10, 0));
111+
}
112+
113+
/** Refresh the current word by immediately querying the editor. */
114+
void set_current_word(CharSequence text_before_cursor)
115+
{
116+
if (text_before_cursor == null)
117+
{
118+
_enabled = false;
119+
return;
120+
}
121+
_w.setLength(0);
122+
int saved_cursor = _cursor;
123+
type_chars(text_before_cursor.toString());
124+
_cursor = saved_cursor;
125+
callback();
126+
}
127+
128+
/** Wait some time to let the editor finishes reacting to changes and call
129+
[refresh_current_word]. */
130+
void delayed_refresh()
131+
{
132+
_refresh_pending = true;
133+
_handler.postDelayed(delayed_refresh_run, 50);
134+
}
135+
136+
Runnable delayed_refresh_run = new Runnable()
137+
{
138+
public void run()
139+
{
140+
if (_refresh_pending)
141+
refresh_current_word();
142+
}
143+
};
144+
145+
public static interface Callback
146+
{
147+
public void currently_typed_word(String word);
148+
}
149+
}

srcs/juloo.keyboard2/EditorConfig.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public final class EditorConfig
2626
// Whether caps state should be updated right away.
2727
public boolean caps_initially_updated = false;
2828

29+
/** CurrentlyTypedWord. */
30+
public CharSequence initial_text_before_cursor = null;
31+
public int initial_sel_start;
32+
public int initial_sel_end;
33+
2934
public EditorConfig() {}
3035

3136
public void refresh(EditorInfo info, Resources res)
@@ -66,6 +71,10 @@ public void refresh(EditorInfo info, Resources res)
6671
caps_mode = info.inputType & TextUtils.CAP_MODE_SENTENCES;
6772
caps_initially_enabled = (info.initialCapsMode != 0);
6873
caps_initially_updated = caps_should_update_state(info);
74+
/* CurrentlyTypedWord */
75+
initial_text_before_cursor = info.getInitialTextBeforeCursor(10, 0);
76+
initial_sel_start = info.initialSelStart;
77+
initial_sel_end = info.initialSelEnd;
6978
}
7079

7180
String actionLabel_of_imeAction(int action, Resources res)

0 commit comments

Comments
 (0)