Import updated Android SetupCompat Library 682227189
Copied from google3/third_party/java_src/android_libs/setupcompat
Test: mm
Included changes:
- 682227189 [BC25] Fix NPE when device in the 2 pane mode.
- 681811849 [BC25] Refine down button position in landscape mode. (2/2)
- 681778893 [BC25] Make the button bar with can be in the whole scree...
- 681309180 [BC25][Down Button] Fix the issue that the button width i...
- 680892642 [BC25] Using footer bar width to calcuate the button widt...
- 680884916 Create the keyboard focus change flag.
- 680797017 Automated g4 rollback of changelist 671307433.
- 680440592 [BC25] Add sucFooterBarButtonFontWeight attribute and set...
- 679015292 [BC25] remove using the attribute sucFullDynamicColor as ...
- 678654714 Create item group corner Radius Partner Config.
- 678474263 [BC25] Apply the button width to expressive style if scro...
- 676755151 [SUW] When GlifExpressive flag to PartnerConfigHelper wil...
- 675803166 [BC25] Add margin to footer button in expressive style
- 674997096 [BC25] Add sucFooterBarMinHeight attribute to adjust the ...
- 674083566 [BC25] Add MaterialButton support for FooterBarMixin
- 673750749 [BC25] Add footer button text color for Glif expressive s...
- 672458843 [BC25] Set button width for expressive style
- 672361102 [BC25] Update primary button color for Glif expressive st...
- 671581134 [BC25] Add setVisibility() method to FooterButton.Builder
- 671307433 Automated g4 rollback of changelist 671261504.
- 671261504 Remove the deprecated component CompatEnforcer, due to th...
- 671255468 [BC25] Add IFooterActionButton interface and used in Foot...
- 671156324 [BC25] Add MaterialFooterActionButton
- 668397555 [BC25] Add IFooterActionButton interface to indicate Andr...
- 667870529 [BC25] Guard addSpace when GlifExpressive flag enabled.
- 666114642 [Theme] Add Glif Expressive theme in ThemeHelper and Them...
- 663516526 [BC25] Implement isGlifExpressiveEnabled method in SetupC...
- 661990826 Fix typo in PartnerConfigHelper.isGlifExpressiveEnabled()...
- 660701130 [BC25][Theme] Add isGlifExpressEnabled method to PartnerC...
- 657141370 Create SetupWizardOrchestratorViewModel.
- 656277701 Small fix for passing logging observer from PartnerCustom...
PiperOrigin-RevId: 682227189
Bug: 344740755
Change-Id: I8749422c83edc23a6e725d9806314b20e45fd309
diff --git a/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java b/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java
index 26e7042..fff4c08 100644
--- a/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java
+++ b/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java
@@ -309,6 +309,10 @@
* {@code false}.
*/
public boolean shouldApplyDynamicColor() {
+ if (!PartnerConfigHelper.isSetupWizardDynamicColorEnabled(getContext())) {
+ return false;
+ }
+
if (!useDynamicColor) {
return false;
}
@@ -323,23 +327,23 @@
/**
* Returns {@code true} if the current layout/activity applies full dynamic color. Otherwise,
- * returns {@code false}. This method combines the result of {@link #shouldApplyDynamicColor()}
- * and the value of the {@code app:sucFullDynamicColor}.
+ * returns {@code false}. This method combines the result of {@link #shouldApplyDynamicColor()},
+ * the value of the {@code app:sucFullDynamicColor}, and the result of {@link
+ * PartnerConfigHelper#isSetupWizardFullDynamicColorEnabled(Context)}.
*/
public boolean useFullDynamicColor() {
- return shouldApplyDynamicColor() && useFullDynamicColorAttr;
+ return shouldApplyDynamicColor()
+ && (useFullDynamicColorAttr
+ || PartnerConfigHelper.isSetupWizardFullDynamicColorEnabled(getContext()));
}
/**
- * 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
+ * Sets a logging observer for {@link FooterBarMixin}. The logging observer is used to log UI
+ * events (e.g. page impressions and button clicks) on the layout and footer bar buttons.
*/
public void setLoggingObserver(LoggingObserver loggingObserver) {
- getMixin(FooterBarMixin.class).setLoggingObserver(loggingObserver);
loggingObserver.log(new LayoutInflatedEvent(this));
+ getMixin(FooterBarMixin.class).setLoggingObserver(loggingObserver);
}
/**
diff --git a/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java b/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java
index d882c9d..733ee52 100644
--- a/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java
+++ b/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java
@@ -52,10 +52,6 @@
*/
public static LifecycleFragment attachNow(Activity activity) {
if (WizardManagerHelper.isAnySetupWizard(activity.getIntent())) {
- SetupCompatServiceInvoker.get(activity.getApplicationContext())
- .bindBack(
- LayoutBindBackHelper.getScreenName(activity),
- LayoutBindBackHelper.getExtraBundle(activity));
if (VERSION.SDK_INT > VERSION_CODES.M) {
FragmentManager fragmentManager = activity.getFragmentManager();
diff --git a/main/java/com/google/android/setupcompat/internal/SetupCompatServiceInvoker.java b/main/java/com/google/android/setupcompat/internal/SetupCompatServiceInvoker.java
index ed9c0e3..7208778 100644
--- a/main/java/com/google/android/setupcompat/internal/SetupCompatServiceInvoker.java
+++ b/main/java/com/google/android/setupcompat/internal/SetupCompatServiceInvoker.java
@@ -32,8 +32,7 @@
/**
* This class is responsible for safely executing methods on SetupCompatService. To avoid memory
* issues due to backed up queues, an upper bound of {@link
- * ExecutorProvider#SETUP_METRICS_LOGGER_MAX_QUEUED} is set on the logging executor service's queue
- * and {@link ExecutorProvider#SETUP_COMPAT_BINDBACK_MAX_QUEUED} on the overall executor service.
+ * ExecutorProvider#SETUP_METRICS_LOGGER_MAX_QUEUED} is set on the logging executor service's queue.
* Once the upper bound is reached, metrics published after this event are dropped silently.
*
* <p>NOTE: This class is not meant to be used directly. Please use {@link
@@ -52,14 +51,6 @@
}
}
- public void bindBack(String screenName, Bundle bundle) {
- try {
- loggingExecutor.execute(() -> invokeBindBack(screenName, bundle));
- } catch (RejectedExecutionException e) {
- LOG.e(String.format("Screen %s bind back fail.", screenName), e);
- }
- }
-
/**
* Help invoke the {@link ISetupCompatService#onFocusStatusChanged} using {@code loggingExecutor}.
*/
@@ -110,23 +101,6 @@
}
}
- private void invokeBindBack(String screenName, Bundle bundle) {
- try {
- ISetupCompatService setupCompatService =
- SetupCompatServiceProvider.get(
- context, waitTimeInMillisForServiceConnection, TimeUnit.MILLISECONDS);
- if (setupCompatService != null) {
- setupCompatService.validateActivity(screenName, bundle);
- } else {
- LOG.w("BindBack failed since service reference is null. Are the permissions valid?");
- }
- } catch (InterruptedException | TimeoutException | RemoteException e) {
- LOG.e(
- String.format("Exception occurred while %s trying bind back to SetupWizard.", screenName),
- e);
- }
- }
-
private SetupCompatServiceInvoker(Context context) {
this.context = context;
this.loggingExecutor = ExecutorProvider.setupCompatServiceInvoker.get();
diff --git a/main/java/com/google/android/setupcompat/template/FooterActionButton.java b/main/java/com/google/android/setupcompat/template/FooterActionButton.java
index d9726f9..212f86e 100644
--- a/main/java/com/google/android/setupcompat/template/FooterActionButton.java
+++ b/main/java/com/google/android/setupcompat/template/FooterActionButton.java
@@ -22,12 +22,13 @@
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
-import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
/** Button that can react to touch when disabled. */
-public class FooterActionButton extends Button {
+@SuppressWarnings("AppCompatCustomView")
+public class FooterActionButton extends Button implements IFooterActionButton {
- @Nullable private FooterButton footerButton;
+ @VisibleForTesting FooterButton footerButton;
private boolean isPrimaryButtonStyle = false;
public FooterActionButton(Context context, AttributeSet attrs) {
@@ -38,8 +39,6 @@
this.footerButton = footerButton;
}
- // getOnClickListenerWhenDisabled is responsible for handling accessibility correctly, calling
- // performClick if necessary.
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
@@ -47,6 +46,8 @@
if (footerButton != null
&& !footerButton.isEnabled()
&& footerButton.getVisibility() == View.VISIBLE) {
+ // getOnClickListenerWhenDisabled is responsible for handling accessibility correctly,
+ // calling performClick if necessary.
OnClickListener listener = footerButton.getOnClickListenerWhenDisabled();
if (listener != null) {
listener.onClick(this);
@@ -65,7 +66,7 @@
this.isPrimaryButtonStyle = isPrimaryButtonStyle;
}
- /** Returns true when the footer button is primary button style. */
+ @Override
public boolean isPrimaryButtonStyle() {
return isPrimaryButtonStyle;
}
diff --git a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
index 5939a18..e52b136 100644
--- a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
+++ b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
@@ -25,6 +25,7 @@
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
import android.os.Build.VERSION_CODES;
import android.os.PersistableBundle;
import android.util.AttributeSet;
@@ -34,6 +35,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
@@ -47,6 +50,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
+import com.google.android.material.button.MaterialButton;
import com.google.android.setupcompat.PartnerCustomizationLayout;
import com.google.android.setupcompat.R;
import com.google.android.setupcompat.internal.FooterButtonPartnerConfig;
@@ -57,6 +61,7 @@
import com.google.android.setupcompat.partnerconfig.PartnerConfig;
import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
import com.google.android.setupcompat.template.FooterButton.ButtonType;
+import com.google.android.setupcompat.util.Logger;
import java.util.Locale;
/**
@@ -66,6 +71,8 @@
*/
public class FooterBarMixin implements Mixin {
+ private static final Logger LOG = new Logger("FooterBarMixin");
+
private final Context context;
@Nullable private final ViewStub footerStub;
@@ -93,6 +100,11 @@
@ColorInt private final int footerBarSecondaryBackgroundColor;
private boolean removeFooterBarWhenEmpty = true;
private boolean isSecondaryButtonInPrimaryStyle = false;
+ private final int footerBarPrimaryButtonEnabledTextColor;
+ private final int footerBarSecondaryButtonEnabledTextColor;
+ private final int footerBarPrimaryButtonDisabledTextColor;
+ private final int footerBarSecondaryButtonDisabledTextColor;
+ @VisibleForTesting final int footerBarButtonMiddleSpacing;
@VisibleForTesting public final FooterBarMixinMetrics metrics = new FooterBarMixinMetrics();
@@ -106,16 +118,35 @@
Button button = buttonContainer.findViewById(id);
if (button != null) {
button.setEnabled(enabled);
- if (applyPartnerResources && !applyDynamicColor) {
- updateButtonTextColorWithStates(
- button,
- (id == primaryButtonId || isSecondaryButtonInPrimaryStyle)
- ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_TEXT_COLOR
- : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_TEXT_COLOR,
- (id == primaryButtonId || isSecondaryButtonInPrimaryStyle)
- ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_DISABLED_TEXT_COLOR
- : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_DISABLED_TEXT_COLOR);
+ // TODO: b/364981299 - Use partner config to allow user to customize text color.
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ if (id == primaryButtonId) {
+ updateTextColorForButton(
+ button,
+ enabled,
+ enabled
+ ? footerBarPrimaryButtonEnabledTextColor
+ : footerBarPrimaryButtonDisabledTextColor);
+ } else if (id == secondaryButtonId) {
+ updateTextColorForButton(
+ button,
+ enabled,
+ enabled
+ ? footerBarSecondaryButtonEnabledTextColor
+ : footerBarSecondaryButtonDisabledTextColor);
+ }
+ } else {
+ if (applyPartnerResources && !applyDynamicColor) {
+ updateButtonTextColorWithStates(
+ button,
+ (id == primaryButtonId || isSecondaryButtonInPrimaryStyle)
+ ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_TEXT_COLOR
+ : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_TEXT_COLOR,
+ (id == primaryButtonId || isSecondaryButtonInPrimaryStyle)
+ ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_DISABLED_TEXT_COLOR
+ : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_DISABLED_TEXT_COLOR);
+ }
}
}
}
@@ -128,6 +159,10 @@
if (button != null) {
button.setVisibility(visibility);
autoSetButtonBarVisibility();
+
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ setButtonWidthForExpressiveStyle(/* isDownButton= */ false);
+ }
}
}
}
@@ -206,6 +241,20 @@
a.getColor(R.styleable.SucFooterBarMixin_sucFooterBarSecondaryFooterBackground, 0);
footerButtonAlignEnd =
a.getBoolean(R.styleable.SucFooterBarMixin_sucFooterBarButtonAlignEnd, false);
+ footerBarPrimaryButtonEnabledTextColor =
+ a.getColor(
+ R.styleable.SucFooterBarMixin_sucFooterBarPrimaryFooterButtonEnabledTextColor, 0);
+ footerBarSecondaryButtonEnabledTextColor =
+ a.getColor(
+ R.styleable.SucFooterBarMixin_sucFooterBarSecondaryFooterButtonEnabledTextColor, 0);
+ footerBarPrimaryButtonDisabledTextColor =
+ a.getColor(
+ R.styleable.SucFooterBarMixin_sucFooterBarPrimaryFooterButtonDisabledTextColor, 0);
+ footerBarSecondaryButtonDisabledTextColor =
+ a.getColor(
+ R.styleable.SucFooterBarMixin_sucFooterBarSecondaryFooterButtonDisabledTextColor, 0);
+ footerBarButtonMiddleSpacing =
+ a.getDimensionPixelSize(R.styleable.SucFooterBarMixin_sucFooterBarButtonMiddleSpacing, 0);
int primaryBtn =
a.getResourceId(R.styleable.SucFooterBarMixin_sucFooterBarPrimaryFooterButton, 0);
@@ -379,15 +428,34 @@
}
/**
- * Inflate FooterActionButton with layout "suc_button". Subclasses can implement this method to
+ * Inflate IFooterActionButton with layout "suc_button". Subclasses can implement this method to
* modify the footer button layout as necessary.
*/
@SuppressLint("InflateParams")
- protected FooterActionButton createThemedButton(Context context, @StyleRes int theme) {
+ protected IFooterActionButton createThemedButton(Context context, @StyleRes int theme) {
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ try {
+ if (theme == R.style.SucGlifMaterialButton_Primary) {
+ return new MaterialFooterActionButton(
+ new ContextThemeWrapper(context, theme), null, R.attr.sucMaterialButtonStyle);
+ } else {
+ return new MaterialFooterActionButton(
+ new ContextThemeWrapper(context, theme), null, R.attr.sucMaterialOutlinedButtonStyle);
+ }
+ } catch (IllegalArgumentException e) {
+ LOG.e("Applyed invalid material theme: " + e);
+ // fallback theme style to glif theme
+ if (theme == R.style.SucGlifMaterialButton_Primary) {
+ theme = R.style.SucPartnerCustomizationButton_Primary;
+ } else {
+ theme = R.style.SucPartnerCustomizationButton_Secondary;
+ }
+ }
+ }
// Inflate a single button from XML, which when using support lib, will take advantage of
// the injected layout inflater and give us AppCompatButton instead.
LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(context, theme));
- return (FooterActionButton) inflater.inflate(R.layout.suc_button, null, false);
+ return (IFooterActionButton) inflater.inflate(R.layout.suc_button, null, false);
}
/** Sets primary button for footer. */
@@ -396,13 +464,21 @@
ensureOnMainThread("setPrimaryButton");
ensureFooterInflated();
+ int defaultPartnerTheme;
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ defaultPartnerTheme = R.style.SucGlifMaterialButton_Primary;
+ } else {
+ defaultPartnerTheme = R.style.SucPartnerCustomizationButton_Primary;
+ }
+
+ // TODO: b/364980746 - Use partner config to allow user to customize primary bg color.
// Setup button partner config
FooterButtonPartnerConfig footerButtonPartnerConfig =
new FooterButtonPartnerConfig.Builder(footerButton)
.setPartnerTheme(
getPartnerTheme(
footerButton,
- /* defaultPartnerTheme= */ R.style.SucPartnerCustomizationButton_Primary,
+ /* defaultPartnerTheme= */ defaultPartnerTheme,
/* buttonBackgroundColorConfig= */ PartnerConfig
.CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR))
.setButtonBackgroundConfig(PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR)
@@ -422,14 +498,32 @@
.setTextStyleConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_TEXT_STYLE)
.build();
- FooterActionButton button = inflateButton(footerButton, footerButtonPartnerConfig);
+ IFooterActionButton buttonImpl = inflateButton(footerButton, footerButtonPartnerConfig);
// update information for primary button. Need to update as long as the button inflated.
+ Button button = (Button) buttonImpl;
primaryButtonId = button.getId();
- button.setPrimaryButtonStyle(/* isPrimaryButtonStyle= */ true);
+ if (buttonImpl instanceof MaterialFooterActionButton) {
+ ((MaterialFooterActionButton) buttonImpl)
+ .setPrimaryButtonStyle(/* isPrimaryButtonStyle= */ true);
+ } else if (button instanceof FooterActionButton) {
+ ((FooterActionButton) buttonImpl).setPrimaryButtonStyle(/* isPrimaryButtonStyle= */ true);
+ } else {
+ LOG.e("Set the primary button style error when setting primary button.");
+ }
primaryButton = footerButton;
primaryButtonPartnerConfigForTesting = footerButtonPartnerConfig;
onFooterButtonInflated(button, footerBarPrimaryBackgroundColor);
onFooterButtonApplyPartnerResource(button, footerButtonPartnerConfig);
+ // TODO: b/364981299 - Use partner config to allow user to customize text color.
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ boolean enabled = primaryButton.isEnabled();
+ updateTextColorForButton(
+ button,
+ enabled,
+ enabled
+ ? footerBarPrimaryButtonEnabledTextColor
+ : footerBarPrimaryButtonDisabledTextColor);
+ }
if (loggingObserver != null) {
loggingObserver.log(
new ButtonInflatedEvent(getPrimaryButtonView(), LoggingObserver.ButtonType.PRIMARY));
@@ -475,15 +569,26 @@
isSecondaryButtonInPrimaryStyle = usePrimaryStyle;
ensureFooterInflated();
+ int defaultPartnerTheme;
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ defaultPartnerTheme =
+ usePrimaryStyle
+ ? R.style.SucGlifMaterialButton_Primary
+ : R.style.SucGlifMaterialButton_Secondary;
+ } else {
+ defaultPartnerTheme =
+ usePrimaryStyle
+ ? R.style.SucPartnerCustomizationButton_Primary
+ : R.style.SucPartnerCustomizationButton_Secondary;
+ }
+
// Setup button partner config
FooterButtonPartnerConfig footerButtonPartnerConfig =
new FooterButtonPartnerConfig.Builder(footerButton)
.setPartnerTheme(
getPartnerTheme(
footerButton,
- /* defaultPartnerTheme= */ usePrimaryStyle
- ? R.style.SucPartnerCustomizationButton_Primary
- : R.style.SucPartnerCustomizationButton_Secondary,
+ /* defaultPartnerTheme= */ defaultPartnerTheme,
/* buttonBackgroundColorConfig= */ usePrimaryStyle
? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR
: PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_BG_COLOR))
@@ -512,15 +617,32 @@
.setTextStyleConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_TEXT_STYLE)
.build();
- FooterActionButton button = inflateButton(footerButton, footerButtonPartnerConfig);
+ IFooterActionButton buttonImpl = inflateButton(footerButton, footerButtonPartnerConfig);
// update information for secondary button. Need to update as long as the button inflated.
+ Button button = (Button) buttonImpl;
secondaryButtonId = button.getId();
- button.setPrimaryButtonStyle(usePrimaryStyle);
+ if (buttonImpl instanceof MaterialFooterActionButton) {
+ ((MaterialFooterActionButton) buttonImpl).setPrimaryButtonStyle(usePrimaryStyle);
+ } else if (button instanceof FooterActionButton) {
+ ((FooterActionButton) buttonImpl).setPrimaryButtonStyle(usePrimaryStyle);
+ } else {
+ LOG.e("Set the primary button style error when setting secondary button.");
+ }
secondaryButton = footerButton;
secondaryButtonPartnerConfigForTesting = footerButtonPartnerConfig;
onFooterButtonInflated(button, footerBarSecondaryBackgroundColor);
onFooterButtonApplyPartnerResource(button, footerButtonPartnerConfig);
+ // TODO: b/364981299 - Use partner config to allow user to customize text color.
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ boolean enabled = secondaryButton.isEnabled();
+ updateTextColorForButton(
+ button,
+ enabled,
+ enabled
+ ? footerBarSecondaryButtonEnabledTextColor
+ : footerBarSecondaryButtonDisabledTextColor);
+ }
if (loggingObserver != null) {
loggingObserver.log(new ButtonInflatedEvent(button, LoggingObserver.ButtonType.SECONDARY));
footerButton.setLoggingObserver(loggingObserver);
@@ -545,7 +667,10 @@
boolean isLandscape =
context.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
- if (isLandscape && isEvenlyWeightedButtons && isFooterButtonAlignedEnd()) {
+ if (isLandscape
+ && isEvenlyWeightedButtons
+ && isFooterButtonAlignedEnd()
+ && !PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
addSpace();
}
@@ -562,7 +687,7 @@
}
buttonContainer.addView(tempSecondaryButton);
}
- if (!isFooterButtonAlignedEnd()) {
+ if (!isFooterButtonAlignedEnd() && !PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
addSpace();
}
if (tempPrimaryButton != null) {
@@ -570,6 +695,10 @@
}
setEvenlyWeightedButtons(tempPrimaryButton, tempSecondaryButton, isEvenlyWeightedButtons);
+
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ setButtonWidthForExpressiveStyle(/* isDownButton= */ false);
+ }
}
private void setEvenlyWeightedButtons(
@@ -588,7 +717,7 @@
if (primaryButton != null) {
LinearLayout.LayoutParams primaryLayoutParams =
(LinearLayout.LayoutParams) primaryButton.getLayoutParams();
- if (null != primaryLayoutParams) {
+ if (primaryLayoutParams != null) {
primaryLayoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
primaryLayoutParams.weight = 0;
primaryButton.setLayoutParams(primaryLayoutParams);
@@ -597,7 +726,7 @@
if (secondaryButton != null) {
LinearLayout.LayoutParams secondaryLayoutParams =
(LinearLayout.LayoutParams) secondaryButton.getLayoutParams();
- if (null != secondaryLayoutParams) {
+ if (secondaryLayoutParams != null) {
secondaryLayoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
secondaryLayoutParams.weight = 0;
secondaryButton.setLayoutParams(secondaryLayoutParams);
@@ -606,6 +735,173 @@
}
}
+ // TODO: b/369285240 - Migrate setButtonWidthForExpressiveStyle of FooterBarMixin to
+ /** Sets button width for expressive style. */
+ public void setButtonWidthForExpressiveStyle(boolean isDownButton) {
+ final ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener =
+ new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ int initialLeftMargin = 0;
+ if (!isDownButton) {
+ Button primaryButton = getPrimaryButtonView();
+ Button secondaryButton = getSecondaryButtonView();
+ int footerBarWidth = buttonContainer.getWidth();
+ if (isTwoPaneLayout()) {
+ footerBarWidth = footerBarWidth / 2;
+ if (primaryButton != null) {
+ // Set back the margin once down button scrolling to the bottom.
+ LinearLayout.LayoutParams primaryLayoutParams =
+ ((LayoutParams) primaryButton.getLayoutParams());
+ if (primaryLayoutParams.leftMargin != initialLeftMargin) {
+ primaryLayoutParams.leftMargin = initialLeftMargin;
+ primaryButton.setLayoutParams(primaryLayoutParams);
+ }
+ }
+ buttonContainer.setGravity(Gravity.END);
+ }
+
+ // TODO: b/364981820 - Use partner config to allow user to customize button width.
+ footerBarWidth =
+ footerBarWidth
+ - footerBarPaddingStart
+ - footerBarPaddingEnd
+ - footerBarButtonMiddleSpacing;
+
+ if (isBothButtons(primaryButton, secondaryButton)) {
+ LayoutParams primaryLayoutParams = (LayoutParams) primaryButton.getLayoutParams();
+ LayoutParams secondaryLayoutParams =
+ (LayoutParams) secondaryButton.getLayoutParams();
+ if (primaryLayoutParams != null) {
+ primaryLayoutParams.width = footerBarWidth / 2;
+ primaryLayoutParams.setMarginStart(footerBarButtonMiddleSpacing / 2);
+ primaryButton.setLayoutParams(primaryLayoutParams);
+ }
+ if (secondaryLayoutParams != null) {
+ secondaryLayoutParams.width = footerBarWidth / 2;
+ secondaryLayoutParams.setMarginEnd(footerBarButtonMiddleSpacing / 2);
+ secondaryButton.setLayoutParams(secondaryLayoutParams);
+ }
+ } else if (isPrimaryButtonOnly(primaryButton, secondaryButton)) {
+ LayoutParams primaryLayoutParams = (LayoutParams) primaryButton.getLayoutParams();
+ if (primaryLayoutParams != null) {
+ primaryLayoutParams.width = footerBarWidth;
+ primaryButton.setLayoutParams(primaryLayoutParams);
+ }
+ } else if (isSecondaryOnly(primaryButton, secondaryButton)) {
+ LayoutParams secondaryLayoutParams =
+ (LayoutParams) secondaryButton.getLayoutParams();
+ if (secondaryLayoutParams != null) {
+ secondaryLayoutParams.width = footerBarWidth;
+ secondaryButton.setLayoutParams(secondaryLayoutParams);
+ }
+ } else {
+ LOG.atInfo("There are no button visible in the footer bar.");
+ }
+ } else {
+ // TODO: b/364121308 - Extract values as attributes.
+ // Set up down button styles.
+ int width =
+ context
+ .getResources()
+ .getDimensionPixelSize(R.dimen.suc_glif_expressive_down_button_width);
+ int height =
+ context
+ .getResources()
+ .getDimensionPixelSize(R.dimen.suc_glif_expressive_down_button_height);
+ float radius =
+ context
+ .getResources()
+ .getDimension(R.dimen.suc_glif_expressive_down_button_radius);
+ setSizeForButton(getPrimaryButtonView(), width, height);
+ setRadiusForButton(getPrimaryButtonView(), radius);
+
+ if (getPrimaryButton() != null && getSecondaryButton() == null) {
+ if (!isTwoPaneLayout()) {
+ buttonContainer.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
+ } else {
+ buttonContainer.setGravity(Gravity.NO_GRAVITY);
+ int containerWidth = buttonContainer.getWidth();
+ Button downButtonView = getPrimaryButtonView();
+ LayoutParams primaryLayoutParams = (LayoutParams) downButtonView.getLayoutParams();
+ int buttonWidth = primaryLayoutParams.width;
+ int halfContainerWidth = containerWidth / 2;
+ initialLeftMargin = primaryLayoutParams.leftMargin;
+ primaryLayoutParams.leftMargin =
+ (halfContainerWidth + (containerWidth / 2 - buttonWidth) / 2);
+ downButtonView.setLayoutParams(primaryLayoutParams);
+ }
+ }
+ }
+ buttonContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ };
+
+ buttonContainer.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
+ }
+
+ private boolean isTwoPaneLayout() {
+ return context.getResources().getBoolean(R.bool.sucTwoPaneLayoutStyle);
+ }
+
+ private boolean isBothButtons(Button primaryButton, Button secondaryButton) {
+ boolean isPrimaryVisible =
+ primaryButton != null && primaryButton.getVisibility() == View.VISIBLE;
+ boolean isSecondaryVisible =
+ secondaryButton != null && secondaryButton.getVisibility() == View.VISIBLE;
+ LOG.atDebug(
+ "isPrimaryVisible=" + isPrimaryVisible + ", isSecondaryVisible=" + isSecondaryVisible);
+ return isPrimaryVisible && isSecondaryVisible;
+ }
+
+ private boolean isPrimaryButtonOnly(Button primaryButton, Button secondaryButton) {
+ boolean isPrimaryOnly = primaryButton != null && secondaryButton == null;
+ boolean isPrimaryOnlyButSecondaryInvisible =
+ (primaryButton != null)
+ && (secondaryButton != null && secondaryButton.getVisibility() != View.VISIBLE);
+ LOG.atDebug(
+ "isPrimaryOnly="
+ + isPrimaryOnly
+ + ", isPrimaryOnlyButSecondaryInvisible="
+ + isPrimaryOnlyButSecondaryInvisible);
+ return isPrimaryOnly || isPrimaryOnlyButSecondaryInvisible;
+ }
+
+ private boolean isSecondaryOnly(Button primaryButton, Button secondaryButton) {
+ boolean isSecondaryOnly = secondaryButton != null && primaryButton == null;
+ boolean isSecondaryOnlyButPrimaryInvisible =
+ (secondaryButton != null)
+ && (primaryButton != null && primaryButton.getVisibility() != View.VISIBLE);
+ LOG.atDebug(
+ "isSecondaryOnly="
+ + isSecondaryOnly
+ + ", isSecondaryOnlyButPrimaryInvisible="
+ + isSecondaryOnlyButPrimaryInvisible);
+ return isSecondaryOnly || isSecondaryOnlyButPrimaryInvisible;
+ }
+
+ private void setSizeForButton(Button button, int width, int height) {
+ if (button != null) {
+ LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) button.getLayoutParams();
+ layoutParams.width = width;
+ layoutParams.height = height;
+ button.setLayoutParams(layoutParams);
+ }
+ }
+
+ private void setRadiusForButton(Button button, float radius) {
+ if (button != null) {
+ if (button instanceof MaterialButton) {
+ ((MaterialButton) button).setCornerRadius((int) radius);
+ } else {
+ GradientDrawable gradientDrawable = FooterButtonStyleUtils.getGradientDrawable(button);
+ if (gradientDrawable != null) {
+ gradientDrawable.setCornerRadius(radius);
+ }
+ }
+ }
+ }
+
/**
* Notifies that the footer button has been inInflated and add to the view hierarchy. Calling
* super is necessary while subclass implement it.
@@ -631,7 +927,9 @@
int overrideTheme = footerButton.getTheme();
// Set the default theme if theme is not set, or when running in setup flow.
- if (footerButton.getTheme() == 0 || applyPartnerResources) {
+ if (footerButton.getTheme() == 0
+ || applyPartnerResources
+ || PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
overrideTheme = defaultPartnerTheme;
}
// TODO: Make sure customize attributes in theme can be applied during setup flow.
@@ -640,9 +938,15 @@
if (applyPartnerResources) {
int color = PartnerConfigHelper.get(context).getColor(context, buttonBackgroundColorConfig);
if (color == Color.TRANSPARENT) {
- overrideTheme = R.style.SucPartnerCustomizationButton_Secondary;
+ overrideTheme =
+ PartnerConfigHelper.isGlifExpressiveEnabled(context)
+ ? R.style.SucGlifMaterialButton_Secondary
+ : R.style.SucPartnerCustomizationButton_Secondary;
} else {
- overrideTheme = R.style.SucPartnerCustomizationButton_Primary;
+ overrideTheme =
+ PartnerConfigHelper.isGlifExpressiveEnabled(context)
+ ? R.style.SucGlifMaterialButton_Primary
+ : R.style.SucPartnerCustomizationButton_Primary;
}
}
return overrideTheme;
@@ -710,10 +1014,11 @@
&& getSecondaryButtonView().getVisibility() == View.VISIBLE;
}
- private FooterActionButton inflateButton(
+ private IFooterActionButton inflateButton(
FooterButton footerButton, FooterButtonPartnerConfig footerButtonPartnerConfig) {
- FooterActionButton button =
+ IFooterActionButton buttonImpl =
createThemedButton(context, footerButtonPartnerConfig.getPartnerTheme());
+ Button button = (Button) buttonImpl;
button.setId(View.generateViewId());
// apply initial configuration into button view.
@@ -721,10 +1026,15 @@
button.setOnClickListener(footerButton);
button.setVisibility(footerButton.getVisibility());
button.setEnabled(footerButton.isEnabled());
- button.setFooterButton(footerButton);
-
+ if (buttonImpl instanceof MaterialFooterActionButton) {
+ ((MaterialFooterActionButton) buttonImpl).setFooterButton(footerButton);
+ } else if (button instanceof FooterActionButton) {
+ ((FooterActionButton) buttonImpl).setFooterButton(footerButton);
+ } else {
+ LOG.e("Set the footer button error!");
+ }
footerButton.setOnButtonEventListener(createButtonEventListener(button.getId()));
- return button;
+ return buttonImpl;
}
// TODO: Make sure customize attributes in theme can be applied during setup flow.
@@ -850,4 +1160,12 @@
public PersistableBundle getLoggingMetrics() {
return metrics.getMetrics();
}
+
+ private void updateTextColorForButton(Button button, boolean enable, int color) {
+ if (enable) {
+ FooterButtonStyleUtils.updateButtonTextEnabledColor(button, color);
+ } else {
+ FooterButtonStyleUtils.updateButtonTextDisabledColor(button, color);
+ }
+ }
}
diff --git a/main/java/com/google/android/setupcompat/template/FooterButton.java b/main/java/com/google/android/setupcompat/template/FooterButton.java
index 38b81c2..33bf265 100644
--- a/main/java/com/google/android/setupcompat/template/FooterButton.java
+++ b/main/java/com/google/android/setupcompat/template/FooterButton.java
@@ -80,6 +80,7 @@
* @param listener The listener for button.
* @param buttonType The type of button.
* @param theme The theme for button.
+ * @param visibility the visibility for button.
*/
private FooterButton(
CharSequence text,
@@ -87,13 +88,15 @@
@ButtonType int buttonType,
@StyleRes int theme,
Locale locale,
- int direction) {
+ int direction,
+ int visibility) {
this.text = text;
onClickListener = listener;
this.buttonType = buttonType;
this.theme = theme;
this.locale = locale;
this.direction = direction;
+ this.visibility = visibility;
}
/** Returns the text that this footer button is displaying. */
@@ -366,6 +369,7 @@
* .setTheme(R.style.SuwGlifButton_Primary)
* .setTextLocale(Locale.CANADA)
* .setLayoutDirection(View.LAYOUT_DIRECTION_LTR)
+ * .setVisibility(View.VISIBLE)
* .build();
* </pre>
*/
@@ -378,6 +382,8 @@
@ButtonType private int buttonType = ButtonType.OTHER;
private int theme = 0;
+ private int visibility = View.VISIBLE;
+
public Builder(@NonNull Context context) {
this.context = context;
}
@@ -424,8 +430,15 @@
return this;
}
+ /** Sets the {@code visibility} of FooterButton. */
+ public Builder setVisibility(int visibility) {
+ this.visibility = visibility;
+ return this;
+ }
+
public FooterButton build() {
- return new FooterButton(text, onClickListener, buttonType, theme, locale, direction);
+ return new FooterButton(
+ text, onClickListener, buttonType, theme, locale, direction, visibility);
}
}
}
diff --git a/main/java/com/google/android/setupcompat/template/FooterButtonStyleUtils.java b/main/java/com/google/android/setupcompat/template/FooterButtonStyleUtils.java
index fc56aad..3045002 100644
--- a/main/java/com/google/android/setupcompat/template/FooterButtonStyleUtils.java
+++ b/main/java/com/google/android/setupcompat/template/FooterButtonStyleUtils.java
@@ -291,12 +291,12 @@
}
float alpha =
PartnerConfigHelper.get(context).getFraction(context, buttonRippleColorAlphaConfig);
- updateButtonRippleColor(button, textDefaultColor, alpha);
+ updateButtonRippleColor(context, button, textDefaultColor, alpha);
}
}
private static void updateButtonRippleColor(
- Button button, @ColorInt int textColor, float rippleAlpha) {
+ Context context, Button button, @ColorInt int textColor, float rippleAlpha) {
// RippleDrawable is available after sdk 21. And because on lower sdk the RippleDrawable is
// unavailable. Since Stencil customization provider only works on Q+, there is no need to
// perform any customization for versions 21.
@@ -315,7 +315,13 @@
new ColorStateList(
new int[][] {pressedState, focusState, StateSet.NOTHING},
new int[] {argbColor, argbColor, Color.TRANSPARENT});
- rippleDrawable.setColor(colorStateList);
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)
+ && button instanceof MaterialFooterActionButton) {
+ MaterialFooterActionButton materialButton = (MaterialFooterActionButton) button;
+ materialButton.setRippleColor(colorStateList);
+ } else {
+ rippleDrawable.setColor(colorStateList);
+ }
}
}
@@ -388,9 +394,15 @@
Context context, Button button, PartnerConfig buttonRadiusConfig) {
if (Build.VERSION.SDK_INT >= VERSION_CODES.N) {
float radius = PartnerConfigHelper.get(context).getDimension(context, buttonRadiusConfig);
- GradientDrawable gradientDrawable = getGradientDrawable(button);
- if (gradientDrawable != null) {
- gradientDrawable.setCornerRadius(radius);
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context)
+ && button instanceof MaterialFooterActionButton) {
+ MaterialFooterActionButton materialButton = (MaterialFooterActionButton) button;
+ materialButton.setCornerRadius((int) radius);
+ } else {
+ GradientDrawable gradientDrawable = getGradientDrawable(button);
+ if (gradientDrawable != null) {
+ gradientDrawable.setCornerRadius(radius);
+ }
}
}
}
diff --git a/main/java/com/google/android/setupcompat/template/IFooterActionButton.java b/main/java/com/google/android/setupcompat/template/IFooterActionButton.java
new file mode 100644
index 0000000..59f7bed
--- /dev/null
+++ b/main/java/com/google/android/setupcompat/template/IFooterActionButton.java
@@ -0,0 +1,42 @@
+/*
+ * 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.google.android.setupcompat.template;
+
+import android.view.MotionEvent;
+
+/**
+ * Interface for footer action buttons in Setup library to indicate Android Button or Material
+ * button classes.
+ *
+ * <p>This interface defines common methods for footer action buttons, regardless of their specific
+ * implementation. It provides a way to interact with footer buttons and determine their style
+ * attributes.
+ */
+public interface IFooterActionButton {
+
+ /**
+ * Handles touch events for the footer action button, ensuring accessibility and proper behavior
+ * even when the button is disabled.
+ *
+ * @param event The MotionEvent object representing the touch event.
+ * @return true if the event was consumed by the button, false otherwise.
+ */
+ boolean onTouchEvent(MotionEvent event);
+
+ /** Returns true when the footer button is primary button style. */
+ boolean isPrimaryButtonStyle();
+}
diff --git a/main/java/com/google/android/setupcompat/template/MaterialFooterActionButton.java b/main/java/com/google/android/setupcompat/template/MaterialFooterActionButton.java
new file mode 100644
index 0000000..da86746
--- /dev/null
+++ b/main/java/com/google/android/setupcompat/template/MaterialFooterActionButton.java
@@ -0,0 +1,75 @@
+/*
+ * 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.google.android.setupcompat.template;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import androidx.annotation.VisibleForTesting;
+import com.google.android.material.button.MaterialButton;
+
+/** Material Button that can react to touch when disabled. */
+public class MaterialFooterActionButton extends MaterialButton implements IFooterActionButton {
+ @VisibleForTesting FooterButton footerButton;
+ private boolean isPrimaryButtonStyle = false;
+
+ public MaterialFooterActionButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MaterialFooterActionButton(Context context, AttributeSet attrs, int value) {
+ super(context, attrs, value);
+ }
+
+ void setFooterButton(FooterButton footerButton) {
+ this.footerButton = footerButton;
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (footerButton != null
+ && !footerButton.isEnabled()
+ && footerButton.getVisibility() == View.VISIBLE) {
+ // getOnClickListenerWhenDisabled is responsible for handling accessibility correctly,
+ // calling performClick if necessary.
+ OnClickListener listener = footerButton.getOnClickListenerWhenDisabled();
+ if (listener != null) {
+ listener.onClick(this);
+ }
+ }
+ }
+ return super.onTouchEvent(event);
+ }
+
+ /**
+ * Sets this footer button is primary button style.
+ *
+ * @param isPrimaryButtonStyle True if this button is primary button style.
+ */
+ void setPrimaryButtonStyle(boolean isPrimaryButtonStyle) {
+ this.isPrimaryButtonStyle = isPrimaryButtonStyle;
+ }
+
+ @Override
+ public boolean isPrimaryButtonStyle() {
+ return isPrimaryButtonStyle;
+ }
+}
diff --git a/main/java/com/google/android/setupcompat/util/KeyboardHelper.java b/main/java/com/google/android/setupcompat/util/KeyboardHelper.java
new file mode 100644
index 0000000..4989f5d
--- /dev/null
+++ b/main/java/com/google/android/setupcompat/util/KeyboardHelper.java
@@ -0,0 +1,31 @@
+/*
+ * 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.google.android.setupcompat.util;
+
+import android.content.Context;
+import androidx.annotation.NonNull;
+import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
+
+/** Helper class to handle keyboard related operations. */
+public final class KeyboardHelper {
+
+ /** Returns whether the keyboard focus changed is enabled. */
+ public static boolean isKeyboardFocusEnhancementEnabled(@NonNull Context context) {
+ return PartnerConfigHelper.isKeyboardFocusEnhancementEnabled(context);
+ }
+
+ private KeyboardHelper() {}
+}
diff --git a/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java b/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java
index 9c73ea9..2b0aedf 100644
--- a/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java
+++ b/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java
@@ -22,7 +22,6 @@
import android.os.Build;
import android.provider.Settings;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
import com.google.errorprone.annotations.InlineMe;
import java.util.Arrays;
@@ -52,10 +51,12 @@
/** 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";
+ public static final String ACTION_NEXT = "com.android.wizard.NEXT";
public static final String EXTRA_WIZARD_BUNDLE = "wizardBundle";
- private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
+
+ /** Extra used for including the resultcode of a wizardmanager action. */
+ public static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
/** Extra for notifying an Activity that it is inside the first SetupWizard flow or not. */
public static final String EXTRA_IS_FIRST_RUN = "firstRun";