--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape android:shape="rectangle">
+ <corners android:radius="2dp" />
+ <solid android:color="?attr/colorBackground" />
+ </shape>
+</inset>
limitations under the License.
-->
-<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/autofill_dataset_picker"
- android:layout_width="wrap_content"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:divider="@null"
- android:background="#ffffffff"
- android:elevation="@dimen/floating_window_z">
-</ListView>
+ style="@style/AutofillDatasetPicker">
+
+ <ListView
+ android:id="@+id/autofill_dataset_list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:divider="@null"
+ android:visibility="gone">
+ </ListView>
+
+</FrameLayout>
<item name="successColor">@color/lock_pattern_view_success_color</item>
</style>
+ <!-- @hide -->
+ <style name="AutofillDatasetPicker">
+ <item name="elevation">4dp</item>
+ <item name="background">@drawable/autofill_dataset_picker_background</item>
+ </style>
+
</resources>
<java-symbol type="dimen" name="item_touch_helper_swipe_escape_max_velocity"/>
<!-- com.android.server.autofill -->
- <!-- TODO: floating_window_z temporary exposed until Autofill UI uses a ContextThemeWrapper -->
- <java-symbol type="dimen" name="floating_window_z" />
<java-symbol type="layout" name="autofill_save"/>
<java-symbol type="layout" name="autofill_dataset_picker"/>
+ <java-symbol type="id" name="autofill_dataset_list"/>
<java-symbol type="id" name="autofill" />
<java-symbol type="id" name="autofill_save_title" />
<java-symbol type="id" name="autofill_save_subtitle" />
<java-symbol type="string" name="autofill_save_type_credit_card" />
<java-symbol type="string" name="autofill_save_type_username" />
<java-symbol type="string" name="autofill_save_type_email_address" />
+ <java-symbol type="drawable" name="autofill_dataset_picker_background" />
+ <java-symbol type="style" name="AutofillDatasetPicker" />
<!-- Accessibility fingerprint gestures -->
<java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
import android.service.autofill.FillResponse;
import android.service.autofill.SaveInfo;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.IAutofillWindowPresenter;
public final class AutoFillUI {
private static final String TAG = "AutoFillUI";
- private static final int MAX_SAVE_TIMEOUT_MS = (int) (30 * DateUtils.SECOND_IN_MILLIS);
-
private final Handler mHandler = UiThread.getHandler();
private final @NonNull Context mContext;
private @Nullable AutoFillUiCallback mCallback;
- private int mSaveTimeoutMs = (int) (5 * DateUtils.SECOND_IN_MILLIS);
private final MetricsLogger mMetricsLogger = new MetricsLogger();
public interface AutoFillUiCallback {
mHandler.post(this::hideAllUiThread);
}
- public void setSaveTimeout(int timeout) {
- if (timeout > MAX_SAVE_TIMEOUT_MS) {
- throw new IllegalArgumentException("Maximum value is " + MAX_SAVE_TIMEOUT_MS + "ms");
- }
- if (timeout <= 0) {
- throw new IllegalArgumentException("Must be a positive value");
- }
- mSaveTimeoutMs = timeout;
- }
-
public void dump(PrintWriter pw) {
pw.println("Autofill UI");
final String prefix = " ";
final String prefix2 = " ";
pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null);
- pw.print(prefix); pw.print("save timeout: "); pw.println(mSaveTimeoutMs);
if (mFillUi != null) {
pw.print(prefix); pw.println("showsFillUi: true");
mFillUi.dump(pw, prefix2);
private final @Nullable ArrayAdapter<ViewItem> mAdapter;
private @Nullable String mFilterText;
- private final String mAccessibilityTitle;
private int mContentWidth;
private int mContentHeight;
@NonNull Callback callback) {
mCallback = callback;
- mAccessibilityTitle = context.getString(R.string.autofill_picker_accessibility_title);
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ final ViewGroup decor = (ViewGroup) inflater.inflate(
+ R.layout.autofill_dataset_picker, null);
if (response.getAuthentication() != null) {
mListView = null;
final View content;
try {
- content = response.getPresentation().apply(context, null);
+ content = response.getPresentation().apply(context, decor);
+ decor.addView(content);
} catch (RuntimeException e) {
callback.onCanceled();
Slog.e(TAG, "Error inflating remote views", e);
mWindow = null;
return;
}
- final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
content.measure(widthMeasureSpec, heightMeasureSpec);
content.setOnClickListener(v -> mCallback.onResponsePicked(response));
- content.setElevation(context.getResources().getDimension(R.dimen.floating_window_z));
// TODO(b/33197203 , b/36660292): temporary limiting maximum height and minimum width
mContentWidth = Math.max(content.getMeasuredWidth(), 1000);
mContentHeight = Math.min(content.getMeasuredHeight(), 500);
- mWindow = new AnchoredWindow(content);
+ mWindow = new AnchoredWindow(decor);
mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
} else {
final int datasetCount = response.getDatasets().size();
}
};
- final LayoutInflater inflater = LayoutInflater.from(context);
- mListView = (ListView) inflater.inflate(R.layout.autofill_dataset_picker, null);
+ mListView = decor.findViewById(R.id.autofill_dataset_list);
mListView.setAdapter(mAdapter);
+ mListView.setVisibility(View.VISIBLE);
mListView.setOnItemClickListener((adapter, view, position, id) -> {
final ViewItem vi = mAdapter.getItem(position);
mCallback.onDatasetPicked(vi.getDataset());
}
applyNewFilterText();
- mWindow = new AnchoredWindow(mListView);
+ mWindow = new AnchoredWindow(decor);
}
}
private void applyNewFilterText() {
+ final int oldCount = mAdapter.getCount();
mAdapter.getFilter().filter(mFilterText, (count) -> {
if (mDestroyed) {
return;
} else {
mListView.setVerticalScrollBarEnabled(false);
}
+ if (mAdapter.getCount() != oldCount) {
+ mListView.requestLayout();
+ }
}
});
}
public void show(WindowManager.LayoutParams params) {
try {
if (!mShowing) {
- params.accessibilityTitle = mAccessibilityTitle;
+ params.accessibilityTitle = mContentView.getContext()
+ .getString(R.string.autofill_picker_accessibility_title);
mWm.addView(mContentView, params);
mContentView.setOnTouchListener(this);
mShowing = true;
pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter != null);
pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText);
- pw.print(prefix); pw.print("mAccessibilityTitle: "); pw.println(mAccessibilityTitle);
pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);