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.element.ASTElementFactory;
022import org.androidtransfuse.adapter.element.ASTTypeBuilderVisitor;
023import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository;
024import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepositoryFactory;
025import org.androidtransfuse.annotations.*;
026import org.androidtransfuse.experiment.ComponentDescriptor;
027import org.androidtransfuse.experiment.ScopesGeneration;
028import org.androidtransfuse.experiment.generators.*;
029import org.androidtransfuse.gen.GeneratorFactory;
030import org.androidtransfuse.gen.componentBuilder.ListenerRegistrationGenerator;
031import org.androidtransfuse.gen.componentBuilder.NonConfigurationInstanceGenerator;
032import org.androidtransfuse.gen.variableBuilder.*;
033import org.androidtransfuse.intentFactory.ActivityIntentFactoryStrategy;
034import org.androidtransfuse.model.InjectionSignature;
035import org.androidtransfuse.scope.ApplicationScope;
036import org.androidtransfuse.util.AndroidLiterals;
037
038import javax.inject.Inject;
039import javax.inject.Provider;
040import javax.lang.model.type.TypeMirror;
041
042import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror;
043
044/**
045 * Activity related Analysis
046 *
047 * @author John Ericksen
048 */
049public class ActivityAnalysis implements Analysis<ComponentDescriptor> {
050
051    private final InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory;
052    private final AnalysisContextFactory analysisContextFactory;
053    private final ASTElementFactory astElementFactory;
054    private final ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder;
055    private final ASTTypeBuilderVisitor astTypeBuilderVisitor;
056    private final InjectionBindingBuilder injectionBindingBuilder;
057    private final ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory;
058    private final ViewInjectionNodeBuilder viewVariableBuilder;
059    private final ExtraInjectionNodeBuilder extraInjectionNodeBuilder;
060    private final SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder;
061    private final ResourceInjectionNodeBuilder resourceInjectionNodeBuilder;
062    private final PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder;
063    private final Provider<ActivityManifestEntryGenerator> manifestGeneratorProvider;
064    private final LayoutGenerator layoutGenerator;
065    private final LayoutHandlerGenerator layoutHandlerGenerator;
066    private final WindowFeatureGenerator windowFeatureGenerator;
067    private final GeneratorFactory generatorFactory;
068    private final ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listerRegistrationGeneratorFactory;
069    private final NonConfigurationInstanceGenerator.NonconfigurationInstanceGeneratorFactory nonConfigurationInstanceGeneratorFactory;
070    private final OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory;
071    private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory;
072    private final ComponentAnalysis componentAnalysis;
073
074    @Inject
075    public ActivityAnalysis(InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory,
076                            AnalysisContextFactory analysisContextFactory,
077                            ASTElementFactory astElementFactory,
078                            ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder,
079                            ASTTypeBuilderVisitor astTypeBuilderVisitor,
080                            InjectionBindingBuilder injectionBindingBuilder,
081                            ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory,
082                            ViewInjectionNodeBuilder viewVariableBuilder,
083                            ExtraInjectionNodeBuilder extraInjectionNodeBuilder,
084                            SystemServiceBindingInjectionNodeBuilder systemServiceBindingInjectionNodeBuilder,
085                            ResourceInjectionNodeBuilder resourceInjectionNodeBuilder,
086                            PreferenceInjectionNodeBuilder preferenceInjectionNodeBuilder,
087                            Provider<ActivityManifestEntryGenerator> manifestGeneratorProvider,
088                            LayoutGenerator layoutGenerator,
089                            LayoutHandlerGenerator layoutHandlerGenerator,
090                            WindowFeatureGenerator windowFeatureGenerator,
091                            GeneratorFactory generatorFactory,
092                            ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listerRegistrationGeneratorFactory,
093                            NonConfigurationInstanceGenerator.NonconfigurationInstanceGeneratorFactory nonConfigurationInstanceGeneratorFactory,
094                            OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory,
095                            ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory,
096                            ComponentAnalysis componentAnalysis) {
097        this.injectionNodeBuilderRepositoryFactory = injectionNodeBuilderRepositoryFactory;
098        this.analysisContextFactory = analysisContextFactory;
099        this.astElementFactory = astElementFactory;
100        this.providerInjectionNodeBuilder = providerInjectionNodeBuilder;
101        this.astTypeBuilderVisitor = astTypeBuilderVisitor;
102        this.injectionBindingBuilder = injectionBindingBuilder;
103        this.observesExpressionGeneratorFactory = observesExpressionGeneratorFactory;
104        this.viewVariableBuilder = viewVariableBuilder;
105        this.extraInjectionNodeBuilder = extraInjectionNodeBuilder;
106        this.systemServiceBindingInjectionNodeBuilder = systemServiceBindingInjectionNodeBuilder;
107        this.resourceInjectionNodeBuilder = resourceInjectionNodeBuilder;
108        this.preferenceInjectionNodeBuilder = preferenceInjectionNodeBuilder;
109        this.manifestGeneratorProvider = manifestGeneratorProvider;
110        this.layoutGenerator = layoutGenerator;
111        this.layoutHandlerGenerator = layoutHandlerGenerator;
112        this.windowFeatureGenerator = windowFeatureGenerator;
113        this.generatorFactory = generatorFactory;
114        this.listerRegistrationGeneratorFactory = listerRegistrationGeneratorFactory;
115        this.nonConfigurationInstanceGeneratorFactory = nonConfigurationInstanceGeneratorFactory;
116        this.onCreateInjectionGeneratorFactory = onCreateInjectionGeneratorFactory;
117        this.scopesGenerationFactory = scopesGenerationFactory;
118        this.componentAnalysis = componentAnalysis;
119    }
120
121    public ComponentDescriptor analyze(ASTType input) {
122
123        Activity activityAnnotation = input.getAnnotation(Activity.class);
124        PackageClass activityClassName;
125        ComponentDescriptor activityDescriptor;
126
127        if (input.extendsFrom(AndroidLiterals.ACTIVITY)) {
128            //vanilla Android activity
129            PackageClass activityPackageClass = input.getPackageClass();
130            activityClassName = componentAnalysis.buildComponentPackageClass(input, activityPackageClass.getClassName(), "Activity");
131            activityDescriptor = new ComponentDescriptor(input, null, activityClassName);
132        } else {
133            //generated Android activity
134            activityClassName = componentAnalysis.buildComponentPackageClass(input, activityAnnotation.name(), "Activity");
135
136            TypeMirror type = getTypeMirror(activityAnnotation, "type");
137
138            ASTType activityType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.ACTIVITY : type.accept(astTypeBuilderVisitor, null);
139
140            AnalysisContext context = analysisContextFactory.buildAnalysisContext(buildVariableBuilderMap(activityType));
141
142            activityDescriptor = new ComponentDescriptor(input, activityType, activityClassName, context);
143
144            activityDescriptor.getGenerators().add(layoutGenerator);
145            activityDescriptor.getGenerators().add(layoutHandlerGenerator);
146            activityDescriptor.getGenerators().add(windowFeatureGenerator);
147            activityDescriptor.getGenerators().add(scopesGenerationFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE)));
148            activityDescriptor.getGenerators().add(onCreateInjectionGeneratorFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE), input));
149            //extra intent factory
150            activityDescriptor.getGenerators().add(generatorFactory.buildStrategyGenerator(ActivityIntentFactoryStrategy.class));
151            //listener registration
152            activityDescriptor.getGenerators().add(listerRegistrationGeneratorFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE)));
153            //non configuration instance update
154            activityDescriptor.getGenerators().add(nonConfigurationInstanceGeneratorFactory.build(getASTMethod("onCreate", AndroidLiterals.BUNDLE)));
155
156            componentAnalysis.setupGenerators(activityDescriptor, activityType, Activity.class);
157
158            activityDescriptor.getGenerators().add(observesExpressionGeneratorFactory.build(
159                    getASTMethod("onCreate", AndroidLiterals.BUNDLE),
160                    getASTMethod("onResume"),
161                    getASTMethod("onPause")));
162        }
163
164        //add manifest elements
165        activityDescriptor.getGenerators().add(manifestGeneratorProvider.get());
166
167        return activityDescriptor;
168    }
169
170    private InjectionNodeBuilderRepository buildVariableBuilderMap(ASTType activityType) {
171
172        InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(activityType, Activity.class);
173
174        ASTType applicationScopeType = astElementFactory.getType(ApplicationScope.ApplicationScopeQualifier.class);
175        ASTType applicationProvider = astElementFactory.getType(ApplicationScope.ApplicationProvider.class);
176        injectionNodeBuilderRepository.putType(AndroidLiterals.APPLICATION, providerInjectionNodeBuilder.builderProviderBuilder(applicationProvider));
177        injectionNodeBuilderRepository.putType(AndroidLiterals.CONTEXT, injectionBindingBuilder.buildThis(AndroidLiterals.CONTEXT));
178        injectionNodeBuilderRepository.putScoped(new InjectionSignature(AndroidLiterals.APPLICATION), applicationScopeType);
179
180        injectionNodeBuilderRepository.putType(AndroidLiterals.ACTIVITY, injectionBindingBuilder.buildThis(AndroidLiterals.ACTIVITY));
181
182        while(!activityType.equals(AndroidLiterals.ACTIVITY) && activityType.inheritsFrom(AndroidLiterals.ACTIVITY)){
183            injectionNodeBuilderRepository.putType(activityType, injectionBindingBuilder.buildThis(activityType));
184            activityType = activityType.getSuperClass();
185        }
186
187        injectionNodeBuilderRepository.putAnnotation(Extra.class, extraInjectionNodeBuilder);
188        injectionNodeBuilderRepository.putAnnotation(Resource.class, resourceInjectionNodeBuilder);
189        injectionNodeBuilderRepository.putAnnotation(SystemService.class, systemServiceBindingInjectionNodeBuilder);
190        injectionNodeBuilderRepository.putAnnotation(Preference.class, preferenceInjectionNodeBuilder);
191        injectionNodeBuilderRepository.putAnnotation(View.class, viewVariableBuilder);
192
193        injectionNodeBuilderRepository.addRepository(
194                injectionNodeBuilderRepositoryFactory.buildApplicationInjections());
195
196        injectionNodeBuilderRepository.addRepository(
197                injectionNodeBuilderRepositoryFactory.buildModuleConfiguration());
198
199        return injectionNodeBuilderRepository;
200
201    }
202
203    private ASTMethod getASTMethod(String methodName, ASTType... args) {
204        return getASTMethod(AndroidLiterals.ACTIVITY, methodName, args);
205    }
206
207    private ASTMethod getASTMethod(ASTType type, String methodName, ASTType... args) {
208        return astElementFactory.findMethod(type, methodName, args);
209    }
210}