LayoutInflaterBuilder.java revision 3cfedd78b1e3704481de27d7354cb29b2fb43781
1847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch/* 2847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Copyright (C) 2016 The Android Open Source Project 3847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 4847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Licensed under the Apache License, Version 2.0 (the "License"); 5847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * you may not use this file except in compliance with the License. 6847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * You may obtain a copy of the License at 7847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 8847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * http://www.apache.org/licenses/LICENSE-2.0 9847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 10847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Unless required by applicable law or agreed to in writing, software 11847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * distributed under the License is distributed on an "AS IS" BASIS, 12847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * See the License for the specific language governing permissions and 14847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * limitations under the License. 15847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch */ 16847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 17847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschpackage com.android.systemui.util; 18847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 19847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.annotation.NonNull; 20847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.content.Context; 21847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.util.ArrayMap; 22847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.util.ArraySet; 23847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.util.AttributeSet; 24847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.util.Log; 25847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.view.LayoutInflater; 26847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport android.view.View; 27847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport java.util.Map; 28847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschimport java.util.Set; 29847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 30847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch/** 31847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Builder class to create a {@link LayoutInflater} with various properties. 32847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 33847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Call any desired configuration methods on the Builder and then use 34847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * {@link Builder#build} to create the LayoutInflater. This is an alternative to directly using 35847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * {@link LayoutInflater#setFilter} and {@link LayoutInflater#setFactory}. 36847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @hide for use by framework 37847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch */ 38847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitschpublic class LayoutInflaterBuilder { 39847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private static final String TAG = "LayoutInflaterBuilder"; 40847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 41847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private Context mFromContext; 42847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private Context mTargetContext; 43847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private Map<String, String> mReplaceMap; 44847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private Set<Class> mDisallowedClasses; 45847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private LayoutInflater mBuiltInflater; 46847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 47847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch /** 48847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Creates a new Builder which will construct a LayoutInflater. 49847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 50847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @param fromContext This context's LayoutInflater will be cloned by the Builder using 51847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * {@link LayoutInflater#cloneInContext}. By default, the new LayoutInflater will point at 52847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * this same Context. 53847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch */ 54847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch public LayoutInflaterBuilder(@NonNull Context fromContext) { 55847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mFromContext = fromContext; 56847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mTargetContext = fromContext; 57847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mReplaceMap = null; 58847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mDisallowedClasses = null; 59847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mBuiltInflater = null; 60847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 61847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 62847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch /** 63847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Instructs the Builder to point the LayoutInflater at a different Context. 64847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 65847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @param targetContext Context to be provided to 66847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * {@link LayoutInflater#cloneInContext(Context)}. 67847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @return Builder object post-modification. 68847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch */ 69847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch public LayoutInflaterBuilder target(@NonNull Context targetContext) { 70847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch assertIfAlreadyBuilt(); 71847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mTargetContext = targetContext; 72847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return this; 73847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 74847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 75847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch /** 76847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Instructs the Builder to configure the LayoutInflater such that all instances 77847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * of one {@link View} will be replaced with instances of another during inflation. 78847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 79847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @param from Instances of this class will be replaced during inflation. 80847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @param to Instances of this class will be inflated as replacements. 81847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @return Builder object post-modification. 82847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch */ 83847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch public LayoutInflaterBuilder replace(@NonNull Class from, @NonNull Class to) { 843cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk return replace(from.getName(), to); 853cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk } 863cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk 873cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk /** 883cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk * Instructs the Builder to configure the LayoutInflater such that all instances 893cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk * of one {@link View} will be replaced with instances of another during inflation. 903cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk * 913cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk * @param tag Instances of this tag will be replaced during inflation. 923cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk * @param to Instances of this class will be inflated as replacements. 933cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk * @return Builder object post-modification. 943cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk */ 953cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk public LayoutInflaterBuilder replace(@NonNull String tag, @NonNull Class to) { 96847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch assertIfAlreadyBuilt(); 97847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch if (mReplaceMap == null) { 98847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mReplaceMap = new ArrayMap<String, String>(); 99847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 1003cfedd78b1e3704481de27d7354cb29b2fb43781Jason Monk mReplaceMap.put(tag, to.getName()); 101847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return this; 102847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 103847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 104847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch /** 105847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Instructs the Builder to configure the LayoutInflater such that any attempt to inflate 106847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * a {@link View} of a given type will throw a {@link InflateException}. 107847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * 108847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @param disallowedClass The Class type that will be disallowed. 109847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * @return Builder object post-modification. 110847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch */ 111847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch public LayoutInflaterBuilder disallow(@NonNull Class disallowedClass) { 112847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch assertIfAlreadyBuilt(); 113847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch if (mDisallowedClasses == null) { 114847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mDisallowedClasses = new ArraySet<Class>(); 115847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 116847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mDisallowedClasses.add(disallowedClass); 117847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return this; 118847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 119847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 120847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch /** 121847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * Builds and returns the LayoutInflater. Afterwards, this Builder can no longer can be 122847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch * used, all future calls on the Builder will throw {@link AssertionError}. 123847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch */ 124847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch public LayoutInflater build() { 125847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch assertIfAlreadyBuilt(); 126847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch mBuiltInflater = 127847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch LayoutInflater.from(mFromContext).cloneInContext(mTargetContext); 128847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch setFactoryIfNeeded(mBuiltInflater); 129847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch setFilterIfNeeded(mBuiltInflater); 130847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return mBuiltInflater; 131847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 132847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 133847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private void assertIfAlreadyBuilt() { 134847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch if (mBuiltInflater != null) { 135847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch throw new AssertionError("Cannot use this Builder after build() has been called."); 136847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 137847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 138847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 139847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private void setFactoryIfNeeded(LayoutInflater inflater) { 140847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch if (mReplaceMap == null) { 141847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return; 142847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 143847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch inflater.setFactory( 144847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch new LayoutInflater.Factory() { 145847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch @Override 146847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch public View onCreateView(String name, Context context, AttributeSet attrs) { 147847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch String replacingClassName = mReplaceMap.get(name); 148847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch if (replacingClassName != null) { 149847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch try { 150847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return inflater.createView(replacingClassName, null, attrs); 151847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } catch (ClassNotFoundException e) { 152847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch Log.e(TAG, "Could not replace " + name 153847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch + " with " + replacingClassName 154847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch + ", Exception: ", e); 155847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 156847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 157847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return null; 158847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 159847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch }); 160847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 161847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch 162847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch private void setFilterIfNeeded(LayoutInflater inflater) { 163847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch if (mDisallowedClasses == null) { 164847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return; 165847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 166847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch inflater.setFilter( 167847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch new LayoutInflater.Filter() { 168847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch @Override 169847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch public boolean onLoadClass(Class clazz) { 170847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch return !mDisallowedClasses.contains(clazz); 171847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 172847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch }); 173847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch } 174847eb5aba868661b258c8b59cd70ded5264c49fdGeoffrey Pitsch} 175