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.BroadcastReceiver;
026import org.androidtransfuse.experiment.ComponentDescriptor;
027import org.androidtransfuse.experiment.ScopesGeneration;
028import org.androidtransfuse.experiment.generators.BroadcastReceiverManifestEntryGenerator;
029import org.androidtransfuse.experiment.generators.OnCreateInjectionGenerator;
030import org.androidtransfuse.gen.variableBuilder.InjectionBindingBuilder;
031import org.androidtransfuse.gen.variableBuilder.ProviderInjectionNodeBuilderFactory;
032import org.androidtransfuse.model.InjectionSignature;
033import org.androidtransfuse.scope.ApplicationScope;
034import org.androidtransfuse.util.AndroidLiterals;
035
036import javax.inject.Inject;
037import javax.lang.model.type.TypeMirror;
038
039import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror;
040
041/**
042 * @author John Ericksen
043 */
044public class BroadcastReceiverAnalysis implements Analysis<ComponentDescriptor> {
045
046    private final InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory;
047    private final ASTTypeBuilderVisitor astTypeBuilderVisitor;
048    private final AnalysisContextFactory analysisContextFactory;
049    private final InjectionBindingBuilder injectionBindingBuilder;
050    private final BroadcastReceiverManifestEntryGenerator manifestEntryGenerator;
051    private final ASTElementFactory astElementFactory;
052    private final ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder;
053    private final OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory;
054    private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory;
055    private final ComponentAnalysis componentAnalysis;
056
057    @Inject
058    public BroadcastReceiverAnalysis(InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory,
059                                     ASTTypeBuilderVisitor astTypeBuilderVisitor,
060                                     AnalysisContextFactory analysisContextFactory,
061                                     InjectionBindingBuilder injectionBindingBuilder,
062                                     BroadcastReceiverManifestEntryGenerator manifestEntryGenerator,
063                                     ASTElementFactory astElementFactory,
064                                     ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder,
065                                     OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory,
066                                     ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory,
067                                     ComponentAnalysis componentAnalysis) {
068        this.injectionNodeBuilderRepositoryFactory = injectionNodeBuilderRepositoryFactory;
069        this.astTypeBuilderVisitor = astTypeBuilderVisitor;
070        this.analysisContextFactory = analysisContextFactory;
071        this.injectionBindingBuilder = injectionBindingBuilder;
072        this.manifestEntryGenerator = manifestEntryGenerator;
073        this.astElementFactory = astElementFactory;
074        this.providerInjectionNodeBuilder = providerInjectionNodeBuilder;
075        this.onCreateInjectionGeneratorFactory = onCreateInjectionGeneratorFactory;
076        this.scopesGenerationFactory = scopesGenerationFactory;
077        this.componentAnalysis = componentAnalysis;
078    }
079
080    public ComponentDescriptor analyze(ASTType astType) {
081
082        BroadcastReceiver broadcastReceiverAnnotation = astType.getAnnotation(BroadcastReceiver.class);
083
084        ComponentDescriptor receiverDescriptor;
085
086        if (astType.extendsFrom(AndroidLiterals.BROADCAST_RECEIVER)) {
087            //vanilla Android broadcast receiver
088            PackageClass activityPackageClass = astType.getPackageClass();
089            PackageClass receiverClassName = componentAnalysis.buildComponentPackageClass(astType, activityPackageClass.getClassName(), "BroadcastReceiver");
090            receiverDescriptor = new ComponentDescriptor(astType, null, receiverClassName);
091        } else {
092            PackageClass receiverClassName = componentAnalysis.buildComponentPackageClass(astType, broadcastReceiverAnnotation.name(), "BroadcastReceiver");
093
094            TypeMirror type = getTypeMirror(broadcastReceiverAnnotation, "type");
095            ASTType receiverType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.BROADCAST_RECEIVER : type.accept(astTypeBuilderVisitor, null);
096
097            InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(receiverType, BroadcastReceiver.class);
098            ASTType applicationScopeType = astElementFactory.getType(ApplicationScope.ApplicationScopeQualifier.class);
099            ASTType applicationProvider = astElementFactory.getType(ApplicationScope.ApplicationProvider.class);
100            injectionNodeBuilderRepository.putType(AndroidLiterals.APPLICATION, providerInjectionNodeBuilder.builderProviderBuilder(applicationProvider));
101            injectionNodeBuilderRepository.putScoped(new InjectionSignature(AndroidLiterals.APPLICATION), applicationScopeType);
102
103            injectionNodeBuilderRepository.addRepository(
104                    injectionNodeBuilderRepositoryFactory.buildApplicationInjections());
105
106            injectionNodeBuilderRepository.addRepository(
107                    injectionNodeBuilderRepositoryFactory.buildModuleConfiguration());
108
109            if(type != null) {
110                ASTType applicationASTType = type.accept(astTypeBuilderVisitor, null);
111
112                while(!applicationASTType.equals(AndroidLiterals.BROADCAST_RECEIVER) && applicationASTType.inheritsFrom(AndroidLiterals.BROADCAST_RECEIVER)){
113                    injectionNodeBuilderRepository.putType(applicationASTType, injectionBindingBuilder.buildThis(applicationASTType));
114                    applicationASTType = applicationASTType.getSuperClass();
115                }
116            }
117
118            AnalysisContext analysisContext = analysisContextFactory.buildAnalysisContext(injectionNodeBuilderRepository);
119
120            receiverDescriptor = new ComponentDescriptor(astType, receiverType, receiverClassName, analysisContext);
121
122            receiverDescriptor.getGenerators().add(scopesGenerationFactory.build(getASTMethod("onReceive", AndroidLiterals.CONTEXT, AndroidLiterals.INTENT)));
123
124            receiverDescriptor.getGenerators().add(onCreateInjectionGeneratorFactory.build(getASTMethod("onReceive", AndroidLiterals.CONTEXT, AndroidLiterals.INTENT), astType));
125
126            componentAnalysis.setupGenerators(receiverDescriptor, receiverType, BroadcastReceiver.class);
127        }
128
129        receiverDescriptor.getGenerators().add(manifestEntryGenerator);
130
131        return receiverDescriptor;
132    }
133
134    private ASTMethod getASTMethod(String methodName, ASTType... args) {
135        return getASTMethod(AndroidLiterals.BROADCAST_RECEIVER, methodName, args);
136    }
137
138    private ASTMethod getASTMethod(ASTType type, String methodName, ASTType... args) {
139        return astElementFactory.findMethod(type, methodName, args);
140    }
141}