summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-08-27 10:16:31 -0700
committerXin Li <delphij@google.com>2020-08-27 10:16:31 -0700
commit3fec5d8276969fd44b7f0b49ddb3afcb9dccdc3e (patch)
tree201c5ea5c4def030650fab9c712ea41bf0ac74e9
parent4a6e4e804f30dfac6c250685a3453e8fb5c2ee32 (diff)
parent93f6d15b4a806cf4465e256a041e0b91c9aab3fe (diff)
downloadsetupcompat-temp_sam_168057903.tar.gz
Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)temp_sam_168057903
Bug: 166295507 Merged-In: Ic60d2d28c1488f6a602a8ac7b4268e722a0e386b Change-Id: I904a49116f122667bf0a0ac3017e718962cb1f2d
-rw-r--r--build.gradle2
-rw-r--r--main/java/com/google/android/setupcompat/PartnerCustomizationLayout.java4
-rw-r--r--main/java/com/google/android/setupcompat/internal/FooterButtonPartnerConfig.java28
-rw-r--r--main/java/com/google/android/setupcompat/internal/LifecycleFragment.java15
-rw-r--r--main/java/com/google/android/setupcompat/internal/SetupCompatServiceProvider.java2
-rw-r--r--main/java/com/google/android/setupcompat/logging/CustomEvent.java14
-rw-r--r--main/java/com/google/android/setupcompat/logging/MetricKey.java35
-rw-r--r--main/java/com/google/android/setupcompat/template/FooterBarMixin.java55
-rw-r--r--main/java/com/google/android/setupcompat/template/FooterButton.java4
-rw-r--r--main/java/com/google/android/setupcompat/util/ResultCodes.java4
-rw-r--r--main/java/com/google/android/setupcompat/util/SystemBarHelper.java2
-rw-r--r--main/java/com/google/android/setupcompat/util/WizardManagerHelper.java4
-rw-r--r--partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java52
-rw-r--r--partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java151
-rw-r--r--partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java52
-rw-r--r--partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java73
16 files changed, 412 insertions, 85 deletions
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
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/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/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;
@@ -40,6 +41,21 @@ public final class MetricKey implements Parcelable {
/**
* 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.
+ *
* <p>NOTE:
*
* <ul>
@@ -50,15 +66,21 @@ public final class MetricKey implements Parcelable {
* </ul>
*/
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/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/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/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 73d66e6..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),
@@ -139,15 +147,55 @@ 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),
+
+ // 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 eac403f..7b9f65b 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,16 +302,63 @@ 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;
}
+ /**
+ * 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 {
@@ -316,29 +374,20 @@ 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");
}
}
}
- 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..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,
@@ -57,6 +59,16 @@ 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,
+ 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)
@@ -121,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";
@@ -162,4 +180,38 @@ 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";
+
+ // 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";
}
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() {
@@ -72,9 +115,17 @@ public final class ResourceEntry {
}
/**
+ * 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));
+ }
+ }
}