| package {package_name}; |
| {{ -if not is_test_mode }} |
| {{ -if allow_instrumentation }} |
| {{ if not library_exported- }}{#- only new storage for prod mode #} |
| // TODO(b/303773055): Remove the annotation after access issue is resolved. |
| import android.compat.annotation.UnsupportedAppUsage; |
| {{ -if runtime_lookup_required }} |
| import android.aconfig.storage.StorageInternalReader; |
| {{ -endif }} |
| /** @hide */ |
| public final class FeatureFlagsImpl implements FeatureFlags \{ |
| {{ -if runtime_lookup_required }} |
| private static volatile boolean isCached = false; |
| {{ for flag in flag_elements }} |
| {{ -if flag.is_read_write }} |
| private static boolean {flag.method_name} = {flag.default_value}; |
| {{ -endif }} |
| {{ -endfor }} |
| |
| private void init() \{ |
| try \{ |
| StorageInternalReader reader = new StorageInternalReader("{container}", "{package_name}"); |
| {{ for namespace_with_flags in namespace_flags }} |
| {{ -for flag in namespace_with_flags.flags }} |
| {{ if flag.is_read_write }} |
| {flag.method_name} = reader.getBooleanFlagValue({flag.flag_offset}); |
| {{ endif }} |
| {{ -endfor }} |
| {{ -endfor }} |
| } catch (Exception e) \{ |
| // pass |
| } catch (NoClassDefFoundError e) \{ |
| // for mainline module running on older devices. |
| // This should be replaces to version check, after the version bump. |
| } |
| isCached = true; |
| } |
| {{ -endif }}{#- end of runtime_lookup_required #} |
| {{ -for flag in flag_elements }} |
| @Override |
| @com.android.aconfig.annotations.AconfigFlagAccessor |
| @UnsupportedAppUsage |
| public boolean {flag.method_name}() \{ |
| {{ -if flag.is_read_write }} |
| if (!isCached) \{ |
| init(); |
| } |
| return {flag.method_name}; |
| {{ -else }} |
| return {flag.default_value}; |
| {{ -endif }} |
| } |
| {{ endfor }} |
| } |
| {{ -else- }}{#- device config for exproted mode #} |
| import android.os.Binder; |
| import android.provider.DeviceConfig; |
| import android.provider.DeviceConfig.Properties; |
| /** @hide */ |
| public final class FeatureFlagsImpl implements FeatureFlags \{ |
| {{ -for namespace_with_flags in namespace_flags }} |
| private static volatile boolean {namespace_with_flags.namespace}_is_cached = false; |
| {{ -endfor- }} |
| {{ for flag in flag_elements }} |
| {{ -if flag.is_read_write }} |
| private static boolean {flag.method_name} = {flag.default_value}; |
| {{ -endif }} |
| {{ -endfor }} |
| {{ for namespace_with_flags in namespace_flags }} |
| private void load_overrides_{namespace_with_flags.namespace}() \{ |
| final long ident = Binder.clearCallingIdentity(); |
| try \{ |
| Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}"); |
| {{ -for flag in namespace_with_flags.flags }} |
| {{ -if flag.is_read_write }} |
| {flag.method_name} = |
| properties.getBoolean(Flags.FLAG_{flag.flag_name_constant_suffix}, {flag.default_value}); |
| {{ -endif }} |
| {{ -endfor }} |
| } catch (NullPointerException e) \{ |
| throw new RuntimeException( |
| "Cannot read value from namespace {namespace_with_flags.namespace} " |
| + "from DeviceConfig. It could be that the code using flag " |
| + "executed before SettingsProvider initialization. Please use " |
| + "fixed read-only flag by adding is_fixed_read_only: true in " |
| + "flag declaration.", |
| e |
| ); |
| } catch (SecurityException e) \{ |
| // for isolated process case, skip loading flag value from the storage, use the default |
| } finally \{ |
| Binder.restoreCallingIdentity(ident); |
| } |
| {namespace_with_flags.namespace}_is_cached = true; |
| } |
| {{ endfor- }} |
| {{ -for flag in flag_elements }} |
| @Override |
| public boolean {flag.method_name}() \{ |
| if (!{flag.device_config_namespace}_is_cached) \{ |
| load_overrides_{flag.device_config_namespace}(); |
| } |
| return {flag.method_name}; |
| } |
| {{ endfor }} |
| } |
| {{ -endif- }} {#- end exported mode #} |
| {{ else }} {#- else for allow_instrumentation is not enabled #} |
| {{ if not library_exported- }} |
| // TODO(b/303773055): Remove the annotation after access issue is resolved. |
| import android.compat.annotation.UnsupportedAppUsage; |
| {{ -endif }} |
| |
| {{ -if runtime_lookup_required }} |
| import android.os.Binder; |
| import android.provider.DeviceConfig; |
| import android.provider.DeviceConfig.Properties; |
| {{ -endif }} |
| /** @hide */ |
| public final class FeatureFlagsImpl implements FeatureFlags \{ |
| {{ -if runtime_lookup_required }} |
| {{ -for namespace_with_flags in namespace_flags }} |
| private static volatile boolean {namespace_with_flags.namespace}_is_cached = false; |
| {{ -endfor- }} |
| |
| {{ for flag in flag_elements }} |
| {{- if flag.is_read_write }} |
| private static boolean {flag.method_name} = {flag.default_value}; |
| {{ -endif }} |
| {{ -endfor }} |
| {{ for namespace_with_flags in namespace_flags }} |
| private void load_overrides_{namespace_with_flags.namespace}() \{ |
| final long ident = Binder.clearCallingIdentity(); |
| try \{ |
| Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}"); |
| {{ -for flag in namespace_with_flags.flags }} |
| {{ -if flag.is_read_write }} |
| {flag.method_name} = |
| properties.getBoolean(Flags.FLAG_{flag.flag_name_constant_suffix}, {flag.default_value}); |
| {{ -endif }} |
| {{ -endfor }} |
| } catch (NullPointerException e) \{ |
| throw new RuntimeException( |
| "Cannot read value from namespace {namespace_with_flags.namespace} " |
| + "from DeviceConfig. It could be that the code using flag " |
| + "executed before SettingsProvider initialization. Please use " |
| + "fixed read-only flag by adding is_fixed_read_only: true in " |
| + "flag declaration.", |
| e |
| ); |
| } finally \{ |
| Binder.restoreCallingIdentity(ident); |
| } |
| {namespace_with_flags.namespace}_is_cached = true; |
| } |
| {{ endfor- }} |
| {{ -endif }}{#- end of runtime_lookup_required #} |
| {{ -for flag in flag_elements }} |
| @Override |
| {{ -if not library_exported }} |
| @com.android.aconfig.annotations.AconfigFlagAccessor |
| @UnsupportedAppUsage |
| {{ -endif }} |
| public boolean {flag.method_name}() \{ |
| {{ -if flag.is_read_write }} |
| if (!{flag.device_config_namespace}_is_cached) \{ |
| load_overrides_{flag.device_config_namespace}(); |
| } |
| return {flag.method_name}; |
| {{ -else }} |
| return {flag.default_value}; |
| {{ -endif }} |
| } |
| {{ endfor }} |
| } |
| {{ endif}} {#- endif for allow_instrumentation #} |
| {{ else }} {#- Generate only stub if in test mode #} |
| /** @hide */ |
| public final class FeatureFlagsImpl implements FeatureFlags \{ |
| {{ for flag in flag_elements }} |
| @Override |
| {{ -if not library_exported }} |
| @com.android.aconfig.annotations.AconfigFlagAccessor |
| {{ -endif }} |
| public boolean {flag.method_name}() \{ |
| throw new UnsupportedOperationException( |
| "Method is not implemented."); |
| } |
| {{ endfor- }} |
| } |
| {{ endif }} |