Autofill: new UX for TV and support themes
1. Define default Themes for autofill window and save dialog. (http://go/theme_autofill). Phone uses light themes, TV uses dark themes. 2. Apply autofill theme to RemoteViews passed from autofill service. So this can make sure the textColor of RemoteViews matches the background of autofill theme uses. Updated public javadoc that autofill service should not hardcode color values. 3. A new TV ux that occupies half screen height (go/autofill-for-tv). TV autofill now passes unhandled physical keyevent to app window in the same way phone/tablet does. 4. Fixed ATV autofill window to be SYSTEM_DIALOG, so it wont be clipped by app activity window (DialogLauncherActivityTest). Bug: 71720680 Bug: 74072921 Test: CtsAutofillTest Change-Id: Ib570227b0958b1800e8f0600b8aec36478568d74
This commit is contained in:
parent
7f352dbeaf
commit
36b86c28f8
@ -82,6 +82,9 @@ public final class BatchUpdates implements Parcelable {
|
||||
* {@link #transformChild(int, Transformation) transformations} are applied to the children
|
||||
* views.
|
||||
*
|
||||
* <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
|
||||
* or background color: Autofill on different platforms may have different themes.
|
||||
*
|
||||
* @param updates a {@link RemoteViews} with the updated actions to be applied in the
|
||||
* underlying presentation template.
|
||||
*
|
||||
|
@ -336,6 +336,9 @@ public final class Dataset implements Parcelable {
|
||||
* higher, datasets that require authentication can be also be filtered by passing a
|
||||
* {@link AutofillValue#forText(CharSequence) text value} as the {@code value} parameter.
|
||||
*
|
||||
* <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
|
||||
* or background color: Autofill on different platforms may have different themes.
|
||||
*
|
||||
* @param id id returned by {@link
|
||||
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
|
||||
* @param value the value to be autofilled. Pass {@code null} if you do not have the value
|
||||
|
@ -241,6 +241,9 @@ public final class FillResponse implements Parcelable {
|
||||
* immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
|
||||
* platform needs to fill in the authentication arguments.
|
||||
*
|
||||
* <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
|
||||
* or background color: Autofill on different platforms may have different themes.
|
||||
*
|
||||
* @param authentication Intent to an activity with your authentication flow.
|
||||
* @param presentation The presentation to visualize the response.
|
||||
* @param ids id of Views that when focused will display the authentication UI.
|
||||
@ -449,6 +452,9 @@ public final class FillResponse implements Parcelable {
|
||||
* authentication (as the header could have been set directly in the main presentation in
|
||||
* these cases).
|
||||
*
|
||||
* <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
|
||||
* or background color: Autofill on different platforms may have different themes.
|
||||
*
|
||||
* @param header a presentation to represent the header. This presentation is not clickable
|
||||
* —calling
|
||||
* {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would
|
||||
@ -477,6 +483,9 @@ public final class FillResponse implements Parcelable {
|
||||
* authentication (as the footer could have been set directly in the main presentation in
|
||||
* these cases).
|
||||
*
|
||||
* <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
|
||||
* or background color: Autofill on different platforms may have different themes.
|
||||
*
|
||||
* @param footer a presentation to represent the footer. This presentation is not clickable
|
||||
* —calling
|
||||
* {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would
|
||||
|
@ -19,6 +19,7 @@ package android.view.autofill;
|
||||
import static android.view.autofill.Helper.sVerbose;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.IBinder;
|
||||
@ -79,11 +80,6 @@ public class AutofillPopupWindow extends PopupWindow {
|
||||
public AutofillPopupWindow(@NonNull IAutofillWindowPresenter presenter) {
|
||||
mWindowPresenter = new WindowPresenter(presenter);
|
||||
|
||||
// We want to show the window as system controlled one so it covers app windows, but it has
|
||||
// to be an application type (so it's contained inside the application area).
|
||||
// Hence, we set it to the application type with the highest z-order, which currently
|
||||
// is TYPE_APPLICATION_ABOVE_SUB_PANEL.
|
||||
setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
|
||||
setTouchModal(false);
|
||||
setOutsideTouchable(true);
|
||||
setInputMethodMode(INPUT_METHOD_NOT_NEEDED);
|
||||
@ -110,7 +106,16 @@ public class AutofillPopupWindow extends PopupWindow {
|
||||
*/
|
||||
public void update(View anchor, int offsetX, int offsetY, int width, int height,
|
||||
Rect virtualBounds) {
|
||||
mFullScreen = width == LayoutParams.MATCH_PARENT && height == LayoutParams.MATCH_PARENT;
|
||||
mFullScreen = width == LayoutParams.MATCH_PARENT;
|
||||
// For no fullscreen autofill window, we want to show the window as system controlled one
|
||||
// so it covers app windows, but it has to be an application type (so it's contained inside
|
||||
// the application area). Hence, we set it to the application type with the highest z-order,
|
||||
// which currently is TYPE_APPLICATION_ABOVE_SUB_PANEL.
|
||||
// For fullscreen mode, autofill window is at the bottom of screen, it should not be
|
||||
// clipped by app activity window. Fullscreen autofill window does not need to follow app
|
||||
// anchor view position.
|
||||
setWindowLayoutType(mFullScreen ? WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
|
||||
: WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
|
||||
// If we are showing the popup for a virtual view we use a fake view which
|
||||
// delegates to the anchor but present itself with the same bounds as the
|
||||
// virtual view. This ensures that the location logic in popup works
|
||||
@ -119,6 +124,15 @@ public class AutofillPopupWindow extends PopupWindow {
|
||||
if (mFullScreen) {
|
||||
offsetX = 0;
|
||||
offsetY = 0;
|
||||
// If it is not fullscreen height, put window at bottom. Computes absolute position.
|
||||
// Note that we cannot easily change default gravity from Gravity.TOP to
|
||||
// Gravity.BOTTOM because PopupWindow base class does not expose computeGravity().
|
||||
final Point outPoint = new Point();
|
||||
anchor.getContext().getDisplay().getSize(outPoint);
|
||||
width = outPoint.x;
|
||||
if (height != LayoutParams.MATCH_PARENT) {
|
||||
offsetY = outPoint.y - height;
|
||||
}
|
||||
actualAnchor = anchor;
|
||||
} else if (virtualBounds != null) {
|
||||
final int[] mLocationOnScreen = new int[] {virtualBounds.left, virtualBounds.top};
|
||||
@ -202,6 +216,16 @@ public class AutofillPopupWindow extends PopupWindow {
|
||||
actualAnchor = anchor;
|
||||
}
|
||||
|
||||
if (!mFullScreen) {
|
||||
// No fullscreen window animation is controlled by PopupWindow.
|
||||
setAnimationStyle(-1);
|
||||
} else if (height == LayoutParams.MATCH_PARENT) {
|
||||
// Complete fullscreen autofill window has no animation.
|
||||
setAnimationStyle(0);
|
||||
} else {
|
||||
// Slide half screen height autofill window from bottom.
|
||||
setAnimationStyle(com.android.internal.R.style.AutofillHalfScreenAnimation);
|
||||
}
|
||||
if (!isShowing()) {
|
||||
setWidth(width);
|
||||
setHeight(height);
|
||||
@ -223,7 +247,12 @@ public class AutofillPopupWindow extends PopupWindow {
|
||||
protected boolean findDropDownPosition(View anchor, LayoutParams outParams,
|
||||
int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) {
|
||||
if (mFullScreen) {
|
||||
// Do not patch LayoutParams if force full screen
|
||||
// In fullscreen mode, don't need consider the anchor view.
|
||||
outParams.x = xOffset;
|
||||
outParams.y = yOffset;
|
||||
outParams.width = width;
|
||||
outParams.height = height;
|
||||
outParams.gravity = gravity;
|
||||
return false;
|
||||
}
|
||||
return super.findDropDownPosition(anchor, outParams, xOffset, yOffset,
|
||||
@ -315,11 +344,6 @@ public class AutofillPopupWindow extends PopupWindow {
|
||||
throw new IllegalStateException("You can't call this!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnimationStyle(int animationStyle) {
|
||||
throw new IllegalStateException("You can't call this!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundDrawable(Drawable background) {
|
||||
throw new IllegalStateException("You can't call this!");
|
||||
|
@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.DimenRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.StyleRes;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.Application;
|
||||
@ -56,6 +57,7 @@ import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.LayoutInflater.Filter;
|
||||
import android.view.RemotableViewMethod;
|
||||
@ -181,6 +183,12 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
*/
|
||||
private boolean mIsRoot = true;
|
||||
|
||||
/**
|
||||
* Optional theme resource id applied in inflateView(). When 0, Theme.DeviceDefault will be
|
||||
* used.
|
||||
*/
|
||||
private int mApplyThemeResId;
|
||||
|
||||
/**
|
||||
* Whether reapply is disallowed on this remoteview. This maybe be true if some actions modify
|
||||
* the layout in a way that isn't recoverable, since views are being removed.
|
||||
@ -3247,6 +3255,14 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the theme used in apply() and applyASync().
|
||||
* @hide
|
||||
*/
|
||||
public void setApplyTheme(@StyleRes int themeResId) {
|
||||
mApplyThemeResId = themeResId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflates the view hierarchy represented by this object and applies
|
||||
* all of the actions.
|
||||
@ -3282,6 +3298,10 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
final Context contextForResources = getContextForResources(context);
|
||||
Context inflationContext = new RemoteViewsContextWrapper(context, contextForResources);
|
||||
|
||||
// If mApplyThemeResId is not given, Theme.DeviceDefault will be used.
|
||||
if (mApplyThemeResId != 0) {
|
||||
inflationContext = new ContextThemeWrapper(inflationContext, mApplyThemeResId);
|
||||
}
|
||||
LayoutInflater inflater = (LayoutInflater)
|
||||
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
|
100
core/res/res/layout-television/autofill_save.xml
Normal file
100
core/res/res/layout-television/autofill_save.xml
Normal file
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<!-- NOTE: outer layout is required to provide proper shadow. -->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/autofill_save"
|
||||
android:background="?android:attr/colorBackground"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="40dp"
|
||||
android:paddingEnd="40dp"
|
||||
android:paddingTop="40dp"
|
||||
android:paddingBottom="40dp">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="32dp">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/autofill_save_icon"
|
||||
android:scaleType="fitStart"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"/>
|
||||
<TextView
|
||||
android:id="@+id/autofill_save_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/autofill_save_title"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textSize="24sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.android.server.autofill.ui.CustomScrollView
|
||||
android:id="@+id/autofill_save_custom_subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="304dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/autofill_save_no"
|
||||
style="?attr/borderlessButtonStyle"
|
||||
android:textAlignment="viewStart"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/autofill_save_no">
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
android:id="@+id/autofill_save_yes"
|
||||
style="?attr/borderlessButtonStyle"
|
||||
android:textAlignment="viewStart"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/autofill_save_yes">
|
||||
</Button>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -14,8 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<view xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
class="com.android.server.autofill.ui.FillUi$AutofillFrameLayout"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/autofill_dataset_picker"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
@ -31,4 +30,4 @@
|
||||
android:visibility="gone">
|
||||
</ListView>
|
||||
|
||||
</view>
|
||||
</FrameLayout>
|
||||
|
@ -14,35 +14,73 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/autofill_dataset_picker"
|
||||
style="@style/AutofillDatasetPicker"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:paddingStart="40dp"
|
||||
android:paddingEnd="40dp"
|
||||
android:paddingTop="40dp"
|
||||
android:paddingBottom="40dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/autofill_window_title"
|
||||
android:layout_above="@+id/autofill_dataset_container"
|
||||
android:layout_alignStart="@+id/autofill_dataset_container"
|
||||
android:textSize="16sp"/>
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="32dp">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
>
|
||||
<ImageView
|
||||
android:id="@+id/autofill_dataset_icon"
|
||||
android:scaleType="fitStart"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"/>
|
||||
<TextView
|
||||
android:id="@+id/autofill_dataset_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textSize="24sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/autofill_dataset_header"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- autofill_container is the common parent for inserting authentication item or
|
||||
autofill_dataset_list-->
|
||||
<FrameLayout
|
||||
android:id="@+id/autofill_dataset_container"
|
||||
android:layout_width="wrap_content"
|
||||
autofill_dataset_list, autofill_dataset_foolter-->
|
||||
<LinearLayout
|
||||
android:layout_width="304dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true">
|
||||
android:id="@+id/autofill_dataset_picker"
|
||||
android:orientation="vertical">
|
||||
<ListView
|
||||
android:id="@+id/autofill_dataset_list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:divider="@null"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:visibility="gone"/>
|
||||
</FrameLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/autofill_dataset_footer"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"/>
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
@ -14,8 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<view xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
class="com.android.server.autofill.ui.FillUi$AutofillFrameLayout"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/autofill_dataset_picker"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
@ -54,4 +53,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</view>
|
||||
</FrameLayout>
|
||||
|
@ -1,73 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/autofill_dataset_picker"
|
||||
style="@style/AutofillDatasetPicker"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/autofill_window_title"
|
||||
android:layout_above="@+id/autofill_dataset_container"
|
||||
android:layout_alignStart="@+id/autofill_dataset_container"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<!-- autofill_container is the common parent for inserting authentication item or
|
||||
autofill_dataset_list-->
|
||||
<FrameLayout
|
||||
android:id="@+id/autofill_dataset_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true">
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/autofill_dataset_header"
|
||||
android:visibility="gone"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/autofill_dataset_list"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:clickable="true"
|
||||
android:divider="@null"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/autofill_dataset_footer"
|
||||
android:visibility="gone"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</RelativeLayout>
|
@ -20,8 +20,4 @@
|
||||
<item type="dimen" format="float" name="ambient_shadow_alpha">0.15</item>
|
||||
<item type="dimen" format="float" name="spot_shadow_alpha">0.3</item>
|
||||
|
||||
<!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
|
||||
<dimen name="autofill_dataset_picker_max_width">60%</dimen>
|
||||
<dimen name="autofill_dataset_picker_max_height">70%</dimen>
|
||||
|
||||
</resources>
|
||||
|
@ -16,4 +16,6 @@
|
||||
<resources>
|
||||
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
|
||||
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
|
||||
<style name="Theme.DeviceDefault.Autofill" parent="Theme.Material.Autofill" />
|
||||
<style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.Material.Autofill.Save" />
|
||||
</resources>
|
||||
|
@ -145,4 +145,8 @@
|
||||
<color name="datepicker_default_view_animator_color_material_light">#fff2f2f2</color>
|
||||
<color name="datepicker_default_view_animator_color_material_dark">#ff303030</color>
|
||||
|
||||
<!-- Autofill colors -->
|
||||
<color name="autofill_background_material_dark">@color/material_blue_grey_900</color>
|
||||
<color name="autofill_background_material_light">@color/material_grey_50</color>
|
||||
|
||||
</resources>
|
||||
|
@ -2196,8 +2196,8 @@
|
||||
<!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form but the user has not configured an AutoFill profile [CHAR-LIMIT=19] -->
|
||||
<string name="setup_autofill">Set up Autofill</string>
|
||||
|
||||
<!-- Title of fullscreen autofill window [CHAR-LIMIT=80] -->
|
||||
<string name="autofill_window_title">Autofill</string>
|
||||
<!-- Title of fullscreen autofill window, including the name of which autofill service it is using [CHAR-LIMIT=NONE] -->
|
||||
<string name="autofill_window_title">Autofill with <xliff:g id="serviceName" example="MyPass">%1$s</xliff:g></string>
|
||||
|
||||
<!-- String used to separate FirstName and LastName when writing out a local name
|
||||
e.g. John<separator>Smith [CHAR-LIMIT=NONE]-->
|
||||
|
@ -1487,12 +1487,18 @@ please see styles_device_defaults.xml.
|
||||
<item name="successColor">@color/lock_pattern_view_success_color</item>
|
||||
</style>
|
||||
|
||||
<!-- @hide -->
|
||||
<!-- @hide Autofill background for popup window (not for fullscreen) -->
|
||||
<style name="AutofillDatasetPicker">
|
||||
<item name="elevation">4dp</item>
|
||||
<item name="background">@drawable/autofill_dataset_picker_background</item>
|
||||
</style>
|
||||
|
||||
<!-- @hide -->
|
||||
<style name="AutofillHalfScreenAnimation">
|
||||
<item name="android:windowEnterAnimation">@anim/slide_in_up</item>
|
||||
<item name="android:windowExitAnimation">@anim/slide_out_down</item>
|
||||
</style>
|
||||
|
||||
<!-- @hide -->
|
||||
<style name="AutofillSaveAnimation">
|
||||
<item name="android:windowEnterAnimation">@anim/slide_in_up</item>
|
||||
|
@ -662,6 +662,7 @@
|
||||
<java-symbol type="string" name="autofill_state_re" />
|
||||
<java-symbol type="string" name="autofill_this_form" />
|
||||
<java-symbol type="string" name="autofill_username_re" />
|
||||
<java-symbol type="string" name="autofill_window_title" />
|
||||
<java-symbol type="string" name="autofill_zip_4_re" />
|
||||
<java-symbol type="string" name="autofill_zip_code" />
|
||||
<java-symbol type="string" name="autofill_zip_code_re" />
|
||||
@ -3045,13 +3046,13 @@
|
||||
<java-symbol type="layout" name="autofill_dataset_picker"/>
|
||||
<java-symbol type="layout" name="autofill_dataset_picker_fullscreen"/>
|
||||
<java-symbol type="layout" name="autofill_dataset_picker_header_footer"/>
|
||||
<java-symbol type="layout" name="autofill_dataset_picker_header_footer_fullscreen"/>
|
||||
<java-symbol type="id" name="autofill" />
|
||||
<java-symbol type="id" name="autofill_dataset_container"/>
|
||||
<java-symbol type="id" name="autofill_dataset_footer"/>
|
||||
<java-symbol type="id" name="autofill_dataset_header"/>
|
||||
<java-symbol type="id" name="autofill_dataset_icon" />
|
||||
<java-symbol type="id" name="autofill_dataset_list"/>
|
||||
<java-symbol type="id" name="autofill_dataset_picker"/>
|
||||
<java-symbol type="id" name="autofill_dataset_title" />
|
||||
<java-symbol type="id" name="autofill_save_custom_subtitle" />
|
||||
<java-symbol type="id" name="autofill_save_icon" />
|
||||
<java-symbol type="id" name="autofill_save_no" />
|
||||
@ -3076,6 +3077,7 @@
|
||||
<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" />
|
||||
<java-symbol type="style" name="AutofillHalfScreenAnimation" />
|
||||
<java-symbol type="style" name="AutofillSaveAnimation" />
|
||||
<java-symbol type="dimen" name="autofill_dataset_picker_max_width"/>
|
||||
<java-symbol type="dimen" name="autofill_dataset_picker_max_height"/>
|
||||
@ -3083,6 +3085,9 @@
|
||||
<java-symbol type="dimen" name="autofill_save_icon_max_size"/>
|
||||
<java-symbol type="integer" name="autofill_max_visible_datasets" />
|
||||
|
||||
<java-symbol type="style" name="Theme.DeviceDefault.Autofill" />
|
||||
<java-symbol type="style" name="Theme.DeviceDefault.Autofill.Save" />
|
||||
|
||||
<java-symbol type="dimen" name="notification_big_picture_max_height"/>
|
||||
<java-symbol type="dimen" name="notification_big_picture_max_width"/>
|
||||
<java-symbol type="dimen" name="notification_media_image_max_width"/>
|
||||
|
@ -1673,6 +1673,15 @@ easier.
|
||||
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
|
||||
</style>
|
||||
|
||||
|
||||
<!-- @hide DeviceDefault theme for the autofill FillUi -->
|
||||
<style name="Theme.DeviceDefault.Autofill" parent="Theme.Material.Autofill.Light">
|
||||
</style>
|
||||
|
||||
<!-- @hide DeviceDefault theme for the autofill SaveUi -->
|
||||
<style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.Material.Autofill.Save.Light">
|
||||
</style>
|
||||
|
||||
<!-- DeviceDefault theme for the default system theme. -->
|
||||
<style name="Theme.DeviceDefault.System" parent="Theme.DeviceDefault.Light.DarkActionBar" />
|
||||
|
||||
|
@ -1417,4 +1417,25 @@ please see themes_device_defaults.xml.
|
||||
<item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
|
||||
<item name="colorSecondary">@color/secondary_material_settings</item>
|
||||
</style>
|
||||
|
||||
<!-- @hide -->
|
||||
<style name="Theme.Material.Autofill" parent="Theme.Material">
|
||||
<item name="colorBackground">@color/autofill_background_material_dark</item>
|
||||
</style>
|
||||
|
||||
<!-- @hide -->
|
||||
<style name="Theme.Material.Autofill.Light" parent="Theme.Material.Light">
|
||||
<item name="colorBackground">@color/autofill_background_material_light</item>
|
||||
</style>
|
||||
|
||||
<!-- @hide -->
|
||||
<style name="Theme.Material.Autofill.Save" parent="Theme.Material.Panel">
|
||||
<item name="colorBackground">@color/autofill_background_material_dark</item>
|
||||
</style>
|
||||
|
||||
<!-- @hide -->
|
||||
<style name="Theme.Material.Autofill.Save.Light" parent="Theme.Material.Light.Panel">
|
||||
<item name="colorBackground">@color/autofill_background_material_light</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -2079,7 +2079,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
}
|
||||
|
||||
getUiForShowing().showFillUi(filledId, response, filterText,
|
||||
mService.getServicePackageName(), mComponentName.getPackageName(), this);
|
||||
mService.getServicePackageName(), mComponentName.getPackageName(),
|
||||
mService.getServiceLabel(), mService.getServiceIcon(), this);
|
||||
|
||||
synchronized (mLock) {
|
||||
if (mUiShownTime == 0) {
|
||||
|
@ -163,11 +163,14 @@ public final class AutoFillUI {
|
||||
* @param filterText text of the view to be filled
|
||||
* @param servicePackageName package name of the autofill service filling the activity
|
||||
* @param packageName package name of the activity that is filled
|
||||
* @param serviceLabel label of autofill service
|
||||
* @param serviceIcon icon of autofill service
|
||||
* @param callback Identifier for the caller
|
||||
*/
|
||||
public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
|
||||
@Nullable String filterText, @Nullable String servicePackageName,
|
||||
@NonNull String packageName, @NonNull AutoFillUiCallback callback) {
|
||||
@NonNull String packageName, @NonNull CharSequence serviceLabel,
|
||||
@NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback) {
|
||||
if (sDebug) {
|
||||
final int size = filterText == null ? 0 : filterText.length();
|
||||
Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars");
|
||||
@ -185,7 +188,7 @@ public final class AutoFillUI {
|
||||
}
|
||||
hideAllUiThread(callback);
|
||||
mFillUi = new FillUi(mContext, response, focusedId,
|
||||
filterText, mOverlayControl, new FillUi.Callback() {
|
||||
filterText, mOverlayControl, serviceLabel, serviceIcon, new FillUi.Callback() {
|
||||
@Override
|
||||
public void onResponsePicked(FillResponse response) {
|
||||
log.setType(MetricsEvent.TYPE_DETAIL);
|
||||
|
@ -26,6 +26,8 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -53,9 +55,11 @@ import android.widget.BaseAdapter;
|
||||
import android.widget.Filter;
|
||||
import android.widget.Filterable;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.server.UiThread;
|
||||
@ -72,30 +76,10 @@ import java.util.stream.Collectors;
|
||||
final class FillUi {
|
||||
private static final String TAG = "FillUi";
|
||||
|
||||
private static final int THEME_ID = com.android.internal.R.style.Theme_DeviceDefault_Autofill;
|
||||
|
||||
private static final TypedValue sTempTypedValue = new TypedValue();
|
||||
|
||||
public static final class AutofillFrameLayout extends FrameLayout {
|
||||
|
||||
OnKeyListener mUnhandledListener;
|
||||
|
||||
public AutofillFrameLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public AutofillFrameLayout(Context context, AttributeSet attrs, @AttrRes int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
boolean handled = super.dispatchKeyEvent(event);
|
||||
if (!handled) {
|
||||
handled = mUnhandledListener.onKey(this, event.getKeyCode(), event);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
void onResponsePicked(@NonNull FillResponse response);
|
||||
void onDatasetPicked(@NonNull Dataset dataset);
|
||||
@ -146,51 +130,64 @@ final class FillUi {
|
||||
|
||||
FillUi(@NonNull Context context, @NonNull FillResponse response,
|
||||
@NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
|
||||
@NonNull OverlayControl overlayControl, @NonNull Callback callback) {
|
||||
mContext = context;
|
||||
@NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
|
||||
@NonNull Drawable serviceIcon, @NonNull Callback callback) {
|
||||
mCallback = callback;
|
||||
mFullScreen = isFullScreen(context);
|
||||
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
mContext = new ContextThemeWrapper(context, THEME_ID);
|
||||
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
|
||||
final RemoteViews headerPresentation = response.getHeader();
|
||||
final RemoteViews footerPresentation = response.getFooter();
|
||||
final ViewGroup decor;
|
||||
if (headerPresentation != null || footerPresentation != null) {
|
||||
decor = (ViewGroup) inflater.inflate(
|
||||
mFullScreen ? R.layout.autofill_dataset_picker_header_footer_fullscreen
|
||||
: R.layout.autofill_dataset_picker_header_footer, null);
|
||||
if (mFullScreen) {
|
||||
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null);
|
||||
} else if (headerPresentation != null || footerPresentation != null) {
|
||||
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_header_footer,
|
||||
null);
|
||||
} else {
|
||||
decor = (ViewGroup) inflater.inflate(
|
||||
mFullScreen ? R.layout.autofill_dataset_picker_fullscreen
|
||||
: R.layout.autofill_dataset_picker, null);
|
||||
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker, null);
|
||||
}
|
||||
final TextView titleView = decor.findViewById(R.id.autofill_dataset_title);
|
||||
if (titleView != null) {
|
||||
titleView.setText(mContext.getString(R.string.autofill_window_title, serviceLabel));
|
||||
}
|
||||
final ImageView iconView = decor.findViewById(R.id.autofill_dataset_icon);
|
||||
if (iconView != null) {
|
||||
iconView.setImageDrawable(serviceIcon);
|
||||
}
|
||||
|
||||
// if autofill ui is not fullscreen, send unhandled keyevent to app window.
|
||||
if (!mFullScreen) {
|
||||
if (decor instanceof AutofillFrameLayout) {
|
||||
((AutofillFrameLayout) decor).mUnhandledListener =
|
||||
(View view, int keyCode, KeyEvent event) -> {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
case KeyEvent.KEYCODE_ESCAPE:
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
return false;
|
||||
default:
|
||||
mCallback.dispatchUnhandledKey(event);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
Slog.wtf(TAG, "Unable to send unhandled key");
|
||||
// In full screen we only initialize size once assuming screen size never changes
|
||||
if (mFullScreen) {
|
||||
final Point outPoint = mTempPoint;
|
||||
mContext.getDisplay().getSize(outPoint);
|
||||
// full with of screen and half height of screen
|
||||
mContentWidth = LayoutParams.MATCH_PARENT;
|
||||
mContentHeight = outPoint.y / 2;
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "initialized fillscreen LayoutParams "
|
||||
+ mContentWidth + "," + mContentHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Send unhandled keyevent to app window.
|
||||
decor.addOnUnhandledKeyEventListener((View view, KeyEvent event) -> {
|
||||
switch (event.getKeyCode() ) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
case KeyEvent.KEYCODE_ESCAPE:
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
return false;
|
||||
default:
|
||||
mCallback.dispatchUnhandledKey(event);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (sVisibleDatasetsMaxCount > 0) {
|
||||
mVisibleDatasetsMaxCount = sVisibleDatasetsMaxCount;
|
||||
if (sVerbose) {
|
||||
@ -218,14 +215,12 @@ final class FillUi {
|
||||
mFooter = null;
|
||||
mAdapter = null;
|
||||
|
||||
// insert authentication item under autofill_dataset_container or decor
|
||||
ViewGroup container = decor.findViewById(R.id.autofill_dataset_container);
|
||||
if (container == null) {
|
||||
container = decor;
|
||||
}
|
||||
// insert authentication item under autofill_dataset_picker
|
||||
ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker);
|
||||
final View content;
|
||||
try {
|
||||
content = response.getPresentation().apply(context, decor, interceptionHandler);
|
||||
response.getPresentation().setApplyTheme(THEME_ID);
|
||||
content = response.getPresentation().apply(mContext, decor, interceptionHandler);
|
||||
container.addView(content);
|
||||
} catch (RuntimeException e) {
|
||||
callback.onCanceled();
|
||||
@ -236,20 +231,22 @@ final class FillUi {
|
||||
decor.setFocusable(true);
|
||||
decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
|
||||
|
||||
final Point maxSize = mTempPoint;
|
||||
resolveMaxWindowSize(context, maxSize);
|
||||
// fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
|
||||
content.getLayoutParams().width = mFullScreen ? maxSize.x
|
||||
: ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
content.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.x,
|
||||
MeasureSpec.AT_MOST);
|
||||
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
|
||||
MeasureSpec.AT_MOST);
|
||||
if (!mFullScreen) {
|
||||
final Point maxSize = mTempPoint;
|
||||
resolveMaxWindowSize(mContext, maxSize);
|
||||
// fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
|
||||
content.getLayoutParams().width = mFullScreen ? maxSize.x
|
||||
: ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
content.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.x,
|
||||
MeasureSpec.AT_MOST);
|
||||
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
|
||||
MeasureSpec.AT_MOST);
|
||||
|
||||
decor.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
mContentWidth = content.getMeasuredWidth();
|
||||
mContentHeight = content.getMeasuredHeight();
|
||||
decor.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
mContentWidth = content.getMeasuredWidth();
|
||||
mContentHeight = content.getMeasuredHeight();
|
||||
}
|
||||
|
||||
mWindow = new AnchoredWindow(decor, overlayControl);
|
||||
requestShowFillUi();
|
||||
@ -263,7 +260,8 @@ final class FillUi {
|
||||
RemoteViews.OnClickHandler clickBlocker = null;
|
||||
if (headerPresentation != null) {
|
||||
clickBlocker = newClickBlocker();
|
||||
mHeader = headerPresentation.apply(context, null, clickBlocker);
|
||||
headerPresentation.setApplyTheme(THEME_ID);
|
||||
mHeader = headerPresentation.apply(mContext, null, clickBlocker);
|
||||
final LinearLayout headerContainer =
|
||||
decor.findViewById(R.id.autofill_dataset_header);
|
||||
if (sVerbose) Slog.v(TAG, "adding header");
|
||||
@ -274,15 +272,21 @@ final class FillUi {
|
||||
}
|
||||
|
||||
if (footerPresentation != null) {
|
||||
if (clickBlocker == null) { // already set for header
|
||||
clickBlocker = newClickBlocker();
|
||||
}
|
||||
mFooter = footerPresentation.apply(context, null, clickBlocker);
|
||||
final LinearLayout footerContainer =
|
||||
decor.findViewById(R.id.autofill_dataset_footer);
|
||||
if (sVerbose) Slog.v(TAG, "adding footer");
|
||||
footerContainer.addView(mFooter);
|
||||
footerContainer.setVisibility(View.VISIBLE);
|
||||
if (footerContainer != null) {
|
||||
if (clickBlocker == null) { // already set for header
|
||||
clickBlocker = newClickBlocker();
|
||||
}
|
||||
footerPresentation.setApplyTheme(THEME_ID);
|
||||
mFooter = footerPresentation.apply(mContext, null, clickBlocker);
|
||||
// Footer not supported on some platform e.g. TV
|
||||
if (sVerbose) Slog.v(TAG, "adding footer");
|
||||
footerContainer.addView(mFooter);
|
||||
footerContainer.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mFooter = null;
|
||||
}
|
||||
} else {
|
||||
mFooter = null;
|
||||
}
|
||||
@ -301,7 +305,8 @@ final class FillUi {
|
||||
final View view;
|
||||
try {
|
||||
if (sVerbose) Slog.v(TAG, "setting remote view for " + focusedViewId);
|
||||
view = presentation.apply(context, null, interceptionHandler);
|
||||
presentation.setApplyTheme(THEME_ID);
|
||||
view = presentation.apply(mContext, null, interceptionHandler);
|
||||
} catch (RuntimeException e) {
|
||||
Slog.e(TAG, "Error inflating remote views", e);
|
||||
continue;
|
||||
@ -352,12 +357,7 @@ final class FillUi {
|
||||
}
|
||||
|
||||
void requestShowFillUi() {
|
||||
if (mFullScreen) {
|
||||
mCallback.requestShowFillUi(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
|
||||
mWindowPresenter);
|
||||
} else {
|
||||
mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
|
||||
}
|
||||
mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,12 +388,6 @@ final class FillUi {
|
||||
mCallback.requestHideFillUi();
|
||||
} else {
|
||||
if (updateContentSize()) {
|
||||
if (mFullScreen) {
|
||||
LayoutParams lp = mListView.getLayoutParams();
|
||||
lp.width = mContentWidth;
|
||||
lp.height = mContentHeight;
|
||||
mListView.setLayoutParams(lp);
|
||||
}
|
||||
requestShowFillUi();
|
||||
}
|
||||
if (mAdapter.getCount() > mVisibleDatasetsMaxCount) {
|
||||
@ -452,6 +446,10 @@ final class FillUi {
|
||||
if (mAdapter == null) {
|
||||
return false;
|
||||
}
|
||||
if (mFullScreen) {
|
||||
// always request show fill window with fixed size for fullscreen
|
||||
return true;
|
||||
}
|
||||
boolean changed = false;
|
||||
if (mAdapter.getCount() <= 0) {
|
||||
if (mContentWidth != 0) {
|
||||
@ -476,11 +474,6 @@ final class FillUi {
|
||||
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
|
||||
MeasureSpec.AT_MOST);
|
||||
final int itemCount = mAdapter.getCount();
|
||||
if (mFullScreen) {
|
||||
// fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
|
||||
changed = true;
|
||||
mContentWidth = maxSize.x;
|
||||
}
|
||||
|
||||
if (mHeader != null) {
|
||||
mHeader.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
@ -491,20 +484,9 @@ final class FillUi {
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
final View view = mAdapter.getItem(i).view;
|
||||
view.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (mFullScreen) {
|
||||
// for fullscreen, add up all children height until hit max height.
|
||||
final int newContentHeight = mContentHeight + view.getMeasuredHeight();
|
||||
final int clampedNewHeight = Math.min(newContentHeight, maxSize.y);
|
||||
if (clampedNewHeight != mContentHeight) {
|
||||
mContentHeight = clampedNewHeight;
|
||||
} else if (view.getMeasuredHeight() > 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
changed |= updateWidth(view, maxSize);
|
||||
if (i < mVisibleDatasetsMaxCount) {
|
||||
changed |= updateHeight(view, maxSize);
|
||||
}
|
||||
changed |= updateWidth(view, maxSize);
|
||||
if (i < mVisibleDatasetsMaxCount) {
|
||||
changed |= updateHeight(view, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ import android.text.Html;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -70,6 +71,9 @@ final class SaveUi {
|
||||
|
||||
private static final String TAG = "AutofillSaveUi";
|
||||
|
||||
private static final int THEME_ID =
|
||||
com.android.internal.R.style.Theme_DeviceDefault_Autofill_Save;
|
||||
|
||||
public interface OnSaveListener {
|
||||
void onSave();
|
||||
void onCancel(IntentSender listener);
|
||||
@ -144,6 +148,7 @@ final class SaveUi {
|
||||
mServicePackageName = servicePackageName;
|
||||
mPackageName = packageName;
|
||||
|
||||
context = new ContextThemeWrapper(context, THEME_ID);
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final View view = inflater.inflate(R.layout.autofill_save, null);
|
||||
|
||||
@ -222,7 +227,7 @@ final class SaveUi {
|
||||
final View yesButton = view.findViewById(R.id.autofill_save_yes);
|
||||
yesButton.setOnClickListener((v) -> mListener.onSave());
|
||||
|
||||
mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
|
||||
mDialog = new Dialog(context, THEME_ID);
|
||||
mDialog.setContentView(view);
|
||||
|
||||
// Dialog can be dismissed when touched outside, but the negative listener should not be
|
||||
@ -309,6 +314,7 @@ final class SaveUi {
|
||||
|
||||
try {
|
||||
// Create the remote view peer.
|
||||
template.setApplyTheme(THEME_ID);
|
||||
final View customSubtitleView = template.apply(context, null, handler);
|
||||
|
||||
// And apply batch updates (if any).
|
||||
|
Loading…
x
Reference in New Issue
Block a user