Remove Context requirement from updatable

Bug: 74843539
Test: runtest-cts-MediaComponents && atest VideoView2Test
Change-Id: I1e377435556bdb786322165e3a0563a54bd8fab6
diff --git a/packages/MediaComponents/proguard.cfg b/packages/MediaComponents/proguard.cfg
index 43f2e63..d7bf730 100644
--- a/packages/MediaComponents/proguard.cfg
+++ b/packages/MediaComponents/proguard.cfg
@@ -16,5 +16,5 @@
 
 # Keep entry point for updatable Java classes
 -keep public class com.android.media.update.ApiFactory {
-   public static java.lang.Object initialize(android.content.res.Resources, android.content.res.Resources$Theme);
+   public static com.android.media.update.ApiFactory initialize(android.content.pm.ApplicationInfo);
 }
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 395e675..05a54d5 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -18,8 +18,7 @@
 
 import android.app.Notification;
 import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.Resources.Theme;
+import android.content.pm.ApplicationInfo;
 import android.media.MediaBrowser2;
 import android.media.MediaBrowser2.BrowserCallback;
 import android.media.MediaController2;
@@ -83,10 +82,11 @@
 
 import java.util.concurrent.Executor;
 
-public class ApiFactory implements StaticProvider {
-    public static Object initialize(Resources libResources, Theme libTheme)
-            throws ReflectiveOperationException {
-        ApiHelper.initialize(libResources, libTheme);
+public final class ApiFactory implements StaticProvider {
+    private ApiFactory() { }
+
+    public static ApiFactory initialize(ApplicationInfo updatableInfo) {
+        ApiHelper.initialize(updatableInfo);
         return new ApiFactory();
     }
 
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
index 7018844..ad8bb48 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
@@ -19,9 +19,12 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
+import android.support.annotation.GuardedBy;
 import android.support.v4.widget.Space;
 import android.support.v7.widget.ButtonBarLayout;
 import android.util.AttributeSet;
@@ -35,45 +38,47 @@
 import com.android.support.mediarouter.app.MediaRouteVolumeSlider;
 import com.android.support.mediarouter.app.OverlayListView;
 
-public class ApiHelper {
-    private static ApiHelper sInstance;
-    private final Resources mLibResources;
-    private final Theme mLibTheme;
+public final class ApiHelper {
+    private static ApplicationInfo sUpdatableInfo;
 
-    public static ApiHelper getInstance() {
-        return sInstance;
-    }
+    @GuardedBy("this")
+    private static Theme sLibTheme;
 
-    static void initialize(Resources libResources, Theme libTheme) {
-        if (sInstance == null) {
-            sInstance = new ApiHelper(libResources, libTheme);
+    private ApiHelper() { }
+
+    static void initialize(ApplicationInfo updatableInfo) {
+        if (sUpdatableInfo != null) {
+            throw new IllegalStateException("initialize should only be called once");
         }
+
+        sUpdatableInfo = updatableInfo;
     }
 
-    private ApiHelper(Resources libResources, Theme libTheme) {
-        mLibResources = libResources;
-        mLibTheme = libTheme;
+    public static Resources getLibResources(Context context) {
+        return getLibTheme(context).getResources();
     }
 
-    public static Resources getLibResources() {
-        return sInstance.mLibResources;
+    public static Theme getLibTheme(Context context) {
+        if (sLibTheme != null) return sLibTheme;
+
+        return getLibThemeSynchronized(context);
     }
 
-    public static Theme getLibTheme() {
-        return sInstance.mLibTheme;
-    }
-
-    public static Theme getLibTheme(int themeId) {
-        Theme theme = sInstance.mLibResources.newTheme();
+    public static Theme getLibTheme(Context context, int themeId) {
+        Theme theme = getLibResources(context).newTheme();
         theme.applyStyle(themeId, true);
         return theme;
     }
 
     public static LayoutInflater getLayoutInflater(Context context) {
-        return getLayoutInflater(context, getLibTheme());
+        return getLayoutInflater(context, null);
     }
 
     public static LayoutInflater getLayoutInflater(Context context, Theme theme) {
+        if (theme == null) {
+            theme = getLibTheme(context);
+        }
+
         // TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
         LayoutInflater layoutInflater = LayoutInflater.from(context).cloneInContext(
                 new ContextThemeWrapper(context, theme));
@@ -106,7 +111,7 @@
     }
 
     public static View inflateLibLayout(Context context, int libResId) {
-        return inflateLibLayout(context, getLibTheme(), libResId, null, false);
+        return inflateLibLayout(context, getLibTheme(context), libResId, null, false);
     }
 
     public static View inflateLibLayout(Context context, Theme theme, int libResId) {
@@ -115,8 +120,23 @@
 
     public static View inflateLibLayout(Context context, Theme theme, int libResId,
             @Nullable ViewGroup root, boolean attachToRoot) {
-        try (XmlResourceParser parser = getLibResources().getLayout(libResId)) {
+        try (XmlResourceParser parser = getLibResources(context).getLayout(libResId)) {
             return getLayoutInflater(context, theme).inflate(parser, root, attachToRoot);
         }
     }
+
+    private static synchronized Theme getLibThemeSynchronized(Context context) {
+        if (sLibTheme != null) return sLibTheme;
+
+        if (sUpdatableInfo == null) {
+            throw new IllegalStateException("initialize hasn't been called yet");
+        }
+
+        try {
+            return sLibTheme = context.getPackageManager()
+                    .getResourcesForApplication(sUpdatableInfo).newTheme();
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
index fa94a81..fde8a63 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
@@ -130,7 +130,7 @@
         mRouter = MediaRouter.getInstance(context);
         mCallback = new MediaRouterCallback();
 
-        Resources.Theme theme = ApiHelper.getLibResources().newTheme();
+        Resources.Theme theme = ApiHelper.getLibResources(context).newTheme();
         theme.applyStyle(MediaRouterThemeHelper.getRouterThemeId(context), true);
         TypedArray a = theme.obtainStyledAttributes(attrs,
                 R.styleable.MediaRouteButton, defStyleAttr, 0);
@@ -304,7 +304,8 @@
      */
     void setCheatSheetEnabled(boolean enable) {
         TooltipCompat.setTooltipText(this, enable
-                ? ApiHelper.getLibResources().getString(R.string.mr_button_content_description)
+                ? ApiHelper.getLibResources(getContext())
+                    .getString(R.string.mr_button_content_description)
                 : null);
     }
 
@@ -547,7 +548,7 @@
         } else {
             resId = R.string.mr_cast_button_disconnected;
         }
-        setContentDescription(ApiHelper.getLibResources().getString(resId));
+        setContentDescription(ApiHelper.getLibResources(getContext()).getString(resId));
     }
 
     private final class MediaRouterCallback extends MediaRouter.Callback {
@@ -604,7 +605,7 @@
 
         @Override
         protected Drawable doInBackground(Void... params) {
-            return ApiHelper.getLibResources().getDrawable(mResId);
+            return ApiHelper.getLibResources(getContext()).getDrawable(mResId);
         }
 
         @Override
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
index 6e70eaf..cac64d9 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
@@ -99,8 +99,8 @@
 
     public MediaRouteChooserDialog(Context context, int theme) {
         // TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
-        super(new ContextThemeWrapper(context,
-                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(context))), theme);
+        super(new ContextThemeWrapper(context, ApiHelper.getLibTheme(context,
+                MediaRouterThemeHelper.getRouterThemeId(context))), theme);
         context = getContext();
 
         mRouter = MediaRouter.getInstance(context);
@@ -187,8 +187,8 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        setContentView(ApiHelper.inflateLibLayout(getContext(),
-                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(getContext())),
+        setContentView(ApiHelper.inflateLibLayout(getContext(), ApiHelper.getLibTheme(getContext(),
+                MediaRouterThemeHelper.getRouterThemeId(getContext())),
                 R.layout.mr_chooser_dialog));
 
         mRoutes = new ArrayList<>();
@@ -206,7 +206,7 @@
      * Sets the width of the dialog. Also called when configuration changes.
      */
     void updateLayout() {
-        getWindow().setLayout(MediaRouteDialogHelper.getDialogWidth(),
+        getWindow().setLayout(MediaRouteDialogHelper.getDialogWidth(getContext()),
                 ViewGroup.LayoutParams.WRAP_CONTENT);
     }
 
@@ -263,7 +263,7 @@
         public RouteAdapter(Context context, List<MediaRouter.RouteInfo> routes) {
             super(context, 0, routes);
 
-            TypedArray styledAttributes = ApiHelper.getLibTheme(
+            TypedArray styledAttributes = ApiHelper.getLibTheme(context,
                     MediaRouterThemeHelper.getRouterThemeId(context)).obtainStyledAttributes(
                             new int[] {
                                 R.attr.mediaRouteDefaultIconDrawable,
@@ -294,7 +294,7 @@
             View view = convertView;
             if (view == null) {
                 view = ApiHelper.inflateLibLayout(getContext(),
-                        ApiHelper.getLibTheme(
+                        ApiHelper.getLibTheme(getContext(),
                                 MediaRouterThemeHelper.getRouterThemeId(getContext())),
                         R.layout.mr_chooser_list_item, parent, false);
             }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
index 269a6e9..060cfca 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
@@ -206,8 +206,8 @@
 
     public MediaRouteControllerDialog(Context context, int theme) {
         // TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
-        super(new ContextThemeWrapper(context,
-                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(context))), theme);
+        super(new ContextThemeWrapper(context, ApiHelper.getLibTheme(context,
+                MediaRouterThemeHelper.getRouterThemeId(context))), theme);
         mContext = getContext();
 
         mControllerCallback = new MediaControllerCallback();
@@ -215,7 +215,7 @@
         mCallback = new MediaRouterCallback();
         mRoute = mRouter.getSelectedRoute();
         setMediaSession(mRouter.getMediaSessionToken());
-        mVolumeGroupListPaddingTop = ApiHelper.getLibResources().getDimensionPixelSize(
+        mVolumeGroupListPaddingTop = ApiHelper.getLibResources(context).getDimensionPixelSize(
                 R.dimen.mr_controller_volume_group_list_padding_top);
         mAccessibilityManager =
                 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
@@ -334,7 +334,7 @@
         getWindow().setBackgroundDrawableResource(android.R.color.transparent);
 
         setContentView(ApiHelper.inflateLibLayout(mContext,
-                ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(mContext)),
+                ApiHelper.getLibTheme(mContext, MediaRouterThemeHelper.getRouterThemeId(mContext)),
                 R.layout.mr_controller_material_dialog_b));
 
         // Remove the neutral button.
@@ -359,13 +359,13 @@
         int color = MediaRouterThemeHelper.getButtonTextColor(mContext);
         mDisconnectButton = findViewById(BUTTON_DISCONNECT_RES_ID);
         mDisconnectButton.setText(
-                ApiHelper.getLibResources().getString(R.string.mr_controller_disconnect));
+                ApiHelper.getLibResources(mContext).getString(R.string.mr_controller_disconnect));
         mDisconnectButton.setTextColor(color);
         mDisconnectButton.setOnClickListener(listener);
 
         mStopCastingButton = findViewById(BUTTON_STOP_RES_ID);
         mStopCastingButton.setText(
-                ApiHelper.getLibResources().getString(R.string.mr_controller_stop_casting));
+                ApiHelper.getLibResources(mContext).getString(R.string.mr_controller_stop_casting));
         mStopCastingButton.setTextColor(color);
         mStopCastingButton.setOnClickListener(listener);
 
@@ -440,11 +440,11 @@
             }
         });
         loadInterpolator();
-        mGroupListAnimationDurationMs = ApiHelper.getLibResources().getInteger(
+        mGroupListAnimationDurationMs = ApiHelper.getLibResources(mContext).getInteger(
                 R.integer.mr_controller_volume_group_list_animation_duration_ms);
-        mGroupListFadeInDurationMs = ApiHelper.getLibResources().getInteger(
+        mGroupListFadeInDurationMs = ApiHelper.getLibResources(mContext).getInteger(
                 R.integer.mr_controller_volume_group_list_fade_in_duration_ms);
-        mGroupListFadeOutDurationMs = ApiHelper.getLibResources().getInteger(
+        mGroupListFadeOutDurationMs = ApiHelper.getLibResources(mContext).getInteger(
                 R.integer.mr_controller_volume_group_list_fade_out_duration_ms);
 
         mCustomControlView = onCreateMediaControlView(savedInstanceState);
@@ -460,13 +460,13 @@
      * Sets the width of the dialog. Also called when configuration changes.
      */
     void updateLayout() {
-        int width = MediaRouteDialogHelper.getDialogWidth();
+        int width = MediaRouteDialogHelper.getDialogWidth(mContext);
         getWindow().setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT);
 
         View decorView = getWindow().getDecorView();
         mDialogContentWidth = width - decorView.getPaddingLeft() - decorView.getPaddingRight();
 
-        Resources res = ApiHelper.getLibResources();
+        Resources res = ApiHelper.getLibResources(mContext);
         mVolumeGroupListItemIconSize = res.getDimensionPixelSize(
                 R.dimen.mr_controller_volume_group_list_item_icon_size);
         mVolumeGroupListItemHeight = res.getDimensionPixelSize(
@@ -991,16 +991,16 @@
             if (mRoute.getPresentationDisplayId()
                     != MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE) {
                 // The user is currently casting screen.
-                mTitleView.setText(ApiHelper.getLibResources().getString(
+                mTitleView.setText(ApiHelper.getLibResources(mContext).getString(
                         R.string.mr_controller_casting_screen));
                 showTitle = true;
             } else if (mState == null || mState.getState() == PlaybackStateCompat.STATE_NONE) {
                 // Show "No media selected" as we don't yet know the playback state.
-                mTitleView.setText(ApiHelper.getLibResources().getString(
+                mTitleView.setText(ApiHelper.getLibResources(mContext).getString(
                         R.string.mr_controller_no_media_selected));
                 showTitle = true;
             } else if (!hasTitle && !hasSubtitle) {
-                mTitleView.setText(ApiHelper.getLibResources().getString(
+                mTitleView.setText(ApiHelper.getLibResources(mContext).getString(
                         R.string.mr_controller_no_info_available));
                 showTitle = true;
             } else {
@@ -1223,7 +1223,8 @@
                                 AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
                         event.setPackageName(mContext.getPackageName());
                         event.setClassName(getClass().getName());
-                        event.getText().add(ApiHelper.getLibResources().getString(actionDescResId));
+                        event.getText().add(
+                                ApiHelper.getLibResources(mContext).getString(actionDescResId));
                         mAccessibilityManager.sendAccessibilityEvent(event);
                     }
                 }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java
index 62c050b..9aabf7b 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java
@@ -41,12 +41,13 @@
      * The framework should set the dialog width properly, but somehow it doesn't work, hence
      * duplicating a similar logic here to determine the appropriate dialog width.
      */
-    public static int getDialogWidth() {
-        DisplayMetrics metrics = ApiHelper.getLibResources().getDisplayMetrics();
+    public static int getDialogWidth(Context context) {
+        DisplayMetrics metrics = ApiHelper.getLibResources(context).getDisplayMetrics();
         boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
 
         TypedValue value = new TypedValue();
-        ApiHelper.getLibResources().getValue(isPortrait ? R.dimen.mr_dialog_fixed_width_minor
+        ApiHelper.getLibResources(context).getValue(isPortrait
+                ? R.dimen.mr_dialog_fixed_width_minor
                 : R.dimen.mr_dialog_fixed_width_major, value, true);
         if (value.type == TypedValue.TYPE_DIMENSION) {
             return (int) value.getDimension(metrics);
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
index defeedb..6a0a95a 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
@@ -51,9 +51,9 @@
     public MediaRouteExpandCollapseButton(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mExpandAnimationDrawable = (AnimationDrawable)
-                ApiHelper.getLibResources().getDrawable(R.drawable.mr_group_expand);
+                ApiHelper.getLibResources(context).getDrawable(R.drawable.mr_group_expand);
         mCollapseAnimationDrawable = (AnimationDrawable)
-                ApiHelper.getLibResources().getDrawable(R.drawable.mr_group_collapse);
+                ApiHelper.getLibResources(context).getDrawable(R.drawable.mr_group_collapse);
 
         ColorFilter filter = new PorterDuffColorFilter(
                 MediaRouterThemeHelper.getControllerColor(context, defStyleAttr),
@@ -62,9 +62,9 @@
         mCollapseAnimationDrawable.setColorFilter(filter);
 
         mExpandGroupDescription =
-                ApiHelper.getLibResources().getString(R.string.mr_controller_expand_group);
+                ApiHelper.getLibResources(context).getString(R.string.mr_controller_expand_group);
         mCollapseGroupDescription =
-                ApiHelper.getLibResources().getString(R.string.mr_controller_collapse_group);
+                ApiHelper.getLibResources(context).getString(R.string.mr_controller_collapse_group);
 
         setImageDrawable(mExpandAnimationDrawable.getFrame(0));
         setContentDescription(mExpandGroupDescription);
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
index 33d92b4..a38491f 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
@@ -267,7 +267,7 @@
             mCallbackObj = createCallbackObj();
             mVolumeCallbackObj = createVolumeCallbackObj();
 
-            Resources r = ApiHelper.getLibResources();
+            Resources r = ApiHelper.getLibResources(context);
             mUserRouteCategoryObj = MediaRouterJellybean.createRouteCategory(
                     mRouterObj, r.getString(R.string.mr_user_route_category_name), false);
 
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 16707c6..1cc407b 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -194,7 +194,7 @@
 
     @Override
     public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        mResources = ApiHelper.getLibResources();
+        mResources = ApiHelper.getLibResources(mInstance.getContext());
         // Inflate MediaControlView2 from XML
         mRoot = makeControllerView();
         mInstance.addView(mRoot);