Merge "Apply Credman Spec styles to Inline Presentation" into main
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
index 7cb1d01..b4d2eeb 100644
--- a/packages/CredentialManager/res/values/colors.xml
+++ b/packages/CredentialManager/res/values/colors.xml
@@ -22,4 +22,7 @@
<color name="dropdown_container">#F3F3FA</color>
<color name="sign_in_options_container">#DADADA</color>
<color name="sign_in_options_icon_color">#1B1B1B</color>
+
+ <!-- These colors are used for Inline Suggestions. -->
+ <color name="inline_background">#FFFFFF</color>
</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
index b47a4dc..350920b2 100644
--- a/packages/CredentialManager/res/values/dimens.xml
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -28,4 +28,6 @@
<dimen name="dropdown_layout_horizontal_margin">24dp</dimen>
<integer name="autofill_max_visible_datasets">5</integer>
<dimen name="dropdown_touch_target_min_height">48dp</dimen>
+ <dimen name="horizontal_chip_padding">8dp</dimen>
+ <dimen name="vertical_chip_padding">6dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index eef75c7..0f17217 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -57,6 +57,7 @@
import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PublicKeyCredentialEntry
import com.android.credentialmanager.GetFlowUtils
+import com.android.credentialmanager.common.ui.InlinePresentationsFactory
import com.android.credentialmanager.common.ui.RemoteViewsFactory
import com.android.credentialmanager.getflow.ProviderDisplayInfo
import com.android.credentialmanager.getflow.toProviderDisplayInfo
@@ -294,8 +295,12 @@
} else {
inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
}
- inlinePresentation = createInlinePresentation(primaryEntry, pendingIntent, icon,
- spec!!, duplicateDisplayNamesForPasskeys)
+ if (spec != null) {
+ inlinePresentation = createInlinePresentation(primaryEntry, pendingIntent, icon,
+ InlinePresentationsFactory.modifyInlinePresentationSpec
+ (this@CredentialAutofillService, spec),
+ duplicateDisplayNamesForPasskeys)
+ }
}
var dropdownPresentation: RemoteViews? = null
if (i < lastDropdownDatasetIndex) {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt
new file mode 100644
index 0000000..3ebdd20
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt
@@ -0,0 +1,84 @@
+/*
+* Copyright (C) 2024 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.
+*/
+
+
+package com.android.credentialmanager.common.ui
+
+
+import android.content.Context
+import android.util.Size
+import android.widget.inline.InlinePresentationSpec
+import androidx.autofill.inline.common.TextViewStyle
+import androidx.autofill.inline.common.ViewStyle
+import androidx.autofill.inline.UiVersions
+import androidx.autofill.inline.UiVersions.Style
+import androidx.autofill.inline.v1.InlineSuggestionUi
+import androidx.core.content.ContextCompat
+import android.util.TypedValue
+import android.graphics.Typeface
+
+
+class InlinePresentationsFactory {
+ companion object {
+ private const val googleSansMediumFontFamily = "google-sans-medium"
+ private const val googleSansTextFontFamily = "google-sans-text"
+ // There is no min width required for now but this is needed for the spec builder
+ private const val minInlineWidth = 5000
+
+
+ fun modifyInlinePresentationSpec(context: Context,
+ originalSpec: InlinePresentationSpec): InlinePresentationSpec {
+ return InlinePresentationSpec.Builder(Size(originalSpec.minSize.width, originalSpec
+ .minSize.height),
+ Size(minInlineWidth, originalSpec
+ .maxSize.height))
+ .setStyle(UiVersions.newStylesBuilder().addStyle(getStyle(context)).build())
+ .build()
+ }
+
+
+ fun getStyle(context: Context): Style {
+ val textColorPrimary = ContextCompat.getColor(context,
+ com.android.credentialmanager.R.color.text_primary)
+ val textColorSecondary = ContextCompat.getColor(context,
+ com.android.credentialmanager.R.color.text_secondary)
+ val textColorBackground = ContextCompat.getColor(context,
+ com.android.credentialmanager.R.color.inline_background)
+ val chipHorizontalPadding = context.resources.getDimensionPixelSize(com.android
+ .credentialmanager.R.dimen.horizontal_chip_padding)
+ val chipVerticalPadding = context.resources.getDimensionPixelSize(com.android
+ .credentialmanager.R.dimen.vertical_chip_padding)
+ return InlineSuggestionUi.newStyleBuilder()
+ .setChipStyle(
+ ViewStyle.Builder().setPadding(chipHorizontalPadding,
+ chipVerticalPadding,
+ chipHorizontalPadding, chipVerticalPadding).build()
+ )
+ .setTitleStyle(
+ TextViewStyle.Builder().setTextColor(textColorPrimary).setTextSize
+ (TypedValue.COMPLEX_UNIT_DIP, 14F)
+ .setTypeface(googleSansMediumFontFamily,
+ Typeface.NORMAL).setBackgroundColor(textColorBackground)
+ .build()
+ )
+ .setSubtitleStyle(TextViewStyle.Builder().setTextColor(textColorSecondary)
+ .setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12F).setTypeface
+ (googleSansTextFontFamily, Typeface.NORMAL).setBackgroundColor
+ (textColorBackground).build())
+ .build()
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
index c734680..ffc80ee 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
@@ -16,6 +16,8 @@
package com.android.server.autofill.ui;
+import static android.service.autofill.FillResponse.FLAG_CREDENTIAL_MANAGER_RESPONSE;
+
import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
@@ -24,6 +26,7 @@
import android.content.IntentSender;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
+import android.service.autofill.Flags;
import android.service.autofill.InlinePresentation;
import android.text.TextUtils;
import android.util.Pair;
@@ -141,10 +144,12 @@
return new InlineFillUi(inlineFillUiInfo, inlineAuthentication,
maxInputLengthForAutofill);
} else if (response.getDatasets() != null) {
+ boolean ignoreHostSpec = Flags.autofillCredmanIntegration() && (
+ (response.getFlags() & FLAG_CREDENTIAL_MANAGER_RESPONSE) != 0);
SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
InlineSuggestionFactory.createInlineSuggestions(inlineFillUiInfo,
InlineSuggestionInfo.SOURCE_AUTOFILL, response.getDatasets(),
- uiCallback);
+ uiCallback, ignoreHostSpec);
return new InlineFillUi(inlineFillUiInfo, inlineSuggestions,
maxInputLengthForAutofill);
}
@@ -160,7 +165,8 @@
@NonNull InlineSuggestionUiCallback uiCallback) {
SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
InlineSuggestionFactory.createInlineSuggestions(inlineFillUiInfo,
- InlineSuggestionInfo.SOURCE_PLATFORM, datasets, uiCallback);
+ InlineSuggestionInfo.SOURCE_PLATFORM, datasets,
+ uiCallback, /* ignoreHostSpec= */ false);
return new InlineFillUi(inlineFillUiInfo, inlineSuggestions);
}
@@ -254,7 +260,7 @@
if (!TextUtils.isEmpty(mFilterText) && mFilterText.length() > mMaxInputLengthForAutofill) {
if (sVerbose) {
Slog.v(TAG, "Not showing inline suggestion when user entered more than "
- + mMaxInputLengthForAutofill + " characters");
+ + mMaxInputLengthForAutofill + " characters");
}
return new InlineSuggestionsResponse(inlineSuggestions);
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 52109ba..d3b9501 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -16,6 +16,7 @@
package com.android.server.autofill.ui;
+import static android.service.autofill.FillResponse.FLAG_CREDENTIAL_MANAGER_RESPONSE;
import static android.view.inputmethod.InlineSuggestionInfo.TYPE_SUGGESTION;
import static com.android.server.autofill.Helper.sDebug;
@@ -25,6 +26,7 @@
import android.content.IntentSender;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
+import android.service.autofill.Flags;
import android.service.autofill.InlinePresentation;
import android.util.Pair;
import android.util.Slog;
@@ -47,11 +49,14 @@
@NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
InlinePresentation inlineAuthentication = response.getInlinePresentation();
final int requestId = response.getRequestId();
+ boolean ignoreHostSpec = Flags.autofillCredmanIntegration() && (
+ (response.getFlags() & FLAG_CREDENTIAL_MANAGER_RESPONSE) != 0);
return createInlineSuggestion(inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL,
InlineSuggestionInfo.TYPE_ACTION, () -> uiCallback.authenticate(requestId,
AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED),
- mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication),
+ mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication,
+ ignoreHostSpec),
createInlineSuggestionTooltip(inlineFillUiInfo.mInlineRequest,
inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL,
response.getInlineTooltipPresentation()),
@@ -67,7 +72,7 @@
@NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
@NonNull @InlineSuggestionInfo.Source String suggestionSource,
@NonNull List<Dataset> datasets,
- @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
+ @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback, boolean ignoreHostSpec) {
if (sDebug) Slog.d(TAG, "createInlineSuggestions(source=" + suggestionSource + ") called");
final InlineSuggestionsRequest request = inlineFillUiInfo.mInlineRequest;
@@ -107,7 +112,8 @@
InlineSuggestion inlineSuggestion = createInlineSuggestion(
inlineFillUiInfo, suggestionSource, suggestionType,
() -> uiCallback.autofill(dataset, index),
- mergedInlinePresentation(request, datasetIndex, inlinePresentation),
+ mergedInlinePresentation(request, datasetIndex, inlinePresentation,
+ ignoreHostSpec),
inlineSuggestionTooltip,
uiCallback);
response.append(datasetIndex, Pair.create(dataset, inlineSuggestion));
@@ -141,16 +147,18 @@
*/
private static InlinePresentation mergedInlinePresentation(
@NonNull InlineSuggestionsRequest request,
- int index, @NonNull InlinePresentation inlinePresentation) {
+ int index, @NonNull InlinePresentation inlinePresentation, boolean ignoreHostSpec) {
final List<InlinePresentationSpec> specs = request.getInlinePresentationSpecs();
if (specs.isEmpty()) {
return inlinePresentation;
}
InlinePresentationSpec specFromHost = specs.get(Math.min(specs.size() - 1, index));
+ InlinePresentationSpec specToUse =
+ ignoreHostSpec ? inlinePresentation.getInlinePresentationSpec() : specFromHost;
InlinePresentationSpec mergedInlinePresentation = new InlinePresentationSpec.Builder(
inlinePresentation.getInlinePresentationSpec().getMinSize(),
inlinePresentation.getInlinePresentationSpec().getMaxSize()).setStyle(
- specFromHost.getStyle()).build();
+ specToUse.getStyle()).build();
return new InlinePresentation(inlinePresentation.getSlice(), mergedInlinePresentation,
inlinePresentation.isPinned());
@@ -211,7 +219,7 @@
inlineFillUiInfo, tooltipInline, () -> { /* no operation */ }, uiCallback);
final InlineSuggestionInfo tooltipInlineSuggestionInfo = new InlineSuggestionInfo(
mergedSpec, suggestionSource, /* autofillHints */ null, TYPE_SUGGESTION,
- /* pinned */ false, /* tooltip */ null);
+ /* pinned */ false, /* tooltip */ null);
return new InlineSuggestion(tooltipInlineSuggestionInfo, tooltipContentProvider);
}