diff options
author | Setup Wizard Team <android-setup-team-eng@google.com> | 2019-03-14 10:00:10 +0800 |
---|---|---|
committer | pastychang <pastychang@google.com> | 2019-03-15 10:37:13 +0800 |
commit | 1ed3073417396ad4d3bec9d6a5722b490a49e47e (patch) | |
tree | 6be9a1c1b6f1d6bbba588ccc23cbd069bad56622 /partnerconfig | |
parent | b5345f3d3b611fcf3513c613d1663f424414a12f (diff) | |
download | setupcompat-1ed3073417396ad4d3bec9d6a5722b490a49e47e.tar.gz |
Import updated Android SetupCompat Library 238357591
Test: mm
PiperOrigin-RevId: 238357591
Change-Id: Ifa32c7db8d5383f076582aeb7b44f42499a1217a
Diffstat (limited to 'partnerconfig')
5 files changed, 768 insertions, 0 deletions
diff --git a/partnerconfig/AndroidManifest.xml b/partnerconfig/AndroidManifest.xml new file mode 100644 index 0000000..c95a4dd --- /dev/null +++ b/partnerconfig/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.setupcompat.partnerconfig"> + + <uses-sdk + android:minSdkVersion="14" + android:targetSdkVersion="28" /> +</manifest> diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java new file mode 100644 index 0000000..d2ae023 --- /dev/null +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfig.java @@ -0,0 +1,168 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.setupcompat.partnerconfig; + +// TODO(b/121371322): optimize the enum +/** Resources that can be customized by partner overlay APK. */ +public enum PartnerConfig { + + // Status bar background color or illustration. + CONFIG_STATUS_BAR_BACKGROUND(PartnerConfigKey.KEY_STATUS_BAR_BACKGROUND, ResourceType.DRAWABLE), + + // The same as "WindowLightStatusBar". If set true, the status bar icons will be drawn such + // that it is compatible with a light status bar background + CONFIG_LIGHT_STATUS_BAR(PartnerConfigKey.KEY_LIGHT_STATUS_BAR, ResourceType.BOOL), + + // Navigation bar background color + CONFIG_NAVIGATION_BAR_BG_COLOR(PartnerConfigKey.KEY_NAVIGATION_BAR_BG_COLOR, ResourceType.COLOR), + + // Background color of the footer bar. + CONFIG_FOOTER_BAR_BG_COLOR(PartnerConfigKey.KEY_FOOTER_BAR_BG_COLOR, ResourceType.COLOR), + + // The same as "windowLightNavigationBar". If set true, the navigation bar icons will be drawn + // such that it is compatible with a light navigation bar background. + CONFIG_LIGHT_NAVIGATION_BAR(PartnerConfigKey.KEY_LIGHT_NAVIGATION_BAR, ResourceType.BOOL), + + // The font face used in footer buttons. This must be a string reference to a font that is + // available in the system. Font references (@font or @xml) are not allowed. + CONFIG_FOOTER_BUTTON_FONT_FAMILY( + PartnerConfigKey.KEY_FOOTER_BUTTON_FONT_FAMILY, ResourceType.STRING), + + // The icon for "add another" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_ADD_ANOTHER( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_ADD_ANOTHER, ResourceType.DRAWABLE), + + // The icon for "cancel" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_CANCEL( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_CANCEL, ResourceType.DRAWABLE), + + // The icon for "clear" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_CLEAR( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_CLEAR, ResourceType.DRAWABLE), + + // The icon for "done" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_DONE( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_DONE, ResourceType.DRAWABLE), + + // The icon for "next" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_NEXT( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_NEXT, ResourceType.DRAWABLE), + + // The icon for "opt-in" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_OPT_IN( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_OPT_IN, ResourceType.DRAWABLE), + + // The icon for "skip" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_SKIP( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_SKIP, ResourceType.DRAWABLE), + + // The icon for "stop" action. Can be "@null" for no icon. + CONFIG_FOOTER_BUTTON_ICON_STOP( + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_STOP, ResourceType.DRAWABLE), + + // Top padding of the footer buttons + CONFIG_FOOTER_BUTTON_PADDING_TOP( + PartnerConfigKey.KEY_FOOTER_BUTTON_PADDING_TOP, ResourceType.DIMENSION), + + // Bottom padding of the footer buttons + CONFIG_FOOTER_BUTTON_PADDING_BOTTOM( + PartnerConfigKey.KEY_FOOTER_BUTTON_PADDING_BOTTOM, ResourceType.DIMENSION), + + // Corner radius of the footer buttons + CONFIG_FOOTER_BUTTON_RADIUS(PartnerConfigKey.KEY_FOOTER_BUTTON_RADIUS, ResourceType.DIMENSION), + + // Ripple color alpha the footer buttons + CONFIG_FOOTER_BUTTON_RIPPLE_COLOR_ALPHA( + PartnerConfigKey.KEY_FOOTER_BUTTON_RIPPLE_ALPHA, ResourceType.FRACTION), + + // Text size of the primary footer button + CONFIG_FOOTER_BUTTON_TEXT_SIZE( + PartnerConfigKey.KEY_FOOTER_BUTTON_TEXT_SIZE, ResourceType.DIMENSION), + + // Background color of the primary footer button + CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR( + PartnerConfigKey.KEY_FOOTER_PRIMARY_BUTTON_BG_COLOR, ResourceType.COLOR), + + // Text color of the primary footer button + CONFIG_FOOTER_PRIMARY_BUTTON_TEXT_COLOR( + PartnerConfigKey.KEY_FOOTER_PRIMARY_BUTTON_TEXT_COLOR, ResourceType.COLOR), + + // Background color of the secondary footer button + CONFIG_FOOTER_SECONDARY_BUTTON_BG_COLOR( + PartnerConfigKey.KEY_FOOTER_SECONDARY_BUTTON_BG_COLOR, ResourceType.COLOR), + + // Text color of the secondary footer button + CONFIG_FOOTER_SECONDARY_BUTTON_TEXT_COLOR( + PartnerConfigKey.KEY_FOOTER_SECONDARY_BUTTON_TEXT_COLOR, ResourceType.COLOR), + + // Background color of layout + CONFIG_LAYOUT_BACKGROUND_COLOR(PartnerConfigKey.KEY_LAYOUT_BACKGROUND_COLOR, ResourceType.COLOR), + + // Text color of the header + CONFIG_HEADER_TEXT_COLOR(PartnerConfigKey.KEY_HEADER_TEXT_COLOR, ResourceType.COLOR), + + // Text size of the header + CONFIG_HEADER_TEXT_SIZE(PartnerConfigKey.KEY_HEADER_TEXT_SIZE, ResourceType.DIMENSION), + + // Font family of the header + CONFIG_HEADER_FONT_FAMILY(PartnerConfigKey.KEY_HEADER_FONT_FAMILY, ResourceType.STRING), + + // Gravity of the header, icon and description + CONFIG_LAYOUT_GRAVITY(PartnerConfigKey.KEY_LAYOUT_GRAVITY, ResourceType.STRING), + + // Background color of the header area + CONFIG_HEADER_AREA_BACKGROUND_COLOR( + PartnerConfigKey.KEY_HEADER_AREA_BACKGROUND_COLOR, ResourceType.COLOR), + + // Text size of the description + CONFIG_DESCRIPTION_TEXT_SIZE(PartnerConfigKey.KEY_DESCRIPTION_TEXT_SIZE, ResourceType.DIMENSION), + + // Text color of the description + CONFIG_DESCRIPTION_TEXT_COLOR(PartnerConfigKey.KEY_DESCRIPTION_TEXT_COLOR, ResourceType.COLOR), + + // Link text color of the description + CONFIG_DESCRIPTION_LINK_TEXT_COLOR( + PartnerConfigKey.KEY_DESCRIPTION_LINK_TEXT_COLOR, ResourceType.COLOR), + + // Font family of the description + CONFIG_DESCRIPTION_FONT_FAMILY(PartnerConfigKey.KEY_DESCRIPTION_FONT_FAMILY, ResourceType.STRING); + + public enum ResourceType { + BOOL, + COLOR, + DRAWABLE, + STRING, + DIMENSION, + FRACTION; + } + + private final String resourceName; + private final ResourceType resourceType; + + public ResourceType getResourceType() { + return resourceType; + } + + public String getResourceName() { + return resourceName; + } + + PartnerConfig(@PartnerConfigKey String resourceName, ResourceType type) { + this.resourceName = resourceName; + this.resourceType = type; + } +} diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java new file mode 100644 index 0000000..6fb391c --- /dev/null +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigHelper.java @@ -0,0 +1,325 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.setupcompat.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; +import android.net.Uri; +import android.os.Build; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import android.util.Log; +import android.util.TypedValue; +import com.google.android.setupcompat.partnerconfig.PartnerConfig.ResourceType; +import java.util.EnumMap; + +/** The helper reads and caches the partner configurations from SUW. */ +public class PartnerConfigHelper { + + private static final String TAG = PartnerConfigHelper.class.getSimpleName(); + + @VisibleForTesting + public static final String SUW_AUTHORITY = "com.google.android.setupwizard.partner"; + + @VisibleForTesting public static final String SUW_GET_PARTNER_CONFIG_METHOD = "getOverlayConfig"; + private static PartnerConfigHelper instance = null; + + @VisibleForTesting Bundle resultBundle = null; + + @VisibleForTesting + final EnumMap<PartnerConfig, Object> partnerResourceCache = new EnumMap<>(PartnerConfig.class); + + public static synchronized PartnerConfigHelper get(@NonNull Context context) { + if (instance == null) { + instance = new PartnerConfigHelper(context); + } + return instance; + } + + private PartnerConfigHelper(Context context) { + getPartnerConfigBundle(context); + } + + /** + * Returns the color of given {@code resourceConfig}, or 0 if the given {@code resourceConfig} is + * not found. If the {@code ResourceType} of the given {@code resourceConfig} is not color, + * IllegalArgumentException will be thrown. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + */ + @ColorInt + public int getColor(@NonNull Context context, PartnerConfig resourceConfig) { + if (resourceConfig.getResourceType() != ResourceType.COLOR) { + throw new IllegalArgumentException("Not a color resource"); + } + + if (partnerResourceCache.containsKey(resourceConfig)) { + return (int) partnerResourceCache.get(resourceConfig); + } + + int result = 0; + try { + String resourceName = resourceConfig.getResourceName(); + ResourceEntry resourceEntry = getResourceEntryFromKey(resourceName); + Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + if (Build.VERSION.SDK_INT >= VERSION_CODES.M) { + result = resource.getColor(resourceEntry.getResourceId(), null); + } else { + result = resource.getColor(resourceEntry.getResourceId()); + } + partnerResourceCache.put(resourceConfig, result); + } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + // fall through + } + return result; + } + + /** + * Returns the {@code Drawable} of given {@code resourceConfig}, or {@code null} if the given + * {@code resourceConfig} is not found. If the {@code ResourceType} of the given {@code + * resourceConfig} is not drawable, IllegalArgumentException will be thrown. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + */ + @Nullable + public Drawable getDrawable(@NonNull Context context, PartnerConfig resourceConfig) { + if (resourceConfig.getResourceType() != ResourceType.DRAWABLE) { + throw new IllegalArgumentException("Not a drawable resource"); + } + + if (partnerResourceCache.containsKey(resourceConfig)) { + return (Drawable) partnerResourceCache.get(resourceConfig); + } + + Drawable result = null; + try { + ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); + Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + + // for @null + TypedValue outValue = new TypedValue(); + resource.getValue(resourceEntry.getResourceId(), 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); + } else { + result = resource.getDrawable(resourceEntry.getResourceId()); + } + partnerResourceCache.put(resourceConfig, result); + } catch (PackageManager.NameNotFoundException + | NullPointerException + | NotFoundException exception) { + // fall through + } + return result; + } + + /** + * Returns the string of the given {@code resourceConfig}, or {@code null} if the given {@code + * resourceConfig} is not found. If the {@code ResourceType} of the given {@code resourceConfig} + * is not string, IllegalArgumentException will be thrown. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + */ + @Nullable + public String getString(@NonNull Context context, PartnerConfig resourceConfig) { + if (resourceConfig.getResourceType() != ResourceType.STRING) { + throw new IllegalArgumentException("Not a string resource"); + } + + if (partnerResourceCache.containsKey(resourceConfig)) { + return (String) partnerResourceCache.get(resourceConfig); + } + + String result = null; + try { + ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); + Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + result = resource.getString(resourceEntry.getResourceId()); + partnerResourceCache.put(resourceConfig, result); + } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + // fall through + } + return result; + } + + /** + * Returns the boolean of given {@code resourceConfig}, or {@code defaultValue} if the given + * {@code resourceName} is not found. If the {@code ResourceType} of the given {@code + * resourceConfig} is not boolean, IllegalArgumentException will be thrown. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + * @param defaultValue The default value + */ + public boolean getBoolean( + @NonNull Context context, PartnerConfig resourceConfig, boolean defaultValue) { + if (resourceConfig.getResourceType() != ResourceType.BOOL) { + throw new IllegalArgumentException("Not a bool resource"); + } + + if (partnerResourceCache.containsKey(resourceConfig)) { + return (boolean) partnerResourceCache.get(resourceConfig); + } + + boolean result = defaultValue; + try { + ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); + Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + result = resource.getBoolean(resourceEntry.getResourceId()); + partnerResourceCache.put(resourceConfig, result); + } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + // fall through + } + return result; + } + + /** + * Returns the dimension of given {@code resourceConfig}. The default return value is 0. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + */ + public float getDimension(@NonNull Context context, PartnerConfig resourceConfig) { + return getDimension(context, resourceConfig, 0); + } + + /** + * Returns the dimension of given {@code resourceConfig}. If the given {@code resourceConfig} not + * found, will return {@code defaultValue}. If the {@code ResourceType} of given {@code + * resourceConfig} is not dimension, will throw IllegalArgumentException. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + * @param defaultValue The default value + */ + public float getDimension( + @NonNull Context context, PartnerConfig resourceConfig, float defaultValue) { + if (resourceConfig.getResourceType() != ResourceType.DIMENSION) { + throw new IllegalArgumentException("Not a dimension resource"); + } + + if (partnerResourceCache.containsKey(resourceConfig)) { + return (float) partnerResourceCache.get(resourceConfig); + } + + float result = defaultValue; + try { + ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); + Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + result = resource.getDimension(resourceEntry.getResourceId()); + partnerResourceCache.put(resourceConfig, result); + } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + // fall through + } + return result; + } + + /** + * Returns the float of given {@code resourceConfig}. The default return value is 0. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + */ + public float getFraction(@NonNull Context context, PartnerConfig resourceConfig) { + return getFraction(context, resourceConfig, 0.0f); + } + + /** + * Returns the float of given {@code resourceConfig}. If the given {@code resourceConfig} not + * found, will return {@code defaultValue}. If the {@code ResourceType} of given {@code + * resourceConfig} is not fraction, will throw IllegalArgumentException. + * + * @param context The context of client activity + * @param resourceConfig The {@code PartnerConfig} of target resource + * @param defaultValue The default value + */ + public float getFraction( + @NonNull Context context, PartnerConfig resourceConfig, float defaultValue) { + if (resourceConfig.getResourceType() != ResourceType.FRACTION) { + throw new IllegalArgumentException("Not a fraction resource"); + } + + if (partnerResourceCache.containsKey(resourceConfig)) { + return (float) partnerResourceCache.get(resourceConfig); + } + + float result = defaultValue; + try { + ResourceEntry resourceEntry = getResourceEntryFromKey(resourceConfig.getResourceName()); + Resources resource = getResourcesByPackageName(context, resourceEntry.getPackageName()); + result = resource.getFraction(resourceEntry.getResourceId(), 1, 1); + partnerResourceCache.put(resourceConfig, result); + } catch (PackageManager.NameNotFoundException | NullPointerException exception) { + // fall through + } + return result; + } + + private void getPartnerConfigBundle(Context context) { + if (resultBundle == null || resultBundle.isEmpty()) { + try { + Uri contentUri = + new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SUW_AUTHORITY) + .appendPath(SUW_GET_PARTNER_CONFIG_METHOD) + .build(); + resultBundle = + context + .getContentResolver() + .call( + contentUri, SUW_GET_PARTNER_CONFIG_METHOD, /* arg= */ null, /* extras= */ null); + partnerResourceCache.clear(); + } catch (IllegalArgumentException 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(); + return manager.getResourcesForApplication(packageName); + } + + private ResourceEntry getResourceEntryFromKey(String resourceName) { + if (resultBundle == null) { + return null; + } + return ResourceEntry.fromBundle(resultBundle.getBundle(resourceName)); + } + + @VisibleForTesting + public static synchronized void resetForTesting() { + instance = null; + } +} diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java new file mode 100644 index 0000000..0c0c44f --- /dev/null +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/PartnerConfigKey.java @@ -0,0 +1,165 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.setupcompat.partnerconfig; + +import androidx.annotation.StringDef; +import androidx.annotation.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** Resource names that can be customized by partner overlay APK. */ +@Retention(RetentionPolicy.SOURCE) +@StringDef({ + PartnerConfigKey.KEY_STATUS_BAR_BACKGROUND, + PartnerConfigKey.KEY_LIGHT_STATUS_BAR, + PartnerConfigKey.KEY_NAVIGATION_BAR_BG_COLOR, + PartnerConfigKey.KEY_LIGHT_NAVIGATION_BAR, + PartnerConfigKey.KEY_FOOTER_BAR_BG_COLOR, + PartnerConfigKey.KEY_FOOTER_BUTTON_FONT_FAMILY, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_ADD_ANOTHER, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_CANCEL, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_CLEAR, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_DONE, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_NEXT, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_OPT_IN, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_SKIP, + PartnerConfigKey.KEY_FOOTER_BUTTON_ICON_STOP, + PartnerConfigKey.KEY_FOOTER_BUTTON_PADDING_TOP, + PartnerConfigKey.KEY_FOOTER_BUTTON_PADDING_BOTTOM, + PartnerConfigKey.KEY_FOOTER_BUTTON_RADIUS, + PartnerConfigKey.KEY_FOOTER_BUTTON_RIPPLE_ALPHA, + PartnerConfigKey.KEY_FOOTER_BUTTON_TEXT_SIZE, + PartnerConfigKey.KEY_FOOTER_PRIMARY_BUTTON_BG_COLOR, + PartnerConfigKey.KEY_FOOTER_PRIMARY_BUTTON_TEXT_COLOR, + PartnerConfigKey.KEY_FOOTER_SECONDARY_BUTTON_BG_COLOR, + PartnerConfigKey.KEY_FOOTER_SECONDARY_BUTTON_TEXT_COLOR, + PartnerConfigKey.KEY_LAYOUT_BACKGROUND_COLOR, + PartnerConfigKey.KEY_HEADER_TEXT_SIZE, + PartnerConfigKey.KEY_HEADER_TEXT_COLOR, + PartnerConfigKey.KEY_HEADER_FONT_FAMILY, + PartnerConfigKey.KEY_HEADER_AREA_BACKGROUND_COLOR, + PartnerConfigKey.KEY_LAYOUT_GRAVITY, + PartnerConfigKey.KEY_DESCRIPTION_TEXT_SIZE, + PartnerConfigKey.KEY_DESCRIPTION_TEXT_COLOR, + PartnerConfigKey.KEY_DESCRIPTION_LINK_TEXT_COLOR, + PartnerConfigKey.KEY_DESCRIPTION_FONT_FAMILY, +}) +// TODO(b/121371322): can be removed and always reference PartnerConfig.getResourceName()? +@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) +public @interface PartnerConfigKey { + // Status bar background color or illustration. + String KEY_STATUS_BAR_BACKGROUND = "setup_compat_status_bar_background"; + + // The same as "WindowLightStatusBar". If set true, the status bar icons will be drawn such + // that it is compatible with a light status bar background + String KEY_LIGHT_STATUS_BAR = "setup_compat_light_status_bar"; + + // Navigation bar background color + String KEY_NAVIGATION_BAR_BG_COLOR = "setup_compat_navigation_bar_bg_color"; + + // The same as "windowLightNavigationBar". If set true, the navigation bar icons will be drawn + // such that it is compatible with a light navigation bar background. + String KEY_LIGHT_NAVIGATION_BAR = "setup_compat_light_navigation_bar"; + + // Background color of the footer bar. + String KEY_FOOTER_BAR_BG_COLOR = "setup_compat_footer_bar_bg_color"; + + // The font face used in footer buttons. This must be a string reference to a font that is + // available in the system. Font references (@font or @xml) are not allowed. + String KEY_FOOTER_BUTTON_FONT_FAMILY = "setup_compat_footer_button_font_family"; + + // The icon for "add another" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_ADD_ANOTHER = "setup_compat_footer_button_icon_add_another"; + + // The icon for "cancel" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_CANCEL = "setup_compat_footer_button_icon_cancel"; + + // The icon for "clear" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_CLEAR = "setup_compat_footer_button_icon_clear"; + + // The icon for "done" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_DONE = "setup_compat_footer_button_icon_done"; + + // The icon for "next" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_NEXT = "setup_compat_footer_button_icon_next"; + + // The icon for "opt-in" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_OPT_IN = "setup_compat_footer_button_icon_opt_in"; + + // The icon for "skip" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_SKIP = "setup_compat_footer_button_icon_skip"; + + // The icon for "stop" action. Can be "@null" for no icon. + String KEY_FOOTER_BUTTON_ICON_STOP = "setup_compat_footer_button_icon_stop"; + + // Top padding of the footer buttons + String KEY_FOOTER_BUTTON_PADDING_TOP = "setup_compat_footer_button_padding_top"; + + // Bottom padding of the footer buttons + String KEY_FOOTER_BUTTON_PADDING_BOTTOM = "setup_compat_footer_button_padding_bottom"; + + // Corner radius of the footer buttons + String KEY_FOOTER_BUTTON_RADIUS = "setup_compat_footer_button_radius"; + + // Ripple color alpha of the footer button + String KEY_FOOTER_BUTTON_RIPPLE_ALPHA = "setup_compat_footer_button_ripple_alpha"; + + // Text size of the footer button + String KEY_FOOTER_BUTTON_TEXT_SIZE = "setup_compat_footer_button_text_size"; + + // Background color of the primary footer button + String KEY_FOOTER_PRIMARY_BUTTON_BG_COLOR = "setup_compat_footer_primary_button_bg_color"; + + // Text color of the primary footer button + String KEY_FOOTER_PRIMARY_BUTTON_TEXT_COLOR = "setup_compat_footer_primary_button_text_color"; + + // Background color of the secondary footer button + String KEY_FOOTER_SECONDARY_BUTTON_BG_COLOR = "setup_compat_footer_secondary_button_bg_color"; + + // Text color of the secondary footer button + String KEY_FOOTER_SECONDARY_BUTTON_TEXT_COLOR = "setup_compat_footer_secondary_button_text_color"; + + // Background color of layout + String KEY_LAYOUT_BACKGROUND_COLOR = "setup_compat_layout_bg_color"; + + // Text size of the header + String KEY_HEADER_TEXT_SIZE = "setup_design_header_text_size"; + + // Text color of the header + String KEY_HEADER_TEXT_COLOR = "setup_design_header_text_color"; + + // Font family of the header + String KEY_HEADER_FONT_FAMILY = "setup_design_header_font_family"; + + // Gravity of the header, icon and description + String KEY_LAYOUT_GRAVITY = "setup_design_layout_gravity"; + + // Background color of the header area + String KEY_HEADER_AREA_BACKGROUND_COLOR = "setup_design_header_area_background_color"; + + // Text size of the description + String KEY_DESCRIPTION_TEXT_SIZE = "setup_design_description_text_size"; + + // Text color of the description + String KEY_DESCRIPTION_TEXT_COLOR = "setup_design_description_text_color"; + + // Link text color of the description + String KEY_DESCRIPTION_LINK_TEXT_COLOR = "setup_design_description_link_text_color"; + + // Font family of the description + String KEY_DESCRIPTION_FONT_FAMILY = "setup_design_description_font_family"; +} diff --git a/partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java new file mode 100644 index 0000000..2794f22 --- /dev/null +++ b/partnerconfig/java/com/google/android/setupcompat/partnerconfig/ResourceEntry.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.setupcompat.partnerconfig; + +import android.os.Bundle; +import androidx.annotation.VisibleForTesting; + +/** + * 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 + * on IPC via the Bundle representation. + */ +public final class ResourceEntry { + @VisibleForTesting static final String KEY_PACKAGE_NAME = "packageName"; + @VisibleForTesting static final String KEY_RESOURCE_NAME = "resourceName"; + @VisibleForTesting static final String KEY_RESOURCE_ID = "resourceId"; + + private final String packageName; + private final String resourceName; + private final int resourceId; + + /** + * Creates a {@code ResourceEntry} object from a provided bundle. + * + * @param bundle the source bundle needs to have all the information for a {@code ResourceEntry} + */ + public static ResourceEntry fromBundle(Bundle bundle) { + String packageName; + String resourceName; + int resourceId; + if (!bundle.containsKey(KEY_PACKAGE_NAME) + || !bundle.containsKey(KEY_RESOURCE_NAME) + || !bundle.containsKey(KEY_RESOURCE_ID)) { + return null; + } + packageName = bundle.getString(KEY_PACKAGE_NAME); + resourceName = bundle.getString(KEY_RESOURCE_NAME); + resourceId = bundle.getInt(KEY_RESOURCE_ID); + return new ResourceEntry(packageName, resourceName, resourceId); + } + + public ResourceEntry(String packageName, String resourceName, int resourceId) { + this.packageName = packageName; + this.resourceName = resourceName; + this.resourceId = resourceId; + } + + public String getPackageName() { + return this.packageName; + } + + public String getResourceName() { + return this.resourceName; + } + + public int getResourceId() { + return this.resourceId; + } + + /** + * Returns a bundle representation of this resource entry, which can then be sent over IPC. + * + * @see #fromBundle(Bundle) + */ + public Bundle toBundle() { + Bundle result = new Bundle(); + result.putString(KEY_PACKAGE_NAME, packageName); + result.putString(KEY_RESOURCE_NAME, resourceName); + result.putInt(KEY_RESOURCE_ID, resourceId); + return result; + } +} |