From 5c8cae4cfc2b79b36d0bbc88c65feb150c0130ad Mon Sep 17 00:00:00 2001 From: Hunter Knepshield Date: Thu, 9 May 2019 17:36:57 -0700 Subject: Remove compileSdkVersion as SDK finalization is happening. Test: compile EuiccGoogle Bug: 132373032 Change-Id: I4b02e0db2bc8358fe14deb8612b195b7b16f22d6 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f4c7459..7398305 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 'android-Q' + // Not specifying compileSdkVersion here so clients can specify it; must be at least Q defaultConfig { minSdkVersion 14 -- cgit v1.2.3 From 24bb1e2b3fd9dec35953ae7324586f95dcef0d95 Mon Sep 17 00:00:00 2001 From: Setup Wizard Team Date: Fri, 8 Nov 2019 15:22:51 +0800 Subject: Import updated Android SetupCompat Library 279249746 Copied from google3/third_party/java_src/android_libs/setupcompat Test: mm Included changes: - 279249746 Trims the metric value less than CustomEvent.MAX_STRING_L... - 258686629 Fix activity test fail. - 258478750 Log onResume time for sort the flow of SUW - 257138376 Fix fail to publish metrics log - 256076624 Refactor the screenName of Metrics - 254929273 Fix PartnerConfigHelper#getResourceEntryFromKey throw NPE - 253952206 Provide the fallback values from setup wizard when the sc... - 252376490 Add partner config for body content text - 251553482 qt-dev is freeze, code will sync to qt-r1-dev PiperOrigin-RevId: 279249746 Change-Id: Id7af2272ded4550bea5246abe75026a68cb51b19 --- .../setupcompat/PartnerCustomizationLayout.java | 4 +- .../setupcompat/internal/LifecycleFragment.java | 15 ++- .../internal/SetupCompatServiceProvider.java | 2 +- .../android/setupcompat/logging/CustomEvent.java | 14 +++ .../android/setupcompat/logging/MetricKey.java | 35 ++++++- .../android/setupcompat/template/FooterButton.java | 4 +- .../setupcompat/partnerconfig/PartnerConfig.java | 17 +++- .../partnerconfig/PartnerConfigHelper.java | 105 +++++++++++---------- .../partnerconfig/PartnerConfigKey.java | 20 ++++ .../setupcompat/partnerconfig/ResourceEntry.java | 73 +++++++++++++- 10 files changed, 222 insertions(+), 67 deletions(-) diff --git a/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java b/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java index 360a0a0..fac4b39 100644 --- a/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java +++ b/main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java @@ -212,9 +212,7 @@ public class PartnerCustomizationLayout extends TemplateLayout { SetupMetricsLogger.logCustomEvent( getContext(), - CustomEvent.create( - MetricKey.get("SetupCompatMetrics", activity.getClass().getSimpleName()), - persistableBundle)); + CustomEvent.create(MetricKey.get("SetupCompatMetrics", activity), persistableBundle)); } } diff --git a/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java b/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java index 269dd6d..d882c9d 100644 --- a/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java +++ b/main/java/com/google/android/setupcompat/internal/LifecycleFragment.java @@ -24,7 +24,9 @@ import android.app.FragmentManager; import android.content.Context; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import android.os.PersistableBundle; import android.util.Log; +import com.google.android.setupcompat.logging.CustomEvent; import com.google.android.setupcompat.logging.MetricKey; import com.google.android.setupcompat.logging.SetupMetricsLogger; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -87,7 +89,7 @@ public class LifecycleFragment extends Fragment { @Override public void onAttach(Context context) { super.onAttach(context); - metricKey = MetricKey.get("ScreenDuration", getActivity().getClass().getSimpleName()); + metricKey = MetricKey.get("ScreenDuration", getActivity()); } @Override @@ -100,6 +102,7 @@ public class LifecycleFragment extends Fragment { public void onResume() { super.onResume(); startInNanos = ClockProvider.timeInNanos(); + logScreenResume(); } @Override @@ -107,4 +110,14 @@ public class LifecycleFragment extends Fragment { super.onPause(); durationInNanos += (ClockProvider.timeInNanos() - startInNanos); } + + private void logScreenResume() { + if (VERSION.SDK_INT >= VERSION_CODES.Q) { + PersistableBundle bundle = new PersistableBundle(); + bundle.putLong("onScreenResume", System.nanoTime()); + SetupMetricsLogger.logCustomEvent( + getActivity(), + CustomEvent.create(MetricKey.get("ScreenActivity", getActivity()), bundle)); + } + } } diff --git a/main/java/com/google/android/setupcompat/internal/SetupCompatServiceProvider.java b/main/java/com/google/android/setupcompat/internal/SetupCompatServiceProvider.java index 66503a7..2043a81 100644 --- a/main/java/com/google/android/setupcompat/internal/SetupCompatServiceProvider.java +++ b/main/java/com/google/android/setupcompat/internal/SetupCompatServiceProvider.java @@ -169,7 +169,7 @@ public class SetupCompatServiceProvider { return serviceContext.state; } - private ServiceContext getCurrentServiceState() { + private synchronized ServiceContext getCurrentServiceState() { return serviceContext; } diff --git a/main/java/com/google/android/setupcompat/logging/CustomEvent.java b/main/java/com/google/android/setupcompat/logging/CustomEvent.java index 88ac05e..38c32fa 100644 --- a/main/java/com/google/android/setupcompat/logging/CustomEvent.java +++ b/main/java/com/google/android/setupcompat/logging/CustomEvent.java @@ -25,6 +25,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.google.android.setupcompat.internal.ClockProvider; import com.google.android.setupcompat.internal.PersistableBundles; @@ -201,6 +202,19 @@ public final class CustomEvent implements Parcelable { } } + /** + * Trims the string longer than {@code MAX_STR_LENGTH} character, only keep the first {@code + * MAX_STR_LENGTH} - 1 characters and attached … in the end. + */ + @NonNull + public static String trimsStringOverMaxLength(@NonNull String str) { + if (str.length() <= MAX_STR_LENGTH) { + return str; + } else { + return String.format("%s…", str.substring(0, MAX_STR_LENGTH - 1)); + } + } + @VisibleForTesting static final int MAX_STR_LENGTH = 50; @VisibleForTesting static final int MIN_BUNDLE_KEY_LENGTH = 3; } diff --git a/main/java/com/google/android/setupcompat/logging/MetricKey.java b/main/java/com/google/android/setupcompat/logging/MetricKey.java index 125dee9..cdfb7d7 100644 --- a/main/java/com/google/android/setupcompat/logging/MetricKey.java +++ b/main/java/com/google/android/setupcompat/logging/MetricKey.java @@ -18,6 +18,7 @@ package com.google.android.setupcompat.logging; import static com.google.android.setupcompat.internal.Validations.assertLengthInRange; +import android.app.Activity; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -37,6 +38,21 @@ public final class MetricKey implements Parcelable { private static final String METRIC_KEY_BUNDLE_VERSION = "MetricKey_version"; private static final int VERSION = 1; + /** + * Creates a new instance of MetricKey. + * + * @param name metric name to identify what we log + * @param activity activity of metric screen, uses to generate screenName + */ + public static MetricKey get(@NonNull String name, @NonNull Activity activity) { + String screenName = activity.getComponentName().getClassName(); + assertLengthInRange(name, "MetricKey.name", MIN_METRIC_KEY_LENGTH, MAX_METRIC_KEY_LENGTH); + Preconditions.checkArgument( + METRIC_KEY_PATTERN.matcher(name).matches(), + "Invalid MetricKey, only alpha numeric characters are allowed."); + return new MetricKey(name, screenName); + } + /** * Creates a new instance of MetricKey. * @@ -50,15 +66,21 @@ public final class MetricKey implements Parcelable { * */ public static MetricKey get(@NonNull String name, @NonNull String screenName) { + // We only checked the length of customized screen name, by the reason if the screenName match + // to the class name skip check it + if (!SCREEN_COMPONENTNAME_PATTERN.matcher(screenName).matches()) { + assertLengthInRange( + screenName, "MetricKey.screenName", MIN_SCREEN_NAME_LENGTH, MAX_SCREEN_NAME_LENGTH); + Preconditions.checkArgument( + SCREEN_NAME_PATTERN.matcher(screenName).matches(), + "Invalid ScreenName, only alpha numeric characters are allowed."); + } + assertLengthInRange(name, "MetricKey.name", MIN_METRIC_KEY_LENGTH, MAX_METRIC_KEY_LENGTH); - assertLengthInRange( - screenName, "MetricKey.screenName", MIN_SCREEN_NAME_LENGTH, MAX_SCREEN_NAME_LENGTH); Preconditions.checkArgument( METRIC_KEY_PATTERN.matcher(name).matches(), "Invalid MetricKey, only alpha numeric characters are allowed."); - Preconditions.checkArgument( - METRIC_KEY_PATTERN.matcher(screenName).matches(), - "Invalid MetricKey, only alpha numeric characters are allowed."); + return new MetricKey(name, screenName); } @@ -145,4 +167,7 @@ public final class MetricKey implements Parcelable { private static final int MAX_SCREEN_NAME_LENGTH = 50; private static final int MAX_METRIC_KEY_LENGTH = 30; private static final Pattern METRIC_KEY_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_]+"); + private static final Pattern SCREEN_COMPONENTNAME_PATTERN = + Pattern.compile("^([a-z]+[.])+[A-Z][a-zA-Z0-9]+"); + private static final Pattern SCREEN_NAME_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_]+"); } diff --git a/main/java/com/google/android/setupcompat/template/FooterButton.java b/main/java/com/google/android/setupcompat/template/FooterButton.java index a4d2c87..2fa8c7c 100644 --- a/main/java/com/google/android/setupcompat/template/FooterButton.java +++ b/main/java/com/google/android/setupcompat/template/FooterButton.java @@ -32,6 +32,7 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import com.google.android.setupcompat.R; +import com.google.android.setupcompat.logging.CustomEvent; import java.lang.annotation.Retention; /** @@ -285,7 +286,8 @@ public final class FooterButton implements OnClickListener { @TargetApi(VERSION_CODES.Q) public PersistableBundle getMetrics(String buttonName) { PersistableBundle bundle = new PersistableBundle(); - bundle.putString(buttonName + KEY_BUTTON_TEXT, getText().toString()); + bundle.putString( + buttonName + KEY_BUTTON_TEXT, CustomEvent.trimsStringOverMaxLength(getText().toString())); bundle.putString(buttonName + KEY_BUTTON_TYPE, getButtonTypeName()); bundle.putInt(buttonName + KEY_BUTTON_ON_CLICK_COUNT, clickCount); return bundle; diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java index 73d66e6..cd479ee 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java @@ -139,7 +139,22 @@ public enum PartnerConfig { PartnerConfigKey.KEY_DESCRIPTION_LINK_TEXT_COLOR, ResourceType.COLOR), // Font family of the description - CONFIG_DESCRIPTION_FONT_FAMILY(PartnerConfigKey.KEY_DESCRIPTION_FONT_FAMILY, ResourceType.STRING); + CONFIG_DESCRIPTION_FONT_FAMILY(PartnerConfigKey.KEY_DESCRIPTION_FONT_FAMILY, ResourceType.STRING), + + // Text size of the body content text + CONFIG_CONTENT_TEXT_SIZE(PartnerConfigKey.KEY_CONTENT_TEXT_SIZE, ResourceType.DIMENSION), + + // Text color of the body content text + CONFIG_CONTENT_TEXT_COLOR(PartnerConfigKey.KEY_CONTENT_TEXT_COLOR, ResourceType.COLOR), + + // Link text color of the body content text + CONFIG_CONTENT_LINK_TEXT_COLOR(PartnerConfigKey.KEY_CONTENT_LINK_TEXT_COLOR, ResourceType.COLOR), + + // Font family of the body content text + CONFIG_CONTENT_FONT_FAMILY(PartnerConfigKey.KEY_CONTENT_FONT_FAMILY, ResourceType.STRING), + + // Gravity of the body content text + CONFIG_CONTENT_LAYOUT_GRAVITY(PartnerConfigKey.KEY_CONTENT_LAYOUT_GRAVITY, ResourceType.STRING); public enum ResourceType { BOOL, diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java index eac403f..7205bbe 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java @@ -18,7 +18,6 @@ package com.google.android.setupcompat.partnerconfig; import android.content.ContentResolver; import android.content.Context; -import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.graphics.drawable.Drawable; @@ -45,6 +44,9 @@ public class PartnerConfigHelper { public static final String SUW_AUTHORITY = "com.google.android.setupwizard.partner"; @VisibleForTesting public static final String SUW_GET_PARTNER_CONFIG_METHOD = "getOverlayConfig"; + + @VisibleForTesting public static final String KEY_FALLBACK_CONFIG = "fallbackConfig"; + private static PartnerConfigHelper instance = null; @VisibleForTesting Bundle resultBundle = null; @@ -92,16 +94,18 @@ public class PartnerConfigHelper { int result = 0; try { - String resourceName = resourceConfig.getResourceName(); - ResourceEntry resourceEntry = getResourceEntryFromKey(resourceName); - Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + ResourceEntry resourceEntry = + getResourceEntryFromKey(context, resourceConfig.getResourceName()); + Resources resource = resourceEntry.getResources(); + int resId = resourceEntry.getResourceId(); + if (Build.VERSION.SDK_INT >= VERSION_CODES.M) { - result = resource.getColor(resourceEntry.getResourceId(), null); + result = resource.getColor(resId, null); } else { - result = resource.getColor(resourceEntry.getResourceId()); + result = resource.getColor(resId); } partnerResourceCache.put(resourceConfig, result); - } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + } catch (NullPointerException exception) { // fall through } return result; @@ -127,25 +131,25 @@ public class PartnerConfigHelper { Drawable result = null; try { - ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); - Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + ResourceEntry resourceEntry = + getResourceEntryFromKey(context, resourceConfig.getResourceName()); + Resources resource = resourceEntry.getResources(); + int resId = resourceEntry.getResourceId(); // for @null TypedValue outValue = new TypedValue(); - resource.getValue(resourceEntry.getResourceId(), outValue, true); + resource.getValue(resId, outValue, true); if (outValue.type == TypedValue.TYPE_REFERENCE && outValue.data == 0) { return result; } if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - result = resource.getDrawable(resourceEntry.getResourceId(), null); + result = resource.getDrawable(resId, null); } else { - result = resource.getDrawable(resourceEntry.getResourceId()); + result = resource.getDrawable(resId); } partnerResourceCache.put(resourceConfig, result); - } catch (PackageManager.NameNotFoundException - | NullPointerException - | NotFoundException exception) { + } catch (NullPointerException | NotFoundException exception) { // fall through } return result; @@ -171,11 +175,14 @@ public class PartnerConfigHelper { String result = null; try { - ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); - Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); - result = resource.getString(resourceEntry.getResourceId()); + ResourceEntry resourceEntry = + getResourceEntryFromKey(context, resourceConfig.getResourceName()); + Resources resource = resourceEntry.getResources(); + int resId = resourceEntry.getResourceId(); + + result = resource.getString(resId); partnerResourceCache.put(resourceConfig, result); - } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + } catch (NullPointerException exception) { // fall through } return result; @@ -202,11 +209,14 @@ public class PartnerConfigHelper { boolean result = defaultValue; try { - ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); - Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); - result = resource.getBoolean(resourceEntry.getResourceId()); + ResourceEntry resourceEntry = + getResourceEntryFromKey(context, resourceConfig.getResourceName()); + Resources resource = resourceEntry.getResources(); + int resId = resourceEntry.getResourceId(); + + result = resource.getBoolean(resId); partnerResourceCache.put(resourceConfig, result); - } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + } catch (NullPointerException exception) { // fall through } return result; @@ -244,17 +254,18 @@ public class PartnerConfigHelper { float result = defaultValue; try { - ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); - Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); - result = resource.getDimension(resourceEntry.getResourceId()); - TypedValue value = - getTypedValueFromResource( - resource, resourceEntry.getResourceId(), TypedValue.TYPE_DIMENSION); + ResourceEntry resourceEntry = + getResourceEntryFromKey(context, resourceConfig.getResourceName()); + Resources resource = resourceEntry.getResources(); + int resId = resourceEntry.getResourceId(); + + result = resource.getDimension(resId); + TypedValue value = getTypedValueFromResource(resource, resId, TypedValue.TYPE_DIMENSION); partnerResourceCache.put(resourceConfig, value); result = getDimensionFromTypedValue( context, (TypedValue) partnerResourceCache.get(resourceConfig)); - } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + } catch (NullPointerException exception) { // fall through } return result; @@ -291,11 +302,14 @@ public class PartnerConfigHelper { float result = defaultValue; try { - ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); - Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); - result = resource.getFraction(resourceEntry.getResourceId(), 1, 1); + ResourceEntry resourceEntry = + getResourceEntryFromKey(context, resourceConfig.getResourceName()); + Resources resource = resourceEntry.getResources(); + int resId = resourceEntry.getResourceId(); + + result = resource.getFraction(resId, 1, 1); partnerResourceCache.put(resourceConfig, result); - } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + } catch (NullPointerException exception) { // fall through } return result; @@ -322,23 +336,14 @@ public class PartnerConfigHelper { } } - private Resources getResourcesByPackageName(Context context, String packageName) - throws PackageManager.NameNotFoundException { - PackageManager manager = context.getPackageManager(); - if (Build.VERSION.SDK_INT >= VERSION_CODES.N) { - return manager.getResourcesForApplication( - manager.getApplicationInfo(packageName, PackageManager.MATCH_DISABLED_COMPONENTS)); - } else { - return manager.getResourcesForApplication( - manager.getApplicationInfo(packageName, PackageManager.GET_DISABLED_COMPONENTS)); - } - } - - private ResourceEntry getResourceEntryFromKey(String resourceName) { - if (resultBundle == null) { - return null; + @Nullable + private ResourceEntry getResourceEntryFromKey(Context context, String resourceName) { + Bundle resourceEntryBundle = resultBundle.getBundle(resourceName); + Bundle fallbackBundle = resultBundle.getBundle(KEY_FALLBACK_CONFIG); + if (fallbackBundle != null) { + resourceEntryBundle.putBundle(KEY_FALLBACK_CONFIG, fallbackBundle.getBundle(resourceName)); } - return ResourceEntry.fromBundle(resultBundle.getBundle(resourceName)); + return ResourceEntry.fromBundle(context, resourceEntryBundle); } @VisibleForTesting diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java index 87f51ba..6701fdd 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java @@ -57,6 +57,11 @@ import java.lang.annotation.RetentionPolicy; PartnerConfigKey.KEY_DESCRIPTION_TEXT_COLOR, PartnerConfigKey.KEY_DESCRIPTION_LINK_TEXT_COLOR, PartnerConfigKey.KEY_DESCRIPTION_FONT_FAMILY, + PartnerConfigKey.KEY_CONTENT_TEXT_SIZE, + PartnerConfigKey.KEY_CONTENT_TEXT_COLOR, + PartnerConfigKey.KEY_CONTENT_LINK_TEXT_COLOR, + PartnerConfigKey.KEY_CONTENT_FONT_FAMILY, + PartnerConfigKey.KEY_CONTENT_LAYOUT_GRAVITY, }) // TODO: can be removed and always reference PartnerConfig.getResourceName()? @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) @@ -162,4 +167,19 @@ public @interface PartnerConfigKey { // Font family of the description String KEY_DESCRIPTION_FONT_FAMILY = "setup_design_description_font_family"; + + // Text size of the body content text + String KEY_CONTENT_TEXT_SIZE = "setup_design_content_text_size"; + + // Text color of the body content text + String KEY_CONTENT_TEXT_COLOR = "setup_design_content_text_color"; + + // Link text color of the body content text + String KEY_CONTENT_LINK_TEXT_COLOR = "setup_design_content_link_text_color"; + + // Font family of the body content text + String KEY_CONTENT_FONT_FAMILY = "setup_design_content_font_family"; + + // Gravity of the body content text + String KEY_CONTENT_LAYOUT_GRAVITY = "setup_design_content_layout_gravity"; } diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java index 2794f22..8f7c9d8 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java @@ -16,15 +16,29 @@ package com.google.android.setupcompat.partnerconfig; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; +import android.os.Build; +import android.os.Build.VERSION_CODES; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import android.util.Log; /** * A potentially cross-package resource entry, which can then be retrieved using {@link - * PackageManager#getApplicationForResources}. This class can also be sent across to other packages + * PackageManager#getResourcesForApplication}. This class can also be sent across to other packages * on IPC via the Bundle representation. */ public final class ResourceEntry { + + private static final String TAG = ResourceEntry.class.getSimpleName(); + + @VisibleForTesting static final String KEY_FALLBACK_CONFIG = "fallbackConfig"; + @VisibleForTesting static final String KEY_PACKAGE_NAME = "packageName"; @VisibleForTesting static final String KEY_RESOURCE_NAME = "resourceName"; @VisibleForTesting static final String KEY_RESOURCE_ID = "resourceId"; @@ -34,11 +48,22 @@ public final class ResourceEntry { private final int resourceId; /** - * Creates a {@code ResourceEntry} object from a provided bundle. + * The {@link Resources} for accessing a specific package's resources. This is {@code null} only + * if the deprecated constructor {@link #ResourceEntry(String, String, int)} is used. + */ + @Nullable private final Resources resources; + + /** + * Creates a {@code ResourceEntry} object from a provided bundle or the fallback resource if + * partner resource not found and the {@code fallbackConfig} key exists in provided bundle. + * Returns {@code null} if fallback package is not found or the {@code bundle} doesn't contain + * packageName, resourceName, or resourceId. * + * @param context the context need to retrieve the {@link Resources} * @param bundle the source bundle needs to have all the information for a {@code ResourceEntry} */ - public static ResourceEntry fromBundle(Bundle bundle) { + @Nullable + public static ResourceEntry fromBundle(@NonNull Context context, Bundle bundle) { String packageName; String resourceName; int resourceId; @@ -50,13 +75,31 @@ public final class ResourceEntry { packageName = bundle.getString(KEY_PACKAGE_NAME); resourceName = bundle.getString(KEY_RESOURCE_NAME); resourceId = bundle.getInt(KEY_RESOURCE_ID); - return new ResourceEntry(packageName, resourceName, resourceId); + try { + return new ResourceEntry( + packageName, resourceName, resourceId, getResourcesByPackageName(context, packageName)); + } catch (NameNotFoundException e) { + Bundle fallbackBundle = bundle.getBundle(KEY_FALLBACK_CONFIG); + if (fallbackBundle != null) { + Log.w(TAG, packageName + " not found, " + resourceName + " fallback to default value"); + return fromBundle(context, fallbackBundle); + } + } + return null; } + /** @deprecated Use {@link #ResourceEntry(String, String, int, Resources)} instead. */ + @Deprecated public ResourceEntry(String packageName, String resourceName, int resourceId) { + this(packageName, resourceName, resourceId, /* resources= */ null); + } + + public ResourceEntry( + String packageName, String resourceName, int resourceId, @Nullable Resources resources) { this.packageName = packageName; this.resourceName = resourceName; this.resourceId = resourceId; + this.resources = resources; } public String getPackageName() { @@ -71,10 +114,18 @@ public final class ResourceEntry { return this.resourceId; } + /** + * Returns a {@link Resources} for accessing specific package's resources. It will be {@code null} + * when the {@link #ResourceEntry(String, String, int)} is used). + */ + public Resources getResources() { + return resources; + } + /** * Returns a bundle representation of this resource entry, which can then be sent over IPC. * - * @see #fromBundle(Bundle) + * @see #fromBundle(Context, Bundle) */ public Bundle toBundle() { Bundle result = new Bundle(); @@ -83,4 +134,16 @@ public final class ResourceEntry { result.putInt(KEY_RESOURCE_ID, resourceId); return result; } + + private static Resources getResourcesByPackageName(Context context, String packageName) + throws NameNotFoundException { + PackageManager manager = context.getPackageManager(); + if (Build.VERSION.SDK_INT >= VERSION_CODES.N) { + return manager.getResourcesForApplication( + manager.getApplicationInfo(packageName, PackageManager.MATCH_DISABLED_COMPONENTS)); + } else { + return manager.getResourcesForApplication( + manager.getApplicationInfo(packageName, PackageManager.GET_DISABLED_COMPONENTS)); + } + } } -- cgit v1.2.3 From aa1a894e84ddde71992d56f9d9491e6b21e8768d Mon Sep 17 00:00:00 2001 From: Setup Wizard Team Date: Wed, 29 Apr 2020 14:48:08 +0800 Subject: Import updated Android SetupCompat Library 308970672 Copied from google3/third_party/java_src/android_libs/setupcompat Test: mm Bug: 155846468 Included changes: - 308970672 Add description field for illustration_loading_screen lay... - 308229658 Handle SecurityException when querying SUW provider for c... - 306566965 New progress illustration layout and related partner conf... - 300675799 [WSR] Support attributes ifFlow and flow in wizard manager - 293781880 [WSR] Check the attribute wizard:ifLifecycle in wizard ma... - 289975918 Add private constructor PiperOrigin-RevId: 308970672 Change-Id: I91e66d94bd43fe668b5ff56d6fdcc66f7b3f7857 --- .../android/setupcompat/util/ResultCodes.java | 4 ++ .../android/setupcompat/util/SystemBarHelper.java | 2 + .../setupcompat/util/WizardManagerHelper.java | 4 +- .../setupcompat/partnerconfig/PartnerConfig.java | 29 +++++++++++++- .../partnerconfig/PartnerConfigHelper.java | 46 +++++++++++++++++++++- .../partnerconfig/PartnerConfigKey.java | 24 +++++++++++ 6 files changed, 105 insertions(+), 4 deletions(-) diff --git a/main/java/com/google/android/setupcompat/util/ResultCodes.java b/main/java/com/google/android/setupcompat/util/ResultCodes.java index 3934b21..5fed731 100644 --- a/main/java/com/google/android/setupcompat/util/ResultCodes.java +++ b/main/java/com/google/android/setupcompat/util/ResultCodes.java @@ -24,6 +24,10 @@ public final class ResultCodes { public static final int RESULT_SKIP = RESULT_FIRST_USER; public static final int RESULT_RETRY = RESULT_FIRST_USER + 1; public static final int RESULT_ACTIVITY_NOT_FOUND = RESULT_FIRST_USER + 2; + public static final int RESULT_LIFECYCLE_NOT_MATCHED = RESULT_FIRST_USER + 3; + public static final int RESULT_FLOW_NOT_MATCHED = RESULT_FIRST_USER + 4; public static final int RESULT_FIRST_SETUP_USER = RESULT_FIRST_USER + 100; + + private ResultCodes() {} } diff --git a/main/java/com/google/android/setupcompat/util/SystemBarHelper.java b/main/java/com/google/android/setupcompat/util/SystemBarHelper.java index f336617..75e5dd3 100644 --- a/main/java/com/google/android/setupcompat/util/SystemBarHelper.java +++ b/main/java/com/google/android/setupcompat/util/SystemBarHelper.java @@ -347,4 +347,6 @@ public final class SystemBarHelper { void onDecorViewInstalled(View decorView); } + + private SystemBarHelper() {} } diff --git a/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java b/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java index 36b7d38..bfe1dbb 100644 --- a/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java +++ b/main/java/com/google/android/setupcompat/util/WizardManagerHelper.java @@ -32,7 +32,7 @@ import java.util.Arrays; * shown inside the setup flow. This includes things like parsing extras passed by Wizard Manager, * and invoking Wizard Manager to start the next action. */ -public class WizardManagerHelper { +public final class WizardManagerHelper { private static final String ACTION_NEXT = "com.android.wizard.NEXT"; @@ -216,4 +216,6 @@ public class WizardManagerHelper { || isDeferredSetupWizard(originalIntent); } } + + private WizardManagerHelper() {} } diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java index cd479ee..2844e03 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java @@ -154,15 +154,40 @@ public enum PartnerConfig { CONFIG_CONTENT_FONT_FAMILY(PartnerConfigKey.KEY_CONTENT_FONT_FAMILY, ResourceType.STRING), // Gravity of the body content text - CONFIG_CONTENT_LAYOUT_GRAVITY(PartnerConfigKey.KEY_CONTENT_LAYOUT_GRAVITY, ResourceType.STRING); + CONFIG_CONTENT_LAYOUT_GRAVITY(PartnerConfigKey.KEY_CONTENT_LAYOUT_GRAVITY, ResourceType.STRING), + + // The animation of loading screen used in those activities which is non of below type. + CONFIG_PROGRESS_ILLUSTRATION_DEFAULT( + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_DEFAULT, ResourceType.ILLUSTRATION), + + // The animation of loading screen used in those activity which is processing account info or + // related functions. + // For example:com.google.android.setupwizard.LOAD_ADD_ACCOUNT_INTENT + CONFIG_PROGRESS_ILLUSTRATION_ACCOUNT( + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_ACCOUNT, ResourceType.ILLUSTRATION), + + // The animation of loading screen used in those activity which is processing data connection. + // For example:com.android.setupwizard.CAPTIVE_PORTAL + CONFIG_PROGRESS_ILLUSTRATION_CONNECTION( + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_CONNECTION, ResourceType.ILLUSTRATION), + + // The animation of loading screen used in those activities which is updating device. + // For example:com.google.android.setupwizard.COMPAT_EARLY_UPDATE + CONFIG_PROGRESS_ILLUSTRATION_UPDATE( + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_UPDATE, ResourceType.ILLUSTRATION), + + CONFIG_PROGRESS_ILLUSTRATION_DISPLAY_MINIMUM_MS( + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_DISPLAY_MINIMUM_MS, ResourceType.INTEGER); public enum ResourceType { + INTEGER, BOOL, COLOR, DRAWABLE, STRING, DIMENSION, - FRACTION; + FRACTION, + ILLUSTRATION; } private final String resourceName; diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java index 7205bbe..7b9f65b 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java @@ -315,6 +315,50 @@ public class PartnerConfigHelper { return result; } + /** + * Returns the {@link ResourceEntry} of given {@code resourceConfig}, or {@code null} if the given + * {@code resourceConfig} is not found. If the {@link ResourceType} of the given {@code + * resourceConfig} is not illustration, IllegalArgumentException will be thrown. + * + * @param context The context of client activity + * @param resourceConfig The {@link PartnerConfig} of target resource + */ + @Nullable + public ResourceEntry getIllustrationResourceEntry( + @NonNull Context context, PartnerConfig resourceConfig) { + if (resourceConfig.getResourceType() != ResourceType.ILLUSTRATION) { + throw new IllegalArgumentException("Not a illustration resource"); + } + + if (partnerResourceCache.containsKey(resourceConfig)) { + return (ResourceEntry) partnerResourceCache.get(resourceConfig); + } + + try { + ResourceEntry resourceEntry = + getResourceEntryFromKey(context, resourceConfig.getResourceName()); + + Resources resource = resourceEntry.getResources(); + int resId = resourceEntry.getResourceId(); + + // TODO: The illustration resource entry validation should validate is it a video + // resource or not? + // for @null + TypedValue outValue = new TypedValue(); + resource.getValue(resId, outValue, true); + if (outValue.type == TypedValue.TYPE_REFERENCE && outValue.data == 0) { + return null; + } + + partnerResourceCache.put(resourceConfig, resourceEntry); + return resourceEntry; + } catch (NullPointerException exception) { + // fall through + } + + return null; + } + private void getPartnerConfigBundle(Context context) { if (resultBundle == null || resultBundle.isEmpty()) { try { @@ -330,7 +374,7 @@ public class PartnerConfigHelper { .call( contentUri, SUW_GET_PARTNER_CONFIG_METHOD, /* arg= */ null, /* extras= */ null); partnerResourceCache.clear(); - } catch (IllegalArgumentException exception) { + } catch (IllegalArgumentException | SecurityException exception) { Log.w(TAG, "Fail to get config from suw provider"); } } diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java index 6701fdd..49e96b2 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java @@ -62,6 +62,11 @@ import java.lang.annotation.RetentionPolicy; PartnerConfigKey.KEY_CONTENT_LINK_TEXT_COLOR, PartnerConfigKey.KEY_CONTENT_FONT_FAMILY, PartnerConfigKey.KEY_CONTENT_LAYOUT_GRAVITY, + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_DEFAULT, + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_ACCOUNT, + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_CONNECTION, + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_UPDATE, + PartnerConfigKey.KEY_PROGRESS_ILLUSTRATION_DISPLAY_MINIMUM_MS, }) // TODO: can be removed and always reference PartnerConfig.getResourceName()? @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) @@ -182,4 +187,23 @@ public @interface PartnerConfigKey { // Gravity of the body content text String KEY_CONTENT_LAYOUT_GRAVITY = "setup_design_content_layout_gravity"; + + // The animation of loading screen used in those activities which is non of below type. + String KEY_PROGRESS_ILLUSTRATION_DEFAULT = "progress_illustration_custom_default"; + + // The animation of loading screen used in those activity which is processing account info or + // related functions. + // For example:com.google.android.setupwizard.LOAD_ADD_ACCOUNT_INTENT + String KEY_PROGRESS_ILLUSTRATION_ACCOUNT = "progress_illustration_custom_account"; + + // The animation of loading screen used in those activity which is processing data connection. + // For example:com.android.setupwizard.CAPTIVE_PORTAL + String KEY_PROGRESS_ILLUSTRATION_CONNECTION = "progress_illustration_custom_connection"; + + // The animation of loading screen used in those activities which is updating device. + // For example:com.google.android.setupwizard.COMPAT_EARLY_UPDATE + String KEY_PROGRESS_ILLUSTRATION_UPDATE = "progress_illustration_custom_update"; + + // The minimum illustration display time, set to 0 may cause the illustration stuck + String KEY_PROGRESS_ILLUSTRATION_DISPLAY_MINIMUM_MS = "progress_illustration_display_minimum_ms"; } -- cgit v1.2.3 From c6d929030275abe2cfd23756cce4e1de8db70713 Mon Sep 17 00:00:00 2001 From: Setup Wizard Team Date: Thu, 21 May 2020 21:40:38 +0800 Subject: Import updated Android SetupCompat Library 312662043 Copied from google3/third_party/java_src/android_libs/setupcompat Bug: 135057670 Test: mm Included changes: - 312662043 [Stencil] Support partner resource to customize the disab... PiperOrigin-RevId: 312662043 Change-Id: I662dd0e785b09bdbddcc4d64927ed754b7c4cce1 --- .../internal/FooterButtonPartnerConfig.java | 28 +++++++++++ .../setupcompat/template/FooterBarMixin.java | 55 ++++++++++++++++------ .../setupcompat/partnerconfig/PartnerConfig.java | 8 ++++ .../partnerconfig/PartnerConfigKey.java | 8 ++++ 4 files changed, 85 insertions(+), 14 deletions(-) diff --git a/main/java/com/google/android/setupcompat/internal/FooterButtonPartnerConfig.java b/main/java/com/google/android/setupcompat/internal/FooterButtonPartnerConfig.java index 6a019fd..39b50cf 100644 --- a/main/java/com/google/android/setupcompat/internal/FooterButtonPartnerConfig.java +++ b/main/java/com/google/android/setupcompat/internal/FooterButtonPartnerConfig.java @@ -22,6 +22,8 @@ import com.google.android.setupcompat.template.FooterButton; /** Keep the partner configuration of a footer button. Used when the button is inflated. */ public class FooterButtonPartnerConfig { private final PartnerConfig buttonBackgroundConfig; + private final PartnerConfig buttonDisableAlphaConfig; + private final PartnerConfig buttonDisableBackgroundConfig; private final PartnerConfig buttonIconConfig; private final PartnerConfig buttonTextColorConfig; private final PartnerConfig buttonTextSizeConfig; @@ -33,6 +35,8 @@ public class FooterButtonPartnerConfig { private FooterButtonPartnerConfig( int partnerTheme, PartnerConfig buttonBackgroundConfig, + PartnerConfig buttonDisableAlphaConfig, + PartnerConfig buttonDisableBackgroundConfig, PartnerConfig buttonIconConfig, PartnerConfig buttonTextColorConfig, PartnerConfig buttonTextSizeConfig, @@ -45,6 +49,8 @@ public class FooterButtonPartnerConfig { this.buttonTextSizeConfig = buttonTextSizeConfig; this.buttonTextTypeFaceConfig = buttonTextTypeFaceConfig; this.buttonBackgroundConfig = buttonBackgroundConfig; + this.buttonDisableAlphaConfig = buttonDisableAlphaConfig; + this.buttonDisableBackgroundConfig = buttonDisableBackgroundConfig; this.buttonRadiusConfig = buttonRadiusConfig; this.buttonIconConfig = buttonIconConfig; this.buttonRippleColorAlphaConfig = buttonRippleColorAlphaConfig; @@ -58,6 +64,14 @@ public class FooterButtonPartnerConfig { return buttonBackgroundConfig; } + public PartnerConfig getButtonDisableAlphaConfig() { + return buttonDisableAlphaConfig; + } + + public PartnerConfig getButtonDisableBackgroundConfig() { + return buttonDisableBackgroundConfig; + } + public PartnerConfig getButtonIconConfig() { return buttonIconConfig; } @@ -86,6 +100,8 @@ public class FooterButtonPartnerConfig { public static class Builder { private final FooterButton footerButton; private PartnerConfig buttonBackgroundConfig = null; + private PartnerConfig buttonDisableAlphaConfig = null; + private PartnerConfig buttonDisableBackgroundConfig = null; private PartnerConfig buttonIconConfig = null; private PartnerConfig buttonTextColorConfig = null; private PartnerConfig buttonTextSizeConfig = null; @@ -105,6 +121,16 @@ public class FooterButtonPartnerConfig { return this; } + public Builder setButtonDisableAlphaConfig(PartnerConfig buttonDisableAlphaConfig) { + this.buttonDisableAlphaConfig = buttonDisableAlphaConfig; + return this; + } + + public Builder setButtonDisableBackgroundConfig(PartnerConfig buttonDisableBackgroundConfig) { + this.buttonDisableBackgroundConfig = buttonDisableBackgroundConfig; + return this; + } + public Builder setButtonIconConfig(PartnerConfig buttonIconConfig) { this.buttonIconConfig = buttonIconConfig; return this; @@ -144,6 +170,8 @@ public class FooterButtonPartnerConfig { return new FooterButtonPartnerConfig( partnerTheme, buttonBackgroundConfig, + buttonDisableAlphaConfig, + buttonDisableBackgroundConfig, buttonIconConfig, buttonTextColorConfig, buttonTextSizeConfig, diff --git a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java index 3c88791..bc9e5c1 100644 --- a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java +++ b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java @@ -303,6 +303,8 @@ public class FooterBarMixin implements Mixin { /* buttonBackgroundColorConfig= */ PartnerConfig .CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR)) .setButtonBackgroundConfig(PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR) + .setButtonDisableAlphaConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_DISABLED_ALPHA) + .setButtonDisableBackgroundConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_DISABLED_BG_COLOR) .setButtonIconConfig(getDrawablePartnerConfig(footerButton.getButtonType())) .setButtonRadiusConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_RADIUS) .setButtonRippleColorAlphaConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_RIPPLE_COLOR_ALPHA) @@ -357,6 +359,8 @@ public class FooterBarMixin implements Mixin { /* buttonBackgroundColorConfig= */ PartnerConfig .CONFIG_FOOTER_SECONDARY_BUTTON_BG_COLOR)) .setButtonBackgroundConfig(PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_BG_COLOR) + .setButtonDisableAlphaConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_DISABLED_ALPHA) + .setButtonDisableBackgroundConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_DISABLED_BG_COLOR) .setButtonIconConfig(getDrawablePartnerConfig(footerButton.getButtonType())) .setButtonRadiusConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_RADIUS) .setButtonRippleColorAlphaConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_RIPPLE_COLOR_ALPHA) @@ -428,14 +432,16 @@ public class FooterBarMixin implements Mixin { // TODO: Make sure customize attributes in theme can be applied during setup flow. // If sets background color to full transparent, the button changes to colored borderless ink // button style. - int color = PartnerConfigHelper.get(context).getColor(context, buttonBackgroundColorConfig); - if (applyPartnerResources && color == Color.TRANSPARENT) { - overrideTheme = R.style.SucPartnerCustomizationButton_Secondary; - } else if (applyPartnerResources && (color != Color.TRANSPARENT)) { - // TODO: remove the constrain (color != Color.WHITE), need to check all pages go - // well without customization. It should be fine since the default value of secondary bg color - // is set as transparent. - overrideTheme = R.style.SucPartnerCustomizationButton_Primary; + if (applyPartnerResources) { + int color = PartnerConfigHelper.get(context).getColor(context, buttonBackgroundColorConfig); + if (color == Color.TRANSPARENT) { + overrideTheme = R.style.SucPartnerCustomizationButton_Secondary; + } else if (color != Color.TRANSPARENT) { + // TODO: remove the constrain (color != Color.WHITE), need to check all pages + // go well without customization. It should be fine since the default value of secondary bg + // color is set as transparent. + overrideTheme = R.style.SucPartnerCustomizationButton_Primary; + } } return overrideTheme; } @@ -545,7 +551,10 @@ public class FooterBarMixin implements Mixin { updateButtonTypeFaceWithPartnerConfig( button, footerButtonPartnerConfig.getButtonTextTypeFaceConfig()); updateButtonBackgroundWithPartnerConfig( - button, footerButtonPartnerConfig.getButtonBackgroundConfig()); + button, + footerButtonPartnerConfig.getButtonBackgroundConfig(), + footerButtonPartnerConfig.getButtonDisableAlphaConfig(), + footerButtonPartnerConfig.getButtonDisableBackgroundConfig()); updateButtonRadiusWithPartnerConfig(button, footerButtonPartnerConfig.getButtonRadiusConfig()); updateButtonIconWithPartnerConfig(button, footerButtonPartnerConfig.getButtonIconConfig()); updateButtonRippleColorWithPartnerConfig(button, footerButtonPartnerConfig); @@ -586,25 +595,43 @@ public class FooterBarMixin implements Mixin { @TargetApi(VERSION_CODES.Q) private void updateButtonBackgroundWithPartnerConfig( - Button button, PartnerConfig buttonBackgroundConfig) { + Button button, + PartnerConfig buttonBackgroundConfig, + PartnerConfig buttonDisableAlphaConfig, + PartnerConfig buttonDisableBackgroundConfig) { Preconditions.checkArgument( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q, "Update button background only support on sdk Q or higher"); @ColorInt int color; + @ColorInt int disabledColor; + float disabledAlpha; int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled}; int[] ENABLED_STATE_SET = {}; color = PartnerConfigHelper.get(context).getColor(context, buttonBackgroundConfig); + disabledAlpha = + PartnerConfigHelper.get(context).getFraction(context, buttonDisableAlphaConfig, 0f); + disabledColor = + PartnerConfigHelper.get(context).getColor(context, buttonDisableBackgroundConfig); if (color != Color.TRANSPARENT) { - TypedArray a = context.obtainStyledAttributes(new int[] {android.R.attr.disabledAlpha}); - float alpha = a.getFloat(0, DEFAULT_DISABLED_ALPHA); - a.recycle(); + if (disabledAlpha <= 0f) { + // if no partner resource, fallback to theme disable alpha + float alpha; + TypedArray a = context.obtainStyledAttributes(new int[] {android.R.attr.disabledAlpha}); + alpha = a.getFloat(0, DEFAULT_DISABLED_ALPHA); + a.recycle(); + disabledAlpha = alpha; + } + if (disabledColor == Color.TRANSPARENT) { + // if no partner resource, fallback to button background color + disabledColor = color; + } // Set text color for ripple. ColorStateList colorStateList = new ColorStateList( new int[][] {DISABLED_STATE_SET, ENABLED_STATE_SET}, - new int[] {convertRgbToArgb(color, alpha), color}); + new int[] {convertRgbToArgb(disabledColor, disabledAlpha), color}); // b/129482013: When a LayerDrawable is mutated, a new clone of its children drawables are // created, but without copying the state from the parent drawable. So even though the diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java index 2844e03..56256c9 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java @@ -93,6 +93,14 @@ public enum PartnerConfig { CONFIG_FOOTER_BUTTON_TEXT_SIZE( PartnerConfigKey.KEY_FOOTER_BUTTON_TEXT_SIZE, ResourceType.DIMENSION), + // Disabled background alpha of the footer buttons + CONFIG_FOOTER_BUTTON_DISABLED_ALPHA( + PartnerConfigKey.KEY_FOOTER_BUTTON_DISABLED_ALPHA, ResourceType.FRACTION), + + // Disabled background color of the footer buttons + CONFIG_FOOTER_BUTTON_DISABLED_BG_COLOR( + PartnerConfigKey.KEY_FOOTER_BUTTON_DISABLED_BG_COLOR, ResourceType.COLOR), + // Background color of the primary footer button CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR( PartnerConfigKey.KEY_FOOTER_PRIMARY_BUTTON_BG_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 49e96b2..e5c5442 100644 --- a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java @@ -43,6 +43,8 @@ import java.lang.annotation.RetentionPolicy; PartnerConfigKey.KEY_FOOTER_BUTTON_RADIUS, PartnerConfigKey.KEY_FOOTER_BUTTON_RIPPLE_ALPHA, PartnerConfigKey.KEY_FOOTER_BUTTON_TEXT_SIZE, + PartnerConfigKey.KEY_FOOTER_BUTTON_DISABLED_ALPHA, + PartnerConfigKey.KEY_FOOTER_BUTTON_DISABLED_BG_COLOR, PartnerConfigKey.KEY_FOOTER_PRIMARY_BUTTON_BG_COLOR, PartnerConfigKey.KEY_FOOTER_PRIMARY_BUTTON_TEXT_COLOR, PartnerConfigKey.KEY_FOOTER_SECONDARY_BUTTON_BG_COLOR, @@ -131,6 +133,12 @@ public @interface PartnerConfigKey { // Text size of the footer button String KEY_FOOTER_BUTTON_TEXT_SIZE = "setup_compat_footer_button_text_size"; + // Disabled background alpha of the footer buttons + String KEY_FOOTER_BUTTON_DISABLED_ALPHA = "setup_compat_footer_button_disabled_alpha"; + + // Disabled background color of the footer buttons + String KEY_FOOTER_BUTTON_DISABLED_BG_COLOR = "setup_compat_footer_button_disabled_bg_color"; + // Background color of the primary footer button String KEY_FOOTER_PRIMARY_BUTTON_BG_COLOR = "setup_compat_footer_primary_button_bg_color"; -- cgit v1.2.3