173 lines
6.4 KiB
Java
173 lines
6.4 KiB
Java
/*
|
|
* Copyright (C) 2017 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 android.testing;
|
|
|
|
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) {
|
|
return replace(from.getName(), to);
|
|
}
|
|
|
|
/**
|
|
* 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 tag Instances of this tag 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 String tag, @NonNull Class to) {
|
|
assertIfAlreadyBuilt();
|
|
if (mReplaceMap == null) {
|
|
mReplaceMap = new ArrayMap<String, String>();
|
|
}
|
|
mReplaceMap.put(tag, 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);
|
|
}
|
|
});
|
|
}
|
|
}
|