/** * Copyright 2011-2015 John Ericksen * * 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 org.androidtransfuse.analysis; import com.sun.codemodel.JExpression; import org.androidtransfuse.adapter.ASTMethod; import org.androidtransfuse.adapter.ASTType; import org.androidtransfuse.adapter.PackageClass; import org.androidtransfuse.adapter.element.ASTElementFactory; import org.androidtransfuse.adapter.element.ASTTypeBuilderVisitor; import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository; import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepositoryFactory; import org.androidtransfuse.annotations.*; import org.androidtransfuse.experiment.ComponentDescriptor; import org.androidtransfuse.experiment.ScopesGeneration; import org.androidtransfuse.experiment.generators.*; import org.androidtransfuse.gen.GeneratorFactory; import org.androidtransfuse.gen.componentBuilder.ListenerRegistrationGenerator; import org.androidtransfuse.gen.componentBuilder.NonConfigurationInstanceGenerator; import org.androidtransfuse.gen.variableBuilder.*; import org.androidtransfuse.intentFactory.ActivityIntentFactoryStrategy; import org.androidtransfuse.util.AndroidLiterals; import javax.inject.Inject; import javax.inject.Provider; import javax.lang.model.type.TypeMirror; import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror; /** * Activity related Analysis * * @author John Ericksen */ public class ActivityAnalysis implements Analysis<ComponentDescriptor> { private final InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory; private final AnalysisContextFactory analysisContextFactory; private final ASTElementFactory astElementFactory; private final ASTTypeBuilderVisitor astTypeBuilderVisitor; private final InjectionBindingBuilder injectionBindingBuilder; private final ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory; private final ViewInjectionNodeBuilder viewVariableBuilder; private final ExtraInjectionNodeBuilder.ExtraInjectionNodeBuilderFactory extraInjectionNodeBuilderFactory; private final SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder; private final ResourceInjectionNodeBuilder resourceInjectionNodeBuilder; private final PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder; private final Provider<ActivityManifestEntryGenerator> manifestGeneratorProvider; private final LayoutGenerator layoutGenerator; private final LayoutHandlerGenerator layoutHandlerGenerator; private final WindowFeatureGenerator windowFeatureGenerator; private final GeneratorFactory generatorFactory; private final ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listerRegistrationGeneratorFactory; private final NonConfigurationInstanceGenerator.NonconfigurationInstanceGeneratorFactory nonConfigurationInstanceGeneratorFactory; private final OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory; private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory; private final ComponentAnalysis componentAnalysis; private final IntentFactoryGenerator intentFactoryGenerator; @Inject public ActivityAnalysis(InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory, AnalysisContextFactory analysisContextFactory, ASTElementFactory astElementFactory, ASTTypeBuilderVisitor astTypeBuilderVisitor, InjectionBindingBuilder injectionBindingBuilder, ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory, ViewInjectionNodeBuilder viewVariableBuilder, ExtraInjectionNodeBuilder.ExtraInjectionNodeBuilderFactory extraInjectionNodeBuilderFactory, SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder, ResourceInjectionNodeBuilder resourceInjectionNodeBuilder, PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder, Provider<ActivityManifestEntryGenerator> manifestGeneratorProvider, LayoutGenerator layoutGenerator, LayoutHandlerGenerator layoutHandlerGenerator, WindowFeatureGenerator windowFeatureGenerator, GeneratorFactory generatorFactory, ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listerRegistrationGeneratorFactory, NonConfigurationInstanceGenerator.NonconfigurationInstanceGeneratorFactory nonConfigurationInstanceGeneratorFactory, OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory, ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory, ComponentAnalysis componentAnalysis, IntentFactoryGenerator intentFactoryGenerator) { this.injectionNodeBuilderRepositoryFactory = injectionNodeBuilderRepositoryFactory; this.analysisContextFactory = analysisContextFactory; this.astElementFactory = astElementFactory; this.astTypeBuilderVisitor = astTypeBuilderVisitor; this.injectionBindingBuilder = injectionBindingBuilder; this.observesExpressionGeneratorFactory = observesExpressionGeneratorFactory; this.viewVariableBuilder = viewVariableBuilder; this.extraInjectionNodeBuilderFactory = extraInjectionNodeBuilderFactory; this.systemServiceBindingInjectionNodeBuilder = systemServiceBindingInjectionNodeBuilder; this.resourceInjectionNodeBuilder = resourceInjectionNodeBuilder; this.preferenceInjectionNodeBuilder = preferenceInjectionNodeBuilder; this.manifestGeneratorProvider = manifestGeneratorProvider; this.layoutGenerator = layoutGenerator; this.layoutHandlerGenerator = layoutHandlerGenerator; this.windowFeatureGenerator = windowFeatureGenerator; this.generatorFactory = generatorFactory; this.listerRegistrationGeneratorFactory = listerRegistrationGeneratorFactory; this.nonConfigurationInstanceGeneratorFactory = nonConfigurationInstanceGeneratorFactory; this.onCreateInjectionGeneratorFactory = onCreateInjectionGeneratorFactory; this.scopesGenerationFactory = scopesGenerationFactory; this.componentAnalysis = componentAnalysis; this.intentFactoryGenerator = intentFactoryGenerator; } public ComponentDescriptor analyze(ASTType input) { Activity activityAnnotation = input.getAnnotation(Activity.class); PackageClass activityClassName; ComponentDescriptor activityDescriptor; if (input.inherits(AndroidLiterals.ACTIVITY)) { //vanilla Android activity PackageClass activityPackageClass = input.getPackageClass(); activityClassName = componentAnalysis.buildComponentPackageClass(input, activityPackageClass.getClassName(), "Activity"); activityDescriptor = new ComponentDescriptor(input, null, activityClassName); } else { //generated Android activity activityClassName = componentAnalysis.buildComponentPackageClass(input, activityAnnotation.name(), "Activity"); TypeMirror type = getTypeMirror(activityAnnotation, "type"); ASTType activityType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.ACTIVITY : type.accept(astTypeBuilderVisitor, null); AnalysisContext context = analysisContextFactory.buildAnalysisContext(buildVariableBuilderMap(activityType)); activityDescriptor = new ComponentDescriptor(input, activityType, activityClassName, context); activityDescriptor.getGenerators().add(layoutGenerator); activityDescriptor.getGenerators().add(layoutHandlerGenerator); activityDescriptor.getGenerators().add(windowFeatureGenerator); activityDescriptor.getGenerators().add(scopesGenerationFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE))); activityDescriptor.getGenerators().add(onCreateInjectionGeneratorFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE), input)); activityDescriptor.getGenerators().add(intentFactoryGenerator); //extra intent factory activityDescriptor.getGenerators().add(generatorFactory.buildStrategyGenerator(ActivityIntentFactoryStrategy.class)); //listener registration activityDescriptor.getGenerators().add(listerRegistrationGeneratorFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE))); //non configuration instance update if(activityType.inherits(AndroidLiterals.FRAGMENT_ACTIVITY)){ activityDescriptor.getGenerators().add(nonConfigurationInstanceGeneratorFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE), AndroidLiterals.FRAGMENT_ACTIVITY, "getLastCustomNonConfigurationInstance", "onRetainCustomNonConfigurationInstance")); } else { activityDescriptor.getGenerators().add(nonConfigurationInstanceGeneratorFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE), AndroidLiterals.ACTIVITY, "getLastNonConfigurationInstance", "onRetainNonConfigurationInstance")); } componentAnalysis.setupGenerators(activityDescriptor, activityType, Activity.class); activityDescriptor.getGenerators().add(observesExpressionGeneratorFactory.build( getASTMethod("onCreate", AndroidLiterals.BUNDLE), getASTMethod("onDestroy"), getASTMethod("onResume"), getASTMethod("onPause"))); } //add manifest elements activityDescriptor.getGenerators().add(manifestGeneratorProvider.get()); return activityDescriptor; } private InjectionNodeBuilderRepository buildVariableBuilderMap(ASTType activityType) { InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(activityType, Activity.class); injectionNodeBuilderRepository.putType(AndroidLiterals.CONTEXT, injectionBindingBuilder.buildThis(AndroidLiterals.CONTEXT)); injectionNodeBuilderRepository.putType(AndroidLiterals.ACTIVITY, injectionBindingBuilder.buildThis(AndroidLiterals.ACTIVITY)); while(!activityType.equals(AndroidLiterals.ACTIVITY) && activityType.inherits(AndroidLiterals.ACTIVITY)){ injectionNodeBuilderRepository.putType(activityType, injectionBindingBuilder.buildThis(activityType)); activityType = activityType.getSuperClass(); } injectionNodeBuilderRepository.putAnnotation(Extra.class, extraInjectionNodeBuilderFactory.build(new ExtraVariableBuilder.GetExtraExpressionBuilder() { @Override public JExpression buildGetExtraBundle(JExpression expression) { return expression.invoke("getIntent").invoke("getExtras"); } })); injectionNodeBuilderRepository.putAnnotation(Resource.class, resourceInjectionNodeBuilder); injectionNodeBuilderRepository.putAnnotation(SystemService.class, systemServiceBindingInjectionNodeBuilder); injectionNodeBuilderRepository.putAnnotation(Preference.class, preferenceInjectionNodeBuilder); injectionNodeBuilderRepository.putAnnotation(View.class, viewVariableBuilder); injectionNodeBuilderRepository.addRepository( injectionNodeBuilderRepositoryFactory.buildModuleConfiguration()); return injectionNodeBuilderRepository; } private ASTMethod getASTMethod(String methodName, ASTType... args) { return getASTMethod(AndroidLiterals.ACTIVITY, methodName, args); } private ASTMethod getASTMethod(ASTType type, String methodName, ASTType... args) { return astElementFactory.findMethod(type, methodName, args); } }