LayoutInflaterBuilder helper in systemui util
Useful for tests that want to inflate production layouts but with some classes replaced with Testable/Mock instances. Located in SystemUI until more clients can be found. Test: See ag/1630107 Change-Id: I4addb4cb4adfdf8c3e8f065dd3926574dc352e84
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Builder class to create a {@link LayoutInflater} with various properties.
|
||||
*
|
||||
* Call any desired configuration methods on the Builder and then use
|
||||
* {@link Builder#build} to create the LayoutInflater. This is an alternative to directly using
|
||||
* {@link LayoutInflater#setFilter} and {@link LayoutInflater#setFactory}.
|
||||
* @hide for use by framework
|
||||
*/
|
||||
public class LayoutInflaterBuilder {
|
||||
private static final String TAG = "LayoutInflaterBuilder";
|
||||
|
||||
private Context mFromContext;
|
||||
private Context mTargetContext;
|
||||
private Map<String, String> mReplaceMap;
|
||||
private Set<Class> mDisallowedClasses;
|
||||
private LayoutInflater mBuiltInflater;
|
||||
|
||||
/**
|
||||
* Creates a new Builder which will construct a LayoutInflater.
|
||||
*
|
||||
* @param fromContext This context's LayoutInflater will be cloned by the Builder using
|
||||
* {@link LayoutInflater#cloneInContext}. By default, the new LayoutInflater will point at
|
||||
* this same Context.
|
||||
*/
|
||||
public LayoutInflaterBuilder(@NonNull Context fromContext) {
|
||||
mFromContext = fromContext;
|
||||
mTargetContext = fromContext;
|
||||
mReplaceMap = null;
|
||||
mDisallowedClasses = null;
|
||||
mBuiltInflater = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the Builder to point the LayoutInflater at a different Context.
|
||||
*
|
||||
* @param targetContext Context to be provided to
|
||||
* {@link LayoutInflater#cloneInContext(Context)}.
|
||||
* @return Builder object post-modification.
|
||||
*/
|
||||
public LayoutInflaterBuilder target(@NonNull Context targetContext) {
|
||||
assertIfAlreadyBuilt();
|
||||
mTargetContext = targetContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the Builder to configure the LayoutInflater such that all instances
|
||||
* of one {@link View} will be replaced with instances of another during inflation.
|
||||
*
|
||||
* @param from Instances of this class will be replaced during inflation.
|
||||
* @param to Instances of this class will be inflated as replacements.
|
||||
* @return Builder object post-modification.
|
||||
*/
|
||||
public LayoutInflaterBuilder replace(@NonNull Class from, @NonNull Class to) {
|
||||
assertIfAlreadyBuilt();
|
||||
if (mReplaceMap == null) {
|
||||
mReplaceMap = new ArrayMap<String, String>();
|
||||
}
|
||||
mReplaceMap.put(from.getName(), to.getName());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the Builder to configure the LayoutInflater such that any attempt to inflate
|
||||
* a {@link View} of a given type will throw a {@link InflateException}.
|
||||
*
|
||||
* @param disallowedClass The Class type that will be disallowed.
|
||||
* @return Builder object post-modification.
|
||||
*/
|
||||
public LayoutInflaterBuilder disallow(@NonNull Class disallowedClass) {
|
||||
assertIfAlreadyBuilt();
|
||||
if (mDisallowedClasses == null) {
|
||||
mDisallowedClasses = new ArraySet<Class>();
|
||||
}
|
||||
mDisallowedClasses.add(disallowedClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the LayoutInflater. Afterwards, this Builder can no longer can be
|
||||
* used, all future calls on the Builder will throw {@link AssertionError}.
|
||||
*/
|
||||
public LayoutInflater build() {
|
||||
assertIfAlreadyBuilt();
|
||||
mBuiltInflater =
|
||||
LayoutInflater.from(mFromContext).cloneInContext(mTargetContext);
|
||||
setFactoryIfNeeded(mBuiltInflater);
|
||||
setFilterIfNeeded(mBuiltInflater);
|
||||
return mBuiltInflater;
|
||||
}
|
||||
|
||||
private void assertIfAlreadyBuilt() {
|
||||
if (mBuiltInflater != null) {
|
||||
throw new AssertionError("Cannot use this Builder after build() has been called.");
|
||||
}
|
||||
}
|
||||
|
||||
private void setFactoryIfNeeded(LayoutInflater inflater) {
|
||||
if (mReplaceMap == null) {
|
||||
return;
|
||||
}
|
||||
inflater.setFactory(
|
||||
new LayoutInflater.Factory() {
|
||||
@Override
|
||||
public View onCreateView(String name, Context context, AttributeSet attrs) {
|
||||
String replacingClassName = mReplaceMap.get(name);
|
||||
if (replacingClassName != null) {
|
||||
try {
|
||||
return inflater.createView(replacingClassName, null, attrs);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(TAG, "Could not replace " + name
|
||||
+ " with " + replacingClassName
|
||||
+ ", Exception: ", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFilterIfNeeded(LayoutInflater inflater) {
|
||||
if (mDisallowedClasses == null) {
|
||||
return;
|
||||
}
|
||||
inflater.setFilter(
|
||||
new LayoutInflater.Filter() {
|
||||
@Override
|
||||
public boolean onLoadClass(Class clazz) {
|
||||
return !mDisallowedClasses.contains(clazz);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user