Merge "Autofill: new UX for TV and support themes" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9ea13ca0b6
@@ -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.
|
||||
@@ -3266,6 +3274,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.
|
||||
@@ -3301,6 +3317,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>
|
||||
|
||||
@@ -663,6 +663,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" />
|
||||
@@ -3053,13 +3054,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" />
|
||||
@@ -3084,6 +3085,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"/>
|
||||
@@ -3091,6 +3093,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).
|
||||
|
||||
Reference in New Issue
Block a user