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