blob: 10fc685015b7f3ca829a09878f6f6b4d32f87dbc [file] [log] [blame]
/*
* Copyright (C) 2018 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.settingslib.search;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.SimpleElementVisitor8;
import javax.tools.Diagnostic.Kind;
/**
* Annotation processor for {@link SearchIndexable} that generates {@link SearchIndexableResources}
* subclasses.
*/
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.android.settingslib.search.SearchIndexable"})
public class IndexableProcessor extends AbstractProcessor {
private static final String PACKAGE = "com.android.settingslib.search";
private static final String CLASS_BASE = "SearchIndexableResourcesBase";
private static final String CLASS_MOBILE = "SearchIndexableResourcesMobile";
private static final String CLASS_TV = "SearchIndexableResourcesTv";
private static final String CLASS_WEAR = "SearchIndexableResourcesWear";
private static final String CLASS_AUTO = "SearchIndexableResourcesAuto";
private static final String CLASS_ARC = "SearchIndexableResourcesArc";
private Filer mFiler;
private Messager mMessager;
private boolean mRanOnce;
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnvironment) {
if (mRanOnce) {
// Will get called once per round, but we only want to run on the first one.
return true;
}
mRanOnce = true;
final FieldSpec providers = FieldSpec.builder(
ParameterizedTypeName.get(
ClassName.get(Set.class),
TypeName.get(Class.class)),
"mProviders",
Modifier.PRIVATE, Modifier.FINAL)
.initializer("new $T()", HashSet.class)
.build();
final MethodSpec addIndex = MethodSpec.methodBuilder("addIndex")
.addModifiers(Modifier.PUBLIC)
.addParameter(ClassName.get(Class.class), "indexClass")
.addCode("$N.add(indexClass);\n", providers)
.build();
final MethodSpec.Builder baseConstructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
final MethodSpec.Builder mobileConstructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
final MethodSpec.Builder tvConstructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
final MethodSpec.Builder wearConstructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
final MethodSpec.Builder autoConstructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
final MethodSpec.Builder arcConstructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
for (Element element : roundEnvironment.getElementsAnnotatedWith(SearchIndexable.class)) {
if (element.getKind().isClass()) {
Name className = element.accept(new SimpleElementVisitor8<Name, Void>() {
@Override
public Name visitType(TypeElement typeElement, Void aVoid) {
return typeElement.getQualifiedName();
}
}, null);
if (className != null) {
SearchIndexable searchIndexable = element.getAnnotation(SearchIndexable.class);
int forTarget = searchIndexable.forTarget();
if (forTarget == SearchIndexable.ALL) {
baseConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
} else if ((forTarget & SearchIndexable.MOBILE) != 0) {
mobileConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
} else if ((forTarget & SearchIndexable.TV) != 0) {
tvConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
} else if ((forTarget & SearchIndexable.WEAR) != 0) {
wearConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
} else if ((forTarget & SearchIndexable.AUTO) != 0) {
autoConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
} else if ((forTarget & SearchIndexable.ARC) != 0) {
arcConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
}
} else {
throw new IllegalStateException("Null classname from " + element);
}
}
}
final MethodSpec getProviderValues = MethodSpec.methodBuilder("getProviderValues")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(ParameterizedTypeName.get(
ClassName.get(Collection.class),
TypeName.get(Class.class)))
.addCode("return $N;\n", providers)
.build();
final TypeSpec baseClass = TypeSpec.classBuilder(CLASS_BASE)
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(ClassName.get(SearchIndexableResources.class))
.addField(providers)
.addMethod(baseConstructorBuilder.build())
.addMethod(addIndex)
.addMethod(getProviderValues)
.build();
final JavaFile searchIndexableResourcesBase = JavaFile.builder(PACKAGE, baseClass).build();
final JavaFile searchIndexableResourcesMobile = JavaFile.builder(PACKAGE,
TypeSpec.classBuilder(CLASS_MOBILE)
.addModifiers(Modifier.PUBLIC)
.superclass(ClassName.get(PACKAGE, baseClass.name))
.addMethod(mobileConstructorBuilder.build())
.build())
.build();
final JavaFile searchIndexableResourcesTv = JavaFile.builder(PACKAGE,
TypeSpec.classBuilder(CLASS_TV)
.addModifiers(Modifier.PUBLIC)
.superclass(ClassName.get(PACKAGE, baseClass.name))
.addMethod(tvConstructorBuilder.build())
.build())
.build();
final JavaFile searchIndexableResourcesWear = JavaFile.builder(PACKAGE,
TypeSpec.classBuilder(CLASS_WEAR)
.addModifiers(Modifier.PUBLIC)
.superclass(ClassName.get(PACKAGE, baseClass.name))
.addMethod(wearConstructorBuilder.build())
.build())
.build();
final JavaFile searchIndexableResourcesAuto = JavaFile.builder(PACKAGE,
TypeSpec.classBuilder(CLASS_AUTO)
.addModifiers(Modifier.PUBLIC)
.superclass(ClassName.get(PACKAGE, baseClass.name))
.addMethod(autoConstructorBuilder.build())
.build())
.build();
final JavaFile searchIndexableResourcesArc = JavaFile.builder(PACKAGE,
TypeSpec.classBuilder(CLASS_ARC)
.addModifiers(Modifier.PUBLIC)
.superclass(ClassName.get(PACKAGE, baseClass.name))
.addMethod(arcConstructorBuilder.build())
.build())
.build();
try {
searchIndexableResourcesBase.writeTo(mFiler);
searchIndexableResourcesMobile.writeTo(mFiler);
searchIndexableResourcesTv.writeTo(mFiler);
searchIndexableResourcesWear.writeTo(mFiler);
searchIndexableResourcesAuto.writeTo(mFiler);
searchIndexableResourcesArc.writeTo(mFiler);
} catch (IOException e) {
mMessager.printMessage(Kind.ERROR, "Error while writing file: " + e);
}
return true;
}
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mFiler = processingEnvironment.getFiler();
mMessager = processingEnvironment.getMessager();
}
}