1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.media.update; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.content.ContextWrapper; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.PackageManager.NameNotFoundException; 24 import android.content.res.Resources; 25 import android.content.res.Resources.Theme; 26 import android.content.res.XmlResourceParser; 27 import android.support.annotation.GuardedBy; 28 import android.support.v4.widget.Space; 29 import android.support.v7.widget.ButtonBarLayout; 30 import android.util.AttributeSet; 31 import android.view.ContextThemeWrapper; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 import android.view.ViewGroup; 35 36 import com.android.support.mediarouter.app.MediaRouteButton; 37 import com.android.support.mediarouter.app.MediaRouteExpandCollapseButton; 38 import com.android.support.mediarouter.app.MediaRouteVolumeSlider; 39 import com.android.support.mediarouter.app.OverlayListView; 40 41 public final class ApiHelper { 42 private static ApplicationInfo sUpdatableInfo; 43 44 @GuardedBy("this") 45 private static Theme sLibTheme; 46 ApiHelper()47 private ApiHelper() { } 48 initialize(ApplicationInfo updatableInfo)49 static void initialize(ApplicationInfo updatableInfo) { 50 if (sUpdatableInfo != null) { 51 throw new IllegalStateException("initialize should only be called once"); 52 } 53 54 sUpdatableInfo = updatableInfo; 55 } 56 getLibResources(Context context)57 public static Resources getLibResources(Context context) { 58 return getLibTheme(context).getResources(); 59 } 60 getLibTheme(Context context)61 public static Theme getLibTheme(Context context) { 62 if (sLibTheme != null) return sLibTheme; 63 64 return getLibThemeSynchronized(context); 65 } 66 getLibTheme(Context context, int themeId)67 public static Theme getLibTheme(Context context, int themeId) { 68 Theme theme = getLibResources(context).newTheme(); 69 theme.applyStyle(themeId, true); 70 return theme; 71 } 72 getLayoutInflater(Context context)73 public static LayoutInflater getLayoutInflater(Context context) { 74 return getLayoutInflater(context, null); 75 } 76 getLayoutInflater(Context context, Theme theme)77 public static LayoutInflater getLayoutInflater(Context context, Theme theme) { 78 if (theme == null) { 79 theme = getLibTheme(context); 80 } 81 82 // TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme. 83 LayoutInflater layoutInflater = LayoutInflater.from(context).cloneInContext( 84 new ContextThemeWrapper(context, theme)); 85 layoutInflater.setFactory2(new LayoutInflater.Factory2() { 86 @Override 87 public View onCreateView( 88 View parent, String name, Context context, AttributeSet attrs) { 89 if (MediaRouteButton.class.getCanonicalName().equals(name)) { 90 return new MediaRouteButton(context, attrs); 91 } else if (MediaRouteVolumeSlider.class.getCanonicalName().equals(name)) { 92 return new MediaRouteVolumeSlider(context, attrs); 93 } else if (MediaRouteExpandCollapseButton.class.getCanonicalName().equals(name)) { 94 return new MediaRouteExpandCollapseButton(context, attrs); 95 } else if (OverlayListView.class.getCanonicalName().equals(name)) { 96 return new OverlayListView(context, attrs); 97 } else if (ButtonBarLayout.class.getCanonicalName().equals(name)) { 98 return new ButtonBarLayout(context, attrs); 99 } else if (Space.class.getCanonicalName().equals(name)) { 100 return new Space(context, attrs); 101 } 102 return null; 103 } 104 105 @Override 106 public View onCreateView(String name, Context context, AttributeSet attrs) { 107 return onCreateView(null, name, context, attrs); 108 } 109 }); 110 return layoutInflater; 111 } 112 inflateLibLayout(Context context, int libResId)113 public static View inflateLibLayout(Context context, int libResId) { 114 return inflateLibLayout(context, getLibTheme(context), libResId, null, false); 115 } 116 inflateLibLayout(Context context, Theme theme, int libResId)117 public static View inflateLibLayout(Context context, Theme theme, int libResId) { 118 return inflateLibLayout(context, theme, libResId, null, false); 119 } 120 inflateLibLayout(Context context, Theme theme, int libResId, @Nullable ViewGroup root, boolean attachToRoot)121 public static View inflateLibLayout(Context context, Theme theme, int libResId, 122 @Nullable ViewGroup root, boolean attachToRoot) { 123 try (XmlResourceParser parser = getLibResources(context).getLayout(libResId)) { 124 return getLayoutInflater(context, theme).inflate(parser, root, attachToRoot); 125 } 126 } 127 getLibThemeSynchronized(Context context)128 private static synchronized Theme getLibThemeSynchronized(Context context) { 129 if (sLibTheme != null) return sLibTheme; 130 131 if (sUpdatableInfo == null) { 132 throw new IllegalStateException("initialize hasn't been called yet"); 133 } 134 135 try { 136 return sLibTheme = context.getPackageManager() 137 .getResourcesForApplication(sUpdatableInfo).newTheme(); 138 } catch (NameNotFoundException e) { 139 throw new RuntimeException(e); 140 } 141 } 142 } 143