diff options
Diffstat (limited to 'app/src/main')
6 files changed, 222 insertions, 185 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java index 1c4c2076..dfe4f3c0 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java @@ -16,6 +16,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.RadioButton; @@ -27,7 +28,8 @@ import com.zeapo.pwdstore.R; public class AutofillFragment extends DialogFragment { private static final int MATCH_WITH = 777; - ArrayAdapter<String> adapter; + private ArrayAdapter<String> adapter; + private boolean isWeb; public AutofillFragment() { } @@ -37,28 +39,27 @@ public class AutofillFragment extends DialogFragment { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // this fragment is only created from the settings page (AutofillPreferenceActivity) // need to interact with the recyclerAdapter which is a member of activity - final AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity(); + AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity(); LayoutInflater inflater = callingActivity.getLayoutInflater(); final View view = inflater.inflate(R.layout.fragment_autofill, null); builder.setView(view); - String packageName = getArguments().getString("packageName", ""); - String appName = getArguments().getString("appName", ""); - - final boolean isWebsite = appName.equals(packageName); + String packageName = getArguments().getString("packageName"); + String appName = getArguments().getString("appName"); + isWeb = getArguments().getBoolean("isWeb"); // set the dialog icon and title or webName editText String iconPackageName; - if (!isWebsite) { + if (!isWeb) { iconPackageName = packageName; builder.setTitle(appName); - view.findViewById(R.id.webName).setVisibility(View.GONE); + view.findViewById(R.id.webURL).setVisibility(View.GONE); } else { iconPackageName = "com.android.browser"; builder.setTitle("Website"); - ((EditText) view.findViewById(R.id.webName)).setText(packageName); + ((EditText) view.findViewById(R.id.webURL)).setText(packageName); } try { builder.setIcon(callingActivity.getPackageManager().getApplicationIcon(iconPackageName)); @@ -89,13 +90,12 @@ public class AutofillFragment extends DialogFragment { // set the existing preference, if any SharedPreferences prefs; - String preference; - if (!isWebsite) { + if (!isWeb) { prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE); } else { prefs = getActivity().getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE); } - preference = prefs.getString(packageName, ""); + String preference = prefs.getString(packageName, ""); switch (preference) { case "": ((RadioButton) view.findViewById(R.id.use_default)).toggle(); @@ -125,86 +125,106 @@ public class AutofillFragment extends DialogFragment { view.findViewById(R.id.matchButton).setOnClickListener(matchPassword); // write to preferences when OK clicked - final SharedPreferences.Editor editor = prefs.edit(); builder.setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - String key; - String packageName = getArguments().getString("packageName", ""); - - if (!isWebsite) { - key = packageName; - } else { - key = ((EditText) view.findViewById(R.id.webName)).getText().toString(); - // if key.equals("") show error - - // if new packageName/appName/website name/website title/key - // is different than old, remove the old one. Basically, - // "edit" the old one. - if (!key.equals(packageName) && !packageName.equals("")) { - editor.remove(packageName); - if (callingActivity.recyclerAdapter != null) { - if (callingActivity.recyclerAdapter.getPosition(packageName) != -1) { - callingActivity.recyclerAdapter.removeWebsite(packageName); - } - } + + } + }); + builder.setNegativeButton(R.string.dialog_cancel, null); + return builder.create(); + } + + // need to the onClick here for buttons to dismiss dialog only when wanted + @Override + public void onStart() { + super.onStart(); + AlertDialog ad = (AlertDialog) getDialog(); + if(ad != null) { + Button positiveButton = ad.getButton(Dialog.BUTTON_POSITIVE); + positiveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity(); + Dialog dialog = getDialog(); + + SharedPreferences prefs; + if (!isWeb) { + prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE); + } else { + prefs = getActivity().getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE); } - } + SharedPreferences.Editor editor = prefs.edit(); - RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.autofill_radiogroup); - switch (radioGroup.getCheckedRadioButtonId()) { - case R.id.use_default: - editor.remove(key); - break; - case R.id.first: - editor.putString(key, "/first"); - break; - case R.id.never: - editor.putString(key, "/never"); - break; - default: - StringBuilder paths = new StringBuilder(); - for (int i = 0; i < adapter.getCount(); i++) { - paths.append(adapter.getItem(i)); - if (i != adapter.getCount()) { - paths.append("\n"); - } + String packageName = getArguments().getString("packageName", ""); + if (isWeb) { + packageName = ((EditText) dialog.findViewById(R.id.webURL)).getText().toString(); + + // handle some errors + EditText webURL = (EditText) dialog.findViewById(R.id.webURL); + if (packageName.equals("")) { + webURL.setError("URL cannot be blank"); + return; } - editor.putString(key, paths.toString()); - } - editor.apply(); - - // if recyclerAdapter has not loaded yet, there is no need to notify - if (callingActivity.recyclerAdapter != null) { - int position; - if (!isWebsite) { - String appName = getArguments().getString("appName", ""); - position = callingActivity.recyclerAdapter.getPosition(appName); - callingActivity.recyclerAdapter.notifyItemChanged(position); - } else { - String appName = ((EditText) view.findViewById(R.id.webName)).getText().toString(); - position = callingActivity.recyclerAdapter.getPosition(appName); - switch (radioGroup.getCheckedRadioButtonId()) { - // remove if existed, else do nothing - case R.id.use_default: - if (position != -1) { - callingActivity.recyclerAdapter.removeWebsite(appName); - } - break; - // change if existed, else add - default: - if (position != -1) { - callingActivity.recyclerAdapter.notifyItemChanged(position); - } else { - callingActivity.recyclerAdapter.addWebsite(appName); + String oldPackageName = getArguments().getString("packageName", ""); + int position = callingActivity.recyclerAdapter.getPosition(packageName); + if (!oldPackageName.equals(packageName) && position != -1) { + webURL.setError("URL already exists"); + return; + } + } + RadioGroup radioGroup = (RadioGroup) dialog.findViewById(R.id.autofill_radiogroup); + switch (radioGroup.getCheckedRadioButtonId()) { + case R.id.use_default: + if (!isWeb) { + editor.remove(packageName); + } else { + editor.putString(packageName, ""); + } + break; + case R.id.first: + editor.putString(packageName, "/first"); + break; + case R.id.never: + editor.putString(packageName, "/never"); + break; + default: + StringBuilder paths = new StringBuilder(); + for (int i = 0; i < adapter.getCount(); i++) { + paths.append(adapter.getItem(i)); + if (i != adapter.getCount()) { + paths.append("\n"); } + } + editor.putString(packageName, paths.toString()); + } + editor.apply(); + + // if recyclerAdapter has not loaded yet, there is no need to notify + if (callingActivity.recyclerAdapter != null) { + int position; + if (!isWeb) { + String appName = getArguments().getString("appName", ""); + position = callingActivity.recyclerAdapter.getPosition(appName); + callingActivity.recyclerAdapter.notifyItemChanged(position); + } else { + position = callingActivity.recyclerAdapter.getPosition(packageName); + String oldPackageName = getArguments().getString("packageName", ""); + if (oldPackageName.equals(packageName)) { + callingActivity.recyclerAdapter.notifyItemChanged(position); + } else if (oldPackageName.equals("")){ + callingActivity.recyclerAdapter.addWebsite(packageName); + } else { + editor.remove(oldPackageName); + callingActivity.recyclerAdapter.updateWebsite(oldPackageName, packageName); + } } } + + dismiss(); } - } - }); - builder.setNegativeButton(R.string.dialog_cancel, null); - return builder.create(); + }); + } } @Override diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java index 7b8a3ba5..81d0ddde 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java @@ -28,7 +28,7 @@ import java.util.Map; public class AutofillPreferenceActivity extends AppCompatActivity { - private RecyclerView recyclerView; + RecyclerView recyclerView; AutofillRecyclerAdapter recyclerAdapter; // let fragment have access private RecyclerView.LayoutManager layoutManager; @@ -56,7 +56,7 @@ public class AutofillPreferenceActivity extends AppCompatActivity { if (extras != null) { recreate = true; - showDialog(extras.getString("packageName"), extras.getString("appName")); + showDialog(extras.getString("packageName"), extras.getString("appName"), extras.getBoolean("isWeb")); } setTitle("Autofill Apps"); @@ -65,7 +65,7 @@ public class AutofillPreferenceActivity extends AppCompatActivity { fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - showDialog("", ""); + showDialog("", "", true); } }); } @@ -85,16 +85,16 @@ public class AutofillPreferenceActivity extends AppCompatActivity { for (ResolveInfo app : allAppsResolveInfo) { allApps.add(new AutofillRecyclerAdapter.AppInfo(app.activityInfo.packageName - , app.loadLabel(pm).toString(), app.loadIcon(pm))); + , app.loadLabel(pm).toString(), false, app.loadIcon(pm))); } SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE); Map<String, ?> prefsMap = prefs.getAll(); for (String key : prefsMap.keySet()) { try { - allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, pm.getApplicationIcon("com.android.browser"))); + allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, pm.getApplicationIcon("com.android.browser"))); } catch (PackageManager.NameNotFoundException e) { - allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, null)); + allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, null)); } } @@ -158,11 +158,12 @@ public class AutofillPreferenceActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } - public void showDialog(String packageName, String appName) { + public void showDialog(String packageName, String appName, boolean isWeb) { DialogFragment df = new AutofillFragment(); Bundle args = new Bundle(); args.putString("packageName", packageName); args.putString("appName", appName); + args.putBoolean("isWeb", isWeb); df.setArguments(args); df.show(getFragmentManager(), "autofill_dialog"); } diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java index 2a567254..901ff903 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java @@ -24,6 +24,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecycl private ArrayList<AppInfo> allApps; // for filtering, maintain a list of all private PackageManager pm; private AutofillPreferenceActivity activity; + Drawable browserIcon = null; public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public View view; @@ -32,6 +33,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecycl public ImageView icon; public String packageName; public String appName; + public Boolean isWeb; public ViewHolder(View view) { super(view); @@ -44,7 +46,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecycl @Override public void onClick(View v) { - activity.showDialog(packageName, appName); + activity.showDialog(packageName, appName, isWeb); } } @@ -52,11 +54,13 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecycl public static class AppInfo { public String packageName; public String appName; + public boolean isWeb; public Drawable icon; - public AppInfo(String packageName, String appName, Drawable icon) { + public AppInfo(String packageName, String appName, boolean isWeb, Drawable icon) { this.packageName = packageName; this.appName = appName; + this.isWeb = isWeb; this.icon = icon; } @@ -91,6 +95,11 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecycl this.allApps = new ArrayList<>(allApps); this.pm = pm; this.activity = activity; + try { + browserIcon = activity.getPackageManager().getApplicationIcon("com.android.browser"); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } } @Override @@ -105,6 +114,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecycl AppInfo app = apps.get(position); holder.packageName = app.packageName; holder.appName = app.appName; + holder.isWeb = app.isWeb; holder.icon.setImageDrawable(app.icon); holder.name.setText(app.appName); @@ -147,23 +157,24 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecycl } public int getPosition(String appName) { - return apps.indexOf(new AppInfo(null, appName, null)); + return apps.indexOf(new AppInfo(null, appName, false, null)); } - public void addWebsite(String appName) { - Drawable icon = null; - try { - icon = activity.getPackageManager().getApplicationIcon("com.android.browser"); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - apps.add(new AppInfo(appName, appName, icon)); - allApps.add(new AppInfo(appName, appName, icon)); + // for websites, URL = packageName == appName + public void addWebsite(String packageName) { + apps.add(new AppInfo(packageName, packageName, true, browserIcon)); + allApps.add(new AppInfo(packageName, packageName, true, browserIcon)); + } + + public void removeWebsite(String packageName) { + apps.remove(new AppInfo(null, packageName, false, null)); + allApps.remove(new AppInfo(null, packageName, false, null)); // compare with equals } - public void removeWebsite(String appName) { - apps.remove(new AppInfo(null, appName, null)); - allApps.remove(new AppInfo(null, appName, null)); // compare with equals + public void updateWebsite(String oldPackageName, String packageName) { + apps.updateItemAt(getPosition(oldPackageName), new AppInfo (packageName, packageName, true, browserIcon)); + allApps.remove(new AppInfo(null, oldPackageName, false, null)); // compare with equals + allApps.add(new AppInfo(null, packageName, false, null)); } public void filter(String s) { diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java index 1025028a..e55d2b7f 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java @@ -156,8 +156,11 @@ public class AutofillService extends AccessibilityService { window = info.getWindow(); } + String packageName; String appName; if (webViewTitle == null) { + packageName = info.getPackageName().toString(); + // get the app name and find a corresponding password PackageManager packageManager = getPackageManager(); ApplicationInfo applicationInfo; @@ -169,9 +172,10 @@ public class AutofillService extends AccessibilityService { appName = (applicationInfo != null ? packageManager.getApplicationLabel(applicationInfo) : "").toString(); setMatchingPasswords(appName, info.getPackageName().toString()); - } else { - appName = setMatchingPasswordsWeb(webViewTitle); + packageName = setMatchingPasswordsWeb(webViewTitle, webViewURL); + + appName = packageName; } // if autofill_always checked, show dialog even if no matches (automatic @@ -179,7 +183,7 @@ public class AutofillService extends AccessibilityService { if (items.isEmpty() && !settings.getBoolean("autofill_always", false)) { return; } - showDialog(appName); + showDialog(packageName, appName); } private String searchWebView(AccessibilityNodeInfo source) { @@ -244,17 +248,19 @@ public class AutofillService extends AccessibilityService { } } - // return key for opening its Settings. Otherwise just use the title - private String setMatchingPasswordsWeb(String webViewTitle) { + // Return the the matched preference's key, which isn't necessarily equal to + // the URL, if a preference is matched so it can be accessed with Settings. + private String setMatchingPasswordsWeb(String webViewTitle, String webViewURL) { SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE); Map<String, ?> prefsMap = prefs.getAll(); for (String key : prefsMap.keySet()) { - if (webViewTitle.toLowerCase().contains(key.toLowerCase())) { + if (webViewURL.toLowerCase().contains(key.toLowerCase())) { getPreferredPasswords(prefs.getString(key, "")); return key; } } - // possible user-defined match not found, try default setting + + // no user-defined match found, maybe auto match using title, not URL if (settings.getBoolean("autofill_default", true)) { if (!PasswordRepository.isInitialized()) { PasswordRepository.initialize(this); @@ -263,7 +269,7 @@ public class AutofillService extends AccessibilityService { } else { items = new ArrayList<>(); } - return webViewTitle; + return webViewURL; } // Put the newline separated list of passwords from the SharedPreferences @@ -305,7 +311,7 @@ public class AutofillService extends AccessibilityService { return items; } - private void showDialog(final String appName) { + private void showDialog(final String packageName, final String appName) { AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog); builder.setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() { @Override @@ -320,12 +326,11 @@ public class AutofillService extends AccessibilityService { // the user will have to return to the app themselves. Intent intent = new Intent(AutofillService.this, AutofillPreferenceActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - if (webViewTitle == null) { - intent.putExtra("packageName", info.getPackageName()); - } else { - intent.putExtra("packageName", appName); - } + intent.putExtra("packageName", packageName); intent.putExtra("appName", appName); + if (webViewTitle != null) { + intent.putExtra("isWeb", true); + } startActivity(intent); } }); diff --git a/app/src/main/res/layout/fragment_autofill.xml b/app/src/main/res/layout/fragment_autofill.xml index 4ac1fc56..1f6aeba2 100644 --- a/app/src/main/res/layout/fragment_autofill.xml +++ b/app/src/main/res/layout/fragment_autofill.xml @@ -1,79 +1,79 @@ <?xml version="1.0" encoding="utf-8"?> - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingBottom="20dp" - android:paddingLeft="24dp" - android:paddingRight="24dp" - android:paddingTop="20dp"> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="20dp" + android:paddingLeft="24dp" + android:paddingRight="24dp" + android:paddingTop="20dp"> - <android.support.design.widget.TextInputLayout xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:hintTextAppearance="@style/TextAppearance.AppCompat"> + <android.support.design.widget.TextInputLayout xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:hintTextAppearance="@style/TextAppearance.AppCompat"> - <EditText - android:id="@+id/webName" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/autofill_webname_hint" - android:inputType="textPersonName"/> - </android.support.design.widget.TextInputLayout> - - <RadioGroup - android:id="@+id/autofill_radiogroup" + <EditText + android:id="@+id/webURL" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:hint="@string/autofill_webURL_hint" + android:inputType="textUri"/> + </android.support.design.widget.TextInputLayout> + + <RadioGroup + android:id="@+id/autofill_radiogroup" + android:layout_width="match_parent" + android:layout_height="wrap_content"> - <RadioButton - android:id="@+id/use_default" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:checked="false" - android:text="@string/autofill_apps_default" /> + <RadioButton + android:id="@+id/use_default" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:checked="false" + android:text="@string/autofill_apps_default" /> - <RadioButton - android:id="@+id/first" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:checked="false" - android:text="@string/autofill_apps_first" /> + <RadioButton + android:id="@+id/first" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:checked="false" + android:text="@string/autofill_apps_first" /> - <RadioButton - android:id="@+id/match" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:checked="false" - android:text="@string/autofill_apps_match_ellipsis" /> + <RadioButton + android:id="@+id/match" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:checked="false" + android:text="@string/autofill_apps_match_ellipsis" /> - <ListView - android:id="@+id/matched" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_weight="1"/> + <ListView + android:id="@+id/matched" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_weight="1"/> - <Button - style="?android:attr/buttonStyleSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="+" - android:id="@+id/matchButton" - android:layout_gravity="center_horizontal"/> + <Button + style="?android:attr/buttonStyleSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="+" + android:id="@+id/matchButton" + android:layout_gravity="center_horizontal"/> - <RadioButton - android:id="@+id/never" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:checked="false" - android:text="@string/autofill_apps_never"/> + <RadioButton + android:id="@+id/never" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:checked="false" + android:text="@string/autofill_apps_never"/> - </RadioGroup> + </RadioGroup> - </LinearLayout>
\ No newline at end of file +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3f4fb345..499ae910 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -171,5 +171,5 @@ <string name="autofill_apps_match_ellipsis">Match with…</string> <string name="autofill_apps_match">Match with</string> <string name="autofill_apps_never">Never match</string> - <string name="autofill_webname_hint">Name</string> + <string name="autofill_webURL_hint">URL</string> </resources> |