001/** 002 * Copyright 2013 John Ericksen 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.androidtransfuse.analysis; 017 018import org.androidtransfuse.adapter.ASTMethod; 019import org.androidtransfuse.adapter.ASTType; 020import org.androidtransfuse.adapter.PackageClass; 021import org.androidtransfuse.adapter.classes.ASTClassFactory; 022import org.androidtransfuse.adapter.element.ASTElementFactory; 023import org.androidtransfuse.adapter.element.ASTTypeBuilderVisitor; 024import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository; 025import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepositoryFactory; 026import org.androidtransfuse.annotations.*; 027import org.androidtransfuse.experiment.ComponentDescriptor; 028import org.androidtransfuse.experiment.ScopesGeneration; 029import org.androidtransfuse.experiment.generators.FragmentLayoutGenerator; 030import org.androidtransfuse.experiment.generators.ObservesExpressionGenerator; 031import org.androidtransfuse.experiment.generators.OnCreateInjectionGenerator; 032import org.androidtransfuse.gen.componentBuilder.ComponentBuilderFactory; 033import org.androidtransfuse.gen.componentBuilder.ListenerRegistrationGenerator; 034import org.androidtransfuse.gen.variableBuilder.*; 035import org.androidtransfuse.model.InjectionSignature; 036import org.androidtransfuse.scope.ApplicationScope; 037import org.androidtransfuse.util.AndroidLiterals; 038 039import javax.inject.Inject; 040import javax.lang.model.type.TypeMirror; 041 042import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror; 043 044/** 045 * @author John Ericksen 046 */ 047public class FragmentAnalysis implements Analysis<ComponentDescriptor> { 048 049 private final ASTClassFactory astClassFactory; 050 private final ASTElementFactory astElementFactory; 051 private final ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder; 052 private final AnalysisContextFactory analysisContextFactory; 053 private final InjectionBindingBuilder injectionBindingBuilder; 054 private final ASTTypeBuilderVisitor astTypeBuilderVisitor; 055 private final InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory; 056 private final ComponentBuilderFactory componentBuilderFactory; 057 private final ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory; 058 private final ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory; 059 private final ExtraInjectionNodeBuilder extraInjectionNodeBuilder; 060 private final SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder; 061 private final ResourceInjectionNodeBuilder resourceInjectionNodeBuilder; 062 private final PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder; 063 private final FragmentViewInjectionNodeBuilder fragmentViewInjectionNodeBuilder; 064 private final OnCreateInjectionGenerator.InjectionGeneratorFactory injectionGeneratorFactory; 065 private final FragmentLayoutGenerator fragmentLayoutGenerator; 066 private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory; 067 private final ComponentAnalysis componentAnalysis; 068 069 @Inject 070 public FragmentAnalysis(ASTClassFactory astClassFactory, 071 ASTElementFactory astElementFactory, 072 ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder, AnalysisContextFactory analysisContextFactory, 073 InjectionBindingBuilder injectionBindingBuilder, 074 ASTTypeBuilderVisitor astTypeBuilderVisitor, 075 InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory, 076 ComponentBuilderFactory componentBuilderFactory, 077 ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory, 078 ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory, 079 ExtraInjectionNodeBuilder extraInjectionNodeBuilder, 080 SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder, 081 ResourceInjectionNodeBuilder resourceInjectionNodeBuilder, 082 PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder, 083 FragmentViewInjectionNodeBuilder fragmentViewInjectionNodeBuilder, 084 OnCreateInjectionGenerator.InjectionGeneratorFactory injectionGeneratorFactory, 085 FragmentLayoutGenerator fragmentLayoutGenerator, 086 ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory, 087 ComponentAnalysis componentAnalysis) { 088 this.astClassFactory = astClassFactory; 089 this.astElementFactory = astElementFactory; 090 this.providerInjectionNodeBuilder = providerInjectionNodeBuilder; 091 this.analysisContextFactory = analysisContextFactory; 092 this.injectionBindingBuilder = injectionBindingBuilder; 093 this.astTypeBuilderVisitor = astTypeBuilderVisitor; 094 this.injectionNodeBuilderRepositoryFactory = injectionNodeBuilderRepositoryFactory; 095 this.componentBuilderFactory = componentBuilderFactory; 096 this.extraInjectionNodeBuilder = extraInjectionNodeBuilder; 097 this.systemServiceBindingInjectionNodeBuilder = systemServiceBindingInjectionNodeBuilder; 098 this.resourceInjectionNodeBuilder = resourceInjectionNodeBuilder; 099 this.preferenceInjectionNodeBuilder = preferenceInjectionNodeBuilder; 100 this.fragmentViewInjectionNodeBuilder = fragmentViewInjectionNodeBuilder; 101 this.listenerRegistrationGeneratorFactory = listenerRegistrationGeneratorFactory; 102 this.observesExpressionGeneratorFactory = observesExpressionGeneratorFactory; 103 this.injectionGeneratorFactory = injectionGeneratorFactory; 104 this.fragmentLayoutGenerator = fragmentLayoutGenerator; 105 this.scopesGenerationFactory = scopesGenerationFactory; 106 this.componentAnalysis = componentAnalysis; 107 } 108 109 @Override 110 public ComponentDescriptor analyze(ASTType astType) { 111 Fragment fragmentAnnotation = astType.getAnnotation(Fragment.class); 112 PackageClass fragmentClassName; 113 ComponentDescriptor fragmentDescriptor = null; 114 115 if (!astType.extendsFrom(AndroidLiterals.FRAGMENT)) { 116 //generated Android fragment 117 fragmentClassName = componentAnalysis.buildComponentPackageClass(astType, fragmentAnnotation.name(), "Fragment"); 118 119 TypeMirror type = getTypeMirror(fragmentAnnotation, "type"); 120 121 ASTType fragmentType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.FRAGMENT : type.accept(astTypeBuilderVisitor, null); 122 123 AnalysisContext context = analysisContextFactory.buildAnalysisContext(buildVariableBuilderMap(fragmentType)); 124 125 fragmentDescriptor = new ComponentDescriptor(astType, fragmentType, fragmentClassName, context); 126 127 componentAnalysis.setupGenerators(fragmentDescriptor, fragmentType, Fragment.class); 128 129 //application generation profile 130 setupFragmentProfile(fragmentDescriptor, astType); 131 } 132 133 return fragmentDescriptor; 134 } 135 136 private void setupFragmentProfile(ComponentDescriptor fragmentDescriptor, ASTType astType) { 137 ASTMethod onCreateViewMethod = getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE); 138 139 fragmentDescriptor.getGenerators().add(injectionGeneratorFactory.build(onCreateViewMethod, astType)); 140 fragmentDescriptor.getGenerators().add(scopesGenerationFactory.build(onCreateViewMethod)); 141 142 fragmentDescriptor.getGenerators().add(fragmentLayoutGenerator); 143 144 145 146 // onSaveInstanceState 147 ASTMethod onSaveInstanceStateMethod = getASTMethod("onSaveInstanceState", AndroidLiterals.BUNDLE); 148 fragmentDescriptor.getGenerators().add(componentBuilderFactory.buildFragmentOnSaveInstanceStateMethodCallbackGenerator(astClassFactory.getType(OnSaveInstanceState.class), onSaveInstanceStateMethod, getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE))); 149 150 fragmentDescriptor.getGenerators().add(listenerRegistrationGeneratorFactory.build(getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE))); 151 152 fragmentDescriptor.getGenerators().add(observesExpressionGeneratorFactory.build( 153 getASTMethod("onCreateView", AndroidLiterals.LAYOUT_INFLATER, AndroidLiterals.VIEW_GROUP, AndroidLiterals.BUNDLE), 154 getASTMethod("onResume"), 155 getASTMethod("onPause") 156 )); 157 158 } 159 160 private ASTMethod getASTMethod(String methodName, ASTType... args) { 161 return getASTMethod(AndroidLiterals.FRAGMENT, methodName, args); 162 } 163 164 private ASTMethod getASTMethod(ASTType type, String methodName, ASTType... args) { 165 return astElementFactory.findMethod(type, methodName, args); 166 } 167 168 private InjectionNodeBuilderRepository buildVariableBuilderMap(ASTType fragmentType) { 169 170 InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(fragmentType, Fragment.class); 171 172 ASTType applicationScopeType = astElementFactory.getType(ApplicationScope.ApplicationScopeQualifier.class); 173 ASTType applicationProvider = astElementFactory.getType(ApplicationScope.ApplicationProvider.class); 174 injectionNodeBuilderRepository.putType(AndroidLiterals.APPLICATION, providerInjectionNodeBuilder.builderProviderBuilder(applicationProvider)); 175 injectionNodeBuilderRepository.putScoped(new InjectionSignature(AndroidLiterals.APPLICATION), applicationScopeType); 176 177 injectionNodeBuilderRepository.putType(AndroidLiterals.FRAGMENT, injectionBindingBuilder.buildThis(AndroidLiterals.FRAGMENT)); 178 injectionNodeBuilderRepository.putType(AndroidLiterals.ACTIVITY, injectionBindingBuilder.dependency(AndroidLiterals.FRAGMENT).invoke(AndroidLiterals.ACTIVITY, "getActivity").build()); 179 injectionNodeBuilderRepository.putType(AndroidLiterals.CONTEXT, injectionBindingBuilder.dependency(AndroidLiterals.FRAGMENT).invoke(AndroidLiterals.CONTEXT, "getActivity").build()); 180 injectionNodeBuilderRepository.putType(AndroidLiterals.FRAGMENT_MANAGER, injectionBindingBuilder.dependency(AndroidLiterals.FRAGMENT).invoke(AndroidLiterals.FRAGMENT_MANAGER, "getFragmentManager").build()); 181 182 183 while(!fragmentType.equals(AndroidLiterals.FRAGMENT) && fragmentType.inheritsFrom(AndroidLiterals.FRAGMENT)){ 184 injectionNodeBuilderRepository.putType(fragmentType, injectionBindingBuilder.buildThis(fragmentType)); 185 fragmentType = fragmentType.getSuperClass(); 186 } 187 188 injectionNodeBuilderRepository.putAnnotation(Extra.class, extraInjectionNodeBuilder); 189 injectionNodeBuilderRepository.putAnnotation(Resource.class, resourceInjectionNodeBuilder); 190 injectionNodeBuilderRepository.putAnnotation(SystemService.class, systemServiceBindingInjectionNodeBuilder); 191 injectionNodeBuilderRepository.putAnnotation(Preference.class, preferenceInjectionNodeBuilder); 192 injectionNodeBuilderRepository.putAnnotation(org.androidtransfuse.annotations.View.class, fragmentViewInjectionNodeBuilder); 193 194 injectionNodeBuilderRepository.addRepository(injectionNodeBuilderRepositoryFactory.buildApplicationInjections()); 195 injectionNodeBuilderRepository.addRepository(injectionNodeBuilderRepositoryFactory.buildModuleConfiguration()); 196 197 return injectionNodeBuilderRepository; 198 } 199}