/**
* 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.JExpr;
import com.sun.codemodel.JExpression;
import org.androidtransfuse.adapter.ASTMethod;
import org.androidtransfuse.adapter.ASTType;
import org.androidtransfuse.adapter.PackageClass;
import org.androidtransfuse.adapter.classes.ASTClassFactory;
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.FragmentFactoryGenerator;
import org.androidtransfuse.experiment.generators.FragmentLayoutGenerator;
import org.androidtransfuse.experiment.generators.ObservesExpressionGenerator;
import org.androidtransfuse.experiment.generators.OnCreateInjectionGenerator;
import org.androidtransfuse.gen.componentBuilder.ComponentBuilderFactory;
import org.androidtransfuse.gen.componentBuilder.ListenerRegistrationGenerator;
import org.androidtransfuse.gen.variableBuilder.*;
import org.androidtransfuse.util.AndroidLiterals;
import javax.inject.Inject;
import javax.lang.model.type.TypeMirror;
import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror;
/**
* @author John Ericksen
*/
public class FragmentAnalysis implements Analysis<ComponentDescriptor> {
private final ASTClassFactory astClassFactory;
private final ASTElementFactory astElementFactory;
private final AnalysisContextFactory analysisContextFactory;
private final InjectionBindingBuilder injectionBindingBuilder;
private final ASTTypeBuilderVisitor astTypeBuilderVisitor;
private final InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory;
private final ComponentBuilderFactory componentBuilderFactory;
private final ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory;
private final ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory;
private final ExtraInjectionNodeBuilder.ExtraInjectionNodeBuilderFactory extraInjectionNodeBuilderFactory;
private final SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder;
private final ResourceInjectionNodeBuilder resourceInjectionNodeBuilder;
private final PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder;
private final FragmentViewInjectionNodeBuilder fragmentViewInjectionNodeBuilder;
private final OnCreateInjectionGenerator.InjectionGeneratorFactory injectionGeneratorFactory;
private final FragmentLayoutGenerator fragmentLayoutGenerator;
private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory;
private final ComponentAnalysis componentAnalysis;
private final FragmentFactoryGenerator fragmentFactoryGenerator;
@Inject
public FragmentAnalysis(ASTClassFactory astClassFactory,
ASTElementFactory astElementFactory,
AnalysisContextFactory analysisContextFactory,
InjectionBindingBuilder injectionBindingBuilder,
ASTTypeBuilderVisitor astTypeBuilderVisitor,
InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory,
ComponentBuilderFactory componentBuilderFactory,
ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory,
ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory,
ExtraInjectionNodeBuilder.ExtraInjectionNodeBuilderFactory extraInjectionNodeBuilderFactory,
SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder,
ResourceInjectionNodeBuilder resourceInjectionNodeBuilder,
PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder,
FragmentViewInjectionNodeBuilder fragmentViewInjectionNodeBuilder,
OnCreateInjectionGenerator.InjectionGeneratorFactory injectionGeneratorFactory,
FragmentLayoutGenerator fragmentLayoutGenerator,
ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory,
ComponentAnalysis componentAnalysis,
FragmentFactoryGenerator fragmentFactoryGenerator) {
this.astClassFactory = astClassFactory;
this.astElementFactory = astElementFactory;
this.analysisContextFactory = analysisContextFactory;
this.injectionBindingBuilder = injectionBindingBuilder;
this.astTypeBuilderVisitor = astTypeBuilderVisitor;
this.injectionNodeBuilderRepositoryFactory = injectionNodeBuilderRepositoryFactory;
this.componentBuilderFactory = componentBuilderFactory;
this.extraInjectionNodeBuilderFactory = extraInjectionNodeBuilderFactory;
this.systemServiceBindingInjectionNodeBuilder = systemServiceBindingInjectionNodeBuilder;
this.resourceInjectionNodeBuilder = resourceInjectionNodeBuilder;
this.preferenceInjectionNodeBuilder = preferenceInjectionNodeBuilder;
this.fragmentViewInjectionNodeBuilder = fragmentViewInjectionNodeBuilder;
this.listenerRegistrationGeneratorFactory = listenerRegistrationGeneratorFactory;
this.observesExpressionGeneratorFactory = observesExpressionGeneratorFactory;
this.injectionGeneratorFactory = injectionGeneratorFactory;
this.fragmentLayoutGenerator = fragmentLayoutGenerator;
this.scopesGenerationFactory = scopesGenerationFactory;
this.componentAnalysis = componentAnalysis;
this.fragmentFactoryGenerator = fragmentFactoryGenerator;
}
@Override
public ComponentDescriptor analyze(ASTType astType) {
Fragment fragmentAnnotation = astType.getAnnotation(Fragment.class);
PackageClass fragmentClassName;
ComponentDescriptor fragmentDescriptor = null;
if (!astType.inherits(AndroidLiterals.FRAGMENT)) {
//generated Android fragment
fragmentClassName = componentAnalysis.buildComponentPackageClass(astType, fragmentAnnotation.name(), "Fragment");
TypeMirror type = getTypeMirror(fragmentAnnotation, "type");
ASTType fragmentType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.FRAGMENT : type.accept(astTypeBuilderVisitor, null);
AnalysisContext context = analysisContextFactory.buildAnalysisContext(buildVariableBuilderMap(fragmentType));
fragmentDescriptor = new ComponentDescriptor(astType, fragmentType, fragmentClassName, context);
componentAnalysis.setupGenerators(fragmentDescriptor, fragmentType, Fragment.class);
//application generation profile
setupFragmentProfile(fragmentDescriptor, astType);
}
return fragmentDescriptor;
}
private void setupFragmentProfile(ComponentDescriptor fragmentDescriptor, ASTType astType) {
ASTMethod onCreateViewMethod = getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE);
fragmentDescriptor.getGenerators().add(injectionGeneratorFactory.build(onCreateViewMethod, astType));
fragmentDescriptor.getGenerators().add(scopesGenerationFactory.build(onCreateViewMethod));
fragmentDescriptor.getGenerators().add(fragmentLayoutGenerator);
fragmentDescriptor.getGenerators().add(fragmentFactoryGenerator);
// onSaveInstanceState
ASTMethod onSaveInstanceStateMethod = getASTMethod("onSaveInstanceState", AndroidLiterals.BUNDLE);
fragmentDescriptor.getGenerators().add(componentBuilderFactory.buildFragmentOnSaveInstanceStateMethodCallbackGenerator(astClassFactory.getType(OnSaveInstanceState.class), onSaveInstanceStateMethod, getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE)));
fragmentDescriptor.getGenerators().add(listenerRegistrationGeneratorFactory.build(getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE)));
fragmentDescriptor.getGenerators().add(observesExpressionGeneratorFactory.build(
getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE),
getASTMethod("onDestroy"),
getASTMethod("onResume"),
getASTMethod("onPause")
));
}
private ASTMethod getASTMethod(String methodName, ASTType... args) {
return getASTMethod(AndroidLiterals.FRAGMENT, methodName, args);
}
private ASTMethod getASTMethod(ASTType type, String methodName, ASTType... args) {
return astElementFactory.findMethod(type, methodName, args);
}
private InjectionNodeBuilderRepository buildVariableBuilderMap(ASTType fragmentType) {
InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(fragmentType, Fragment.class);
injectionNodeBuilderRepository.putType(AndroidLiterals.FRAGMENT, injectionBindingBuilder.buildThis(AndroidLiterals.FRAGMENT));
injectionNodeBuilderRepository.putType(AndroidLiterals.ACTIVITY, injectionBindingBuilder.dependency(AndroidLiterals.FRAGMENT).invoke(AndroidLiterals.ACTIVITY, "getActivity").build());
injectionNodeBuilderRepository.putType(AndroidLiterals.CONTEXT, injectionBindingBuilder.dependency(AndroidLiterals.FRAGMENT).invoke(AndroidLiterals.CONTEXT, "getActivity").build());
injectionNodeBuilderRepository.putType(AndroidLiterals.FRAGMENT_MANAGER, injectionBindingBuilder.dependency(AndroidLiterals.FRAGMENT).invoke(AndroidLiterals.FRAGMENT_MANAGER, "getFragmentManager").build());
while(!fragmentType.equals(AndroidLiterals.FRAGMENT) && fragmentType.inherits(AndroidLiterals.FRAGMENT)){
injectionNodeBuilderRepository.putType(fragmentType, injectionBindingBuilder.buildThis(fragmentType));
fragmentType = fragmentType.getSuperClass();
}
injectionNodeBuilderRepository.putAnnotation(Extra.class, extraInjectionNodeBuilderFactory.build(new ExtraVariableBuilder.GetExtraExpressionBuilder() {
@Override
public JExpression buildGetExtraBundle(JExpression expression) {
return JExpr._this().invoke("getArguments");
}
}));
injectionNodeBuilderRepository.putAnnotation(Resource.class, resourceInjectionNodeBuilder);
injectionNodeBuilderRepository.putAnnotation(SystemService.class, systemServiceBindingInjectionNodeBuilder);
injectionNodeBuilderRepository.putAnnotation(Preference.class, preferenceInjectionNodeBuilder);
injectionNodeBuilderRepository.putAnnotation(org.androidtransfuse.annotations.View.class, fragmentViewInjectionNodeBuilder);
injectionNodeBuilderRepository.addRepository(injectionNodeBuilderRepositoryFactory.buildModuleConfiguration());
return injectionNodeBuilderRepository;
}
}