[automerger skipped] Merge Android 24Q1 Release (ab/11220357) am: a04310d7b5 -s ours
am skip reason: Merged-In Id51dab308ea8b76e335226d555f6b327f6de281e with SHA-1 5329c00299 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/setupcompat/+/25968592
Change-Id: Ibf7e53728c49b8d58704976222f094eec6616f5b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 80a73b5..f9fc433 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,6 +49,7 @@
"main/java/com/google/android/setupcompat/*.java",
"main/java/com/google/android/setupcompat/internal/*.java",
"main/java/com/google/android/setupcompat/logging/*.java",
+ "main/java/com/google/android/setupcompat/logging/*.kt",
"main/java/com/google/android/setupcompat/logging/internal/*.java",
"main/java/com/google/android/setupcompat/template/*.java",
"main/java/com/google/android/setupcompat/util/*.java",
diff --git a/lint-baseline.xml b/lint-baseline.xml
index 43e81f8..bd06eb8 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="`android:Widget.Material.Button.Colored` requires API level 23 (current min is 14)"
- errorLine1=" <style name="SucPartnerCustomizationButton.Primary" parent="android:Widget.Material.Button.Colored">"
+ message="`android:Widget.Material.Button.Colored` requires API level 23 (current min is 19)"
+ errorLine1=' <style name="SucPartnerCustomizationButton.Primary" parent="android:Widget.Material.Button.Colored">'
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="external/setupcompat/main/res/values/styles.xml"
@@ -14,30 +14,8 @@
<issue
id="NewApi"
- message="`android:fontFamily` requires API level 16 (current min is 14)"
- errorLine1=" <item name="android:fontFamily">?attr/sucFooterBarButtonFontFamily</item>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="external/setupcompat/main/res/values/styles.xml"
- line="48"
- column="15"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`android:stateListAnimator` requires API level 21 (current min is 14)"
- errorLine1=" <item name="android:stateListAnimator">@null</item>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="external/setupcompat/main/res/values/styles.xml"
- line="54"
- column="15"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`android:Widget.Material.Button.Borderless.Colored` requires API level 21 (current min is 14)"
- errorLine1=" <style name="SucPartnerCustomizationButton.Secondary" parent="android:Widget.Material.Button.Borderless.Colored">"
+ message="`android:Widget.Material.Button.Borderless.Colored` requires API level 21 (current min is 19)"
+ errorLine1=' <style name="SucPartnerCustomizationButton.Secondary" parent="android:Widget.Material.Button.Borderless.Colored">'
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="external/setupcompat/main/res/values/styles.xml"
@@ -45,15 +23,4 @@
column="59"/>
</issue>
- <issue
- id="NewApi"
- message="`android:fontFamily` requires API level 16 (current min is 14)"
- errorLine1=" <item name="android:fontFamily">?attr/sucFooterBarButtonFontFamily</item>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="external/setupcompat/main/res/values/styles.xml"
- line="68"
- column="15"/>
- </issue>
-
-</issues>
+</issues>
\ No newline at end of file
diff --git a/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java b/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java
index 70b28d9..26e7042 100644
--- a/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java
+++ b/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java
@@ -36,6 +36,8 @@
import com.google.android.setupcompat.internal.SetupCompatServiceInvoker;
import com.google.android.setupcompat.internal.TemplateLayout;
import com.google.android.setupcompat.logging.CustomEvent;
+import com.google.android.setupcompat.logging.LoggingObserver;
+import com.google.android.setupcompat.logging.LoggingObserver.SetupCompatUiEvent.LayoutInflatedEvent;
import com.google.android.setupcompat.logging.MetricKey;
import com.google.android.setupcompat.logging.SetupMetricsLogger;
import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
@@ -258,8 +260,8 @@
}
/**
- * PartnerCustomizationLayout is a template layout for different type of GlifLayout.
- * This method allows each type of layout to report its "GlifLayoutType".
+ * PartnerCustomizationLayout is a template layout for different type of GlifLayout. This method
+ * allows each type of layout to report its "GlifLayoutType".
*/
public void setLayoutTypeMetrics(PersistableBundle bundle) {
this.layoutTypeBundle = bundle;
@@ -329,6 +331,18 @@
}
/**
+ * Sets a logging observer for {@link FooterBarMixin}. The logging observer is used to log
+ * impressions and clicks on the layout and footer bar buttons.
+ *
+ * @throws UnsupportedOperationException if the primary or secondary button has been set before
+ * the logging observer is set
+ */
+ public void setLoggingObserver(LoggingObserver loggingObserver) {
+ getMixin(FooterBarMixin.class).setLoggingObserver(loggingObserver);
+ loggingObserver.log(new LayoutInflatedEvent(this));
+ }
+
+ /**
* Invoke the method onFocusStatusChanged when onWindowFocusChangeListener receive onFocusChanged.
*/
private void onFocusChanged(boolean hasFocus) {
@@ -339,4 +353,3 @@
activity, PartnerCustomizationLayout.this, hasFocus));
}
}
-
diff --git a/main/java/com/google/android/setupcompat/logging/LoggingObserver.kt b/main/java/com/google/android/setupcompat/logging/LoggingObserver.kt
new file mode 100644
index 0000000..4b2f092
--- /dev/null
+++ b/main/java/com/google/android/setupcompat/logging/LoggingObserver.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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.google.android.setupcompat.logging
+
+import android.view.View
+
+/**
+ * An abstract class which can be attached to a Setupcompat layout and provides methods for logging
+ * impressions and interactions of its views and buttons.
+ */
+interface LoggingObserver {
+ fun log(event: SetupCompatUiEvent)
+
+ sealed class SetupCompatUiEvent {
+ data class LayoutInflatedEvent(val view: View) : SetupCompatUiEvent()
+
+ data class LayoutShownEvent(val view: View) : SetupCompatUiEvent()
+
+ data class ButtonInflatedEvent(val view: View, val buttonType: ButtonType) :
+ SetupCompatUiEvent()
+
+ data class ButtonShownEvent(val view: View, val buttonType: ButtonType) : SetupCompatUiEvent()
+
+ data class ButtonInteractionEvent(val view: View, val interactionType: InteractionType) :
+ SetupCompatUiEvent()
+ }
+
+ enum class ButtonType {
+ UNKNOWN,
+ PRIMARY,
+ SECONDARY
+ }
+
+ enum class InteractionType {
+ UNKNOWN,
+ TAP,
+ LONG_PRESS,
+ DOUBLE_TAP
+ }
+}
diff --git a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
index b417857..84cba21 100644
--- a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
+++ b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
@@ -51,6 +51,8 @@
import com.google.android.setupcompat.R;
import com.google.android.setupcompat.internal.FooterButtonPartnerConfig;
import com.google.android.setupcompat.internal.TemplateLayout;
+import com.google.android.setupcompat.logging.LoggingObserver;
+import com.google.android.setupcompat.logging.LoggingObserver.SetupCompatUiEvent.ButtonInflatedEvent;
import com.google.android.setupcompat.logging.internal.FooterBarMixinMetrics;
import com.google.android.setupcompat.partnerconfig.PartnerConfig;
import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
@@ -76,6 +78,7 @@
@VisibleForTesting public LinearLayout buttonContainer;
private FooterButton primaryButton;
private FooterButton secondaryButton;
+ private LoggingObserver loggingObserver;
@IdRes private int primaryButtonId;
@IdRes private int secondaryButtonId;
@VisibleForTesting public FooterButtonPartnerConfig primaryButtonPartnerConfigForTesting;
@@ -222,7 +225,25 @@
metrics.logSecondaryButtonInitialStateVisibility(
/* isVisible= */ true, /* isUsingXml= */ true);
}
+ }
+ public void setLoggingObserver(LoggingObserver observer) {
+ loggingObserver = observer;
+
+ // If primary button is already created, it's likely that {@code setPrimaryButton()} was called
+ // before an {@link LoggingObserver} is set, we need to set an observer and call the right
+ // logging method here.
+ if (primaryButtonId != 0) {
+ loggingObserver.log(
+ new ButtonInflatedEvent(getPrimaryButtonView(), LoggingObserver.ButtonType.PRIMARY));
+ getPrimaryButton().setLoggingObserver(observer);
+ }
+ // Same for secondary button.
+ if (secondaryButtonId != 0) {
+ loggingObserver.log(
+ new ButtonInflatedEvent(getSecondaryButtonView(), LoggingObserver.ButtonType.SECONDARY));
+ getSecondaryButton().setLoggingObserver(observer);
+ }
}
protected boolean isFooterButtonAlignedEnd() {
@@ -409,6 +430,11 @@
primaryButtonPartnerConfigForTesting = footerButtonPartnerConfig;
onFooterButtonInflated(button, footerBarPrimaryBackgroundColor);
onFooterButtonApplyPartnerResource(button, footerButtonPartnerConfig);
+ if (loggingObserver != null) {
+ loggingObserver.log(
+ new ButtonInflatedEvent(getPrimaryButtonView(), LoggingObserver.ButtonType.PRIMARY));
+ footerButton.setLoggingObserver(loggingObserver);
+ }
// Make sure the position of buttons are correctly and prevent primary button create twice or
// more.
@@ -439,7 +465,7 @@
/** Sets secondary button for footer. */
@MainThread
public void setSecondaryButton(FooterButton footerButton) {
- setSecondaryButton(footerButton, /*usePrimaryStyle= */ false);
+ setSecondaryButton(footerButton, /* usePrimaryStyle= */ false);
}
/** Sets secondary button for footer. Allow to use the primary button style. */
@@ -495,6 +521,10 @@
onFooterButtonInflated(button, footerBarSecondaryBackgroundColor);
onFooterButtonApplyPartnerResource(button, footerButtonPartnerConfig);
+ if (loggingObserver != null) {
+ loggingObserver.log(new ButtonInflatedEvent(button, LoggingObserver.ButtonType.SECONDARY));
+ footerButton.setLoggingObserver(loggingObserver);
+ }
// Make sure the position of buttons are correctly and prevent secondary button create twice or
// more.
diff --git a/main/java/com/google/android/setupcompat/template/FooterButton.java b/main/java/com/google/android/setupcompat/template/FooterButton.java
index 90c13ec..38b81c2 100644
--- a/main/java/com/google/android/setupcompat/template/FooterButton.java
+++ b/main/java/com/google/android/setupcompat/template/FooterButton.java
@@ -33,6 +33,9 @@
import androidx.annotation.StyleRes;
import com.google.android.setupcompat.R;
import com.google.android.setupcompat.logging.CustomEvent;
+import com.google.android.setupcompat.logging.LoggingObserver;
+import com.google.android.setupcompat.logging.LoggingObserver.InteractionType;
+import com.google.android.setupcompat.logging.LoggingObserver.SetupCompatUiEvent.ButtonInteractionEvent;
import java.lang.annotation.Retention;
import java.util.Locale;
@@ -53,6 +56,7 @@
private OnClickListener onClickListener;
private OnClickListener onClickListenerWhenDisabled;
private OnButtonEventListener buttonListener;
+ private LoggingObserver loggingObserver;
private int clickCount = 0;
private Locale locale;
private int direction;
@@ -223,9 +227,16 @@
if (onClickListener != null) {
clickCount++;
onClickListener.onClick(v);
+ if (loggingObserver != null) {
+ loggingObserver.log(new ButtonInteractionEvent(v, InteractionType.TAP));
+ }
}
}
+ void setLoggingObserver(LoggingObserver loggingObserver) {
+ this.loggingObserver = loggingObserver;
+ }
+
/** Interface definition for a callback to be invoked when footer button API has set. */
interface OnButtonEventListener {
@@ -263,23 +274,31 @@
public @interface ButtonType {
/** A type of button that doesn't fit into any other categories. */
int OTHER = 0;
+
/**
* A type of button that will set up additional elements of the ongoing setup step(s) when
* clicked.
*/
int ADD_ANOTHER = 1;
+
/** A type of button that will cancel the ongoing setup step(s) and exit setup when clicked. */
int CANCEL = 2;
+
/** A type of button that will clear the progress when clicked. (eg: clear PIN code) */
int CLEAR = 3;
+
/** A type of button that will exit the setup flow when clicked. */
int DONE = 4;
+
/** A type of button that will go to the next screen, or next step in the flow when clicked. */
int NEXT = 5;
+
/** A type of button to opt-in or agree to the features described in the current screen. */
int OPT_IN = 6;
+
/** A type of button that will skip the current step when clicked. */
int SKIP = 7;
+
/** A type of button that will stop the ongoing setup step(s) and skip forward when clicked. */
int STOP = 8;
}
diff --git a/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java b/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java
index 60b2e21..19eea8a 100644
--- a/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java
+++ b/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java
@@ -23,6 +23,7 @@
import android.provider.Settings;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.google.errorprone.annotations.InlineMe;
import java.util.Arrays;
/**
@@ -32,12 +33,20 @@
*/
public final class WizardManagerHelper {
- @VisibleForTesting public static final String ACTION_NEXT = "com.android.wizard.NEXT";
+ /** Enum for notifying an Activity that what SetupWizard flow is */
+ public enum SuwLifeCycleEnum {
+ UNKNOWN,
+ INITIALIZATION,
+ PREDEFERRED,
+ DEFERRED,
+ PORTAL,
+ RESTORE_ANYTIME;
+ }
- // EXTRA_SCRIPT_URI and EXTRA_ACTION_ID are used in setup wizard in versions before M and are
- // kept for backwards compatibility.
- @VisibleForTesting static final String EXTRA_SCRIPT_URI = "scriptUri";
- @VisibleForTesting static final String EXTRA_ACTION_ID = "actionId";
+ /** Extra for notifying an Activity that what SetupWizard flow is. */
+ public static final String EXTRA_SUW_LIFECYCLE = "suw_lifecycle";
+
+ @VisibleForTesting public static final String ACTION_NEXT = "com.android.wizard.NEXT";
@VisibleForTesting static final String EXTRA_WIZARD_BUNDLE = "wizardBundle";
private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
@@ -128,12 +137,19 @@
dstIntent.putExtra(key, srcIntent.getBooleanExtra(key, false));
}
- for (String key : Arrays.asList(EXTRA_THEME, EXTRA_SCRIPT_URI, EXTRA_ACTION_ID)) {
- dstIntent.putExtra(key, srcIntent.getStringExtra(key));
- }
+ // The TikTok code in Restore doesn't let us put serializable extras into intents.
+ dstIntent.putExtra(
+ EXTRA_SUW_LIFECYCLE,
+ srcIntent.getIntExtra(EXTRA_SUW_LIFECYCLE, SuwLifeCycleEnum.UNKNOWN.ordinal()));
+ dstIntent.putExtra(EXTRA_THEME, srcIntent.getStringExtra(EXTRA_THEME));
}
- /** @deprecated Use {@link isInitialSetupWizard} instead. */
+ /**
+ * @deprecated Use {@link isInitialSetupWizard} instead.
+ */
+ @InlineMe(
+ replacement = "intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, false)",
+ imports = "com.google.android.setupcompat.util.WizardManagerHelper")
@Deprecated
public static boolean isSetupWizardIntent(Intent intent) {
return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);
diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java
index 03e9bb5..efa3b7a 100644
--- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java
+++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java
@@ -210,6 +210,10 @@
CONFIG_ILLUSTRATION_MAX_WIDTH(
PartnerConfigKey.KEY_ILLUSTRATION_MAX_WIDTH, ResourceType.DIMENSION),
+ // The max height of the illustration
+ CONFIG_ILLUSTRATION_MAX_HEIGHT(
+ PartnerConfigKey.KEY_ILLUSTRATION_MAX_HEIGHT, ResourceType.DIMENSION),
+
// Background color of the header area
CONFIG_HEADER_AREA_BACKGROUND_COLOR(
PartnerConfigKey.KEY_HEADER_AREA_BACKGROUND_COLOR, ResourceType.COLOR),
diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java
index 1dac81f..fb05a40 100644
--- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java
+++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java
@@ -82,6 +82,7 @@
PartnerConfigKey.KEY_ICON_MARGIN_TOP,
PartnerConfigKey.KEY_ICON_SIZE,
PartnerConfigKey.KEY_ILLUSTRATION_MAX_WIDTH,
+ PartnerConfigKey.KEY_ILLUSTRATION_MAX_HEIGHT,
PartnerConfigKey.KEY_DESCRIPTION_TEXT_SIZE,
PartnerConfigKey.KEY_DESCRIPTION_TEXT_COLOR,
PartnerConfigKey.KEY_DESCRIPTION_LINK_TEXT_COLOR,
@@ -308,8 +309,12 @@
// Size of the icon
String KEY_ICON_SIZE = "setup_design_icon_size";
+ // The max width for illustration
String KEY_ILLUSTRATION_MAX_WIDTH = "setup_design_illustration_max_width";
+ // The max height for illustration
+ String KEY_ILLUSTRATION_MAX_HEIGHT = "setup_design_illustration_max_height";
+
// Background color of the header area
String KEY_HEADER_AREA_BACKGROUND_COLOR = "setup_design_header_area_background_color";