Skip to content

Commit 043923e

Browse files
Added|Fixed: Do not show AutoFill UI on Termux start and add support for usernames
- The AutoFill type and hints are no longer hardcoded in `TerminalView` class and `TermuxActivity` layout xml. They are dynamically set to required values before making a manual AutoFill request and reverted back afterwards to default values. The hardcoded value `AUTOFILL_TYPE_TEXT` returned by `getAutofillType()` was causing the AutoFill UI to show on Activity starts, this will return `AUTOFILL_TYPE_NONE` by default now so that AutoFill UI isn't shown automatically. - The AutoFill importance is no longer hardcoded in `TermuxActivity` layout xml and is returned by `TerminalView` class itself by `getImportantForAutofill()`. - The AutoFill function in `TermuxActivity` for making a manual AutoFill request is moved to `TerminalView` class. This and moving of hardcoded values to `TerminalView` class mentioned above is done as complete logic of AutoFill should be handled by `TerminalView` class itself and not scattered in various places. - The Terminal context menu now supports AutoFilling a username. Note that GBoard/Google Password Manager seems to have a bug where it will still show `Pick a saved password` instead of username, even though `AUTOFILL_HINT_USERNAME` is being requested, however it will still AutoFill a username of selected entry correctly. - Pressing the back button to close the keyboard will also cancel the current manually requested AutoFill request and UI will not show when keyboard is opened again. Closes #3909
1 parent 2d38a1c commit 043923e

File tree

4 files changed

+132
-26
lines changed

4 files changed

+132
-26
lines changed

app/src/main/java/com/termux/app/TermuxActivity.java

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import android.content.pm.PackageManager;
1515
import android.graphics.Color;
1616
import android.net.Uri;
17-
import android.os.Build;
1817
import android.os.Bundle;
1918
import android.os.IBinder;
2019
import android.view.ContextMenu;
@@ -25,7 +24,6 @@
2524
import android.view.View;
2625
import android.view.ViewGroup;
2726
import android.view.WindowManager;
28-
import android.view.autofill.AutofillManager;
2927
import android.widget.EditText;
3028
import android.widget.ImageButton;
3129
import android.widget.ListView;
@@ -164,7 +162,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
164162
private static final int CONTEXT_MENU_SELECT_URL_ID = 0;
165163
private static final int CONTEXT_MENU_SHARE_TRANSCRIPT_ID = 1;
166164
private static final int CONTEXT_MENU_SHARE_SELECTED_TEXT = 10;
167-
private static final int CONTEXT_MENU_AUTOFILL_ID = 2;
165+
private static final int CONTEXT_MENU_AUTOFILL_USERNAME = 11;
166+
private static final int CONTEXT_MENU_AUTOFILL_PASSWORD = 2;
168167
private static final int CONTEXT_MENU_RESET_TERMINAL_ID = 3;
169168
private static final int CONTEXT_MENU_KILL_PROCESS_ID = 4;
170169
private static final int CONTEXT_MENU_STYLING_ID = 5;
@@ -589,20 +588,16 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn
589588
TerminalSession currentSession = getCurrentSession();
590589
if (currentSession == null) return;
591590

592-
boolean addAutoFillMenu = false;
593-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
594-
AutofillManager autofillManager = getSystemService(AutofillManager.class);
595-
if (autofillManager != null && autofillManager.isEnabled()) {
596-
addAutoFillMenu = true;
597-
}
598-
}
591+
boolean autoFillEnabled = mTerminalView.isAutoFillEnabled();
599592

600593
menu.add(Menu.NONE, CONTEXT_MENU_SELECT_URL_ID, Menu.NONE, R.string.action_select_url);
601594
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_TRANSCRIPT_ID, Menu.NONE, R.string.action_share_transcript);
602595
if (!DataUtils.isNullOrEmpty(mTerminalView.getStoredSelectedText()))
603596
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_SELECTED_TEXT, Menu.NONE, R.string.action_share_selected_text);
604-
if (addAutoFillMenu)
605-
menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password);
597+
if (autoFillEnabled)
598+
menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_USERNAME, Menu.NONE, R.string.action_autofill_username);
599+
if (autoFillEnabled)
600+
menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_PASSWORD, Menu.NONE, R.string.action_autofill_password);
606601
menu.add(Menu.NONE, CONTEXT_MENU_RESET_TERMINAL_ID, Menu.NONE, R.string.action_reset_terminal);
607602
menu.add(Menu.NONE, CONTEXT_MENU_KILL_PROCESS_ID, Menu.NONE, getResources().getString(R.string.action_kill_process, getCurrentSession().getPid())).setEnabled(currentSession.isRunning());
608603
menu.add(Menu.NONE, CONTEXT_MENU_STYLING_ID, Menu.NONE, R.string.action_style_terminal);
@@ -633,8 +628,11 @@ public boolean onContextItemSelected(MenuItem item) {
633628
case CONTEXT_MENU_SHARE_SELECTED_TEXT:
634629
mTermuxTerminalViewClient.shareSelectedText();
635630
return true;
636-
case CONTEXT_MENU_AUTOFILL_ID:
637-
requestAutoFill();
631+
case CONTEXT_MENU_AUTOFILL_USERNAME:
632+
mTerminalView.requestAutoFillUsername();
633+
return true;
634+
case CONTEXT_MENU_AUTOFILL_PASSWORD:
635+
mTerminalView.requestAutoFillPassword();
638636
return true;
639637
case CONTEXT_MENU_RESET_TERMINAL_ID:
640638
onResetTerminalSession(session);
@@ -715,15 +713,6 @@ private void toggleKeepScreenOn() {
715713
}
716714
}
717715

718-
private void requestAutoFill() {
719-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
720-
AutofillManager autofillManager = getSystemService(AutofillManager.class);
721-
if (autofillManager != null && autofillManager.isEnabled()) {
722-
autofillManager.requestAutofill(mTerminalView);
723-
}
724-
}
725-
}
726-
727716

728717

729718
/**

app/src/main/res/layout/activity_termux.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
android:focusableInTouchMode="true"
3232
android:scrollbarThumbVertical="@drawable/terminal_scroll_shape"
3333
android:scrollbars="vertical"
34-
android:importantForAutofill="no"
35-
android:autofillHints="password"
3634
tools:ignore="UnusedAttribute" />
3735

3836
<LinearLayout

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<string name="title_share_selected_text">Terminal Text</string>
7070
<string name="title_share_selected_text_with">Send selected text to:</string>
7171

72+
<string name="action_autofill_username">Autofill username</string>
7273
<string name="action_autofill_password">Autofill password</string>
7374

7475
<string name="action_reset_terminal">Reset</string>

terminal-view/src/main/java/com/termux/view/TerminalView.java

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import android.view.ViewConfiguration;
2828
import android.view.ViewTreeObserver;
2929
import android.view.accessibility.AccessibilityManager;
30+
import android.view.autofill.AutofillManager;
3031
import android.view.autofill.AutofillValue;
3132
import android.view.inputmethod.BaseInputConnection;
3233
import android.view.inputmethod.EditorInfo;
@@ -85,6 +86,29 @@ public final class TerminalView extends View {
8586
/** If non-zero, this is the last unicode code point received if that was a combining character. */
8687
int mCombiningAccent;
8788

89+
/**
90+
* The current AutoFill type returned for {@link View#getAutofillType()} by {@link #getAutofillType()}.
91+
*
92+
* The default is {@link #AUTOFILL_TYPE_NONE} so that AutoFill UI, like toolbar above keyboard
93+
* is not shown automatically, like on Activity starts/View create. This value should be updated
94+
* to required value, like {@link #AUTOFILL_TYPE_TEXT} before calling
95+
* {@link AutofillManager#requestAutofill(View)} so that AutoFill UI shows. The updated value
96+
* set will automatically be restored to {@link #AUTOFILL_TYPE_NONE} in
97+
* {@link #autofill(AutofillValue)} so that AutoFill UI isn't shown anymore by calling
98+
* {@link #resetAutoFill()}.
99+
*/
100+
@RequiresApi(api = Build.VERSION_CODES.O)
101+
private int mAutoFillType = AUTOFILL_TYPE_NONE;
102+
103+
/**
104+
* The current AutoFill hints returned for {@link View#getAutofillHints()} ()} by {@link #getAutofillHints()} ()}.
105+
*
106+
* The default is an empty `string[]`. This value should be updated to required value. The
107+
* updated value set will automatically be restored an empty `string[]` in
108+
* {@link #autofill(AutofillValue)} by calling {@link #resetAutoFill()}.
109+
*/
110+
private String[] mAutoFillHints = new String[0];
111+
88112
private final boolean mAccessibilityEnabled;
89113

90114
private static final String LOG_TAG = "TerminalView";
@@ -593,6 +617,7 @@ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
593617
if (TERMINAL_VIEW_KEY_LOGGING_ENABLED)
594618
mClient.logInfo(LOG_TAG, "onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
595619
if (keyCode == KeyEvent.KEYCODE_BACK) {
620+
cancelRequestAutoFill();
596621
if (isSelectingText()) {
597622
stopTextSelectionMode();
598623
return true;
@@ -1009,12 +1034,20 @@ public void autofill(AutofillValue value) {
10091034
if (value.isText()) {
10101035
mTermSession.write(value.getTextValue().toString());
10111036
}
1037+
1038+
resetAutoFill();
10121039
}
10131040

10141041
@RequiresApi(api = Build.VERSION_CODES.O)
10151042
@Override
10161043
public int getAutofillType() {
1017-
return AUTOFILL_TYPE_TEXT;
1044+
return mAutoFillType;
1045+
}
1046+
1047+
@RequiresApi(api = Build.VERSION_CODES.O)
1048+
@Override
1049+
public String[] getAutofillHints() {
1050+
return mAutoFillHints;
10181051
}
10191052

10201053
@RequiresApi(api = Build.VERSION_CODES.O)
@@ -1023,6 +1056,91 @@ public AutofillValue getAutofillValue() {
10231056
return AutofillValue.forText("");
10241057
}
10251058

1059+
@RequiresApi(api = Build.VERSION_CODES.O)
1060+
@Override
1061+
public int getImportantForAutofill() {
1062+
return IMPORTANT_FOR_AUTOFILL_NO;
1063+
}
1064+
1065+
@RequiresApi(api = Build.VERSION_CODES.O)
1066+
private synchronized void resetAutoFill() {
1067+
// Restore none type so that AutoFill UI isn't shown anymore.
1068+
mAutoFillType = AUTOFILL_TYPE_NONE;
1069+
mAutoFillHints = new String[0];
1070+
}
1071+
1072+
public AutofillManager getAutoFillManagerService() {
1073+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return null;
1074+
1075+
try {
1076+
Context context = getContext();
1077+
if (context == null) return null;
1078+
return context.getSystemService(AutofillManager.class);
1079+
} catch (Exception e) {
1080+
mClient.logStackTraceWithMessage(LOG_TAG, "Failed to get AutofillManager service", e);
1081+
return null;
1082+
}
1083+
}
1084+
1085+
public boolean isAutoFillEnabled() {
1086+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false;
1087+
1088+
try {
1089+
AutofillManager autofillManager = getAutoFillManagerService();
1090+
return autofillManager != null && autofillManager.isEnabled();
1091+
} catch (Exception e) {
1092+
mClient.logStackTraceWithMessage(LOG_TAG, "Failed to check if Autofill is enabled", e);
1093+
return false;
1094+
}
1095+
}
1096+
1097+
public synchronized void requestAutoFillUsername() {
1098+
requestAutoFill(
1099+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? new String[]{View.AUTOFILL_HINT_USERNAME} :
1100+
null);
1101+
}
1102+
1103+
public synchronized void requestAutoFillPassword() {
1104+
requestAutoFill(
1105+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? new String[]{View.AUTOFILL_HINT_PASSWORD} :
1106+
null);
1107+
}
1108+
1109+
public synchronized void requestAutoFill(String[] autoFillHints) {
1110+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
1111+
if (autoFillHints == null || autoFillHints.length < 1) return;
1112+
1113+
try {
1114+
AutofillManager autofillManager = getAutoFillManagerService();
1115+
if (autofillManager != null && autofillManager.isEnabled()) {
1116+
// Update type that will be returned by `getAutofillType()` so that AutoFill UI is shown.
1117+
mAutoFillType = AUTOFILL_TYPE_TEXT;
1118+
// Update hints that will be returned by `getAutofillHints()` for which to show AutoFill UI.
1119+
mAutoFillHints = autoFillHints;
1120+
autofillManager.requestAutofill(this);
1121+
}
1122+
} catch (Exception e) {
1123+
mClient.logStackTraceWithMessage(LOG_TAG, "Failed to request Autofill", e);
1124+
}
1125+
}
1126+
1127+
public synchronized void cancelRequestAutoFill() {
1128+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
1129+
if (mAutoFillType == AUTOFILL_TYPE_NONE) return;
1130+
1131+
try {
1132+
AutofillManager autofillManager = getAutoFillManagerService();
1133+
if (autofillManager != null && autofillManager.isEnabled()) {
1134+
resetAutoFill();
1135+
autofillManager.cancel();
1136+
}
1137+
} catch (Exception e) {
1138+
mClient.logStackTraceWithMessage(LOG_TAG, "Failed to cancel Autofill request", e);
1139+
}
1140+
}
1141+
1142+
1143+
10261144

10271145

10281146
/**

0 commit comments

Comments
 (0)