• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.util;
18 
19 import android.content.Context;
20 import android.util.ArrayMap;
21 import android.util.AttributeSet;
22 import android.view.InflateException;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 
26 import com.android.keyguard.KeyguardClockSwitch;
27 import com.android.keyguard.KeyguardMessageArea;
28 import com.android.keyguard.KeyguardSliceView;
29 import com.android.systemui.SystemUIFactory;
30 import com.android.systemui.qs.QSCarrierGroup;
31 import com.android.systemui.qs.QSFooterImpl;
32 import com.android.systemui.qs.QSPanel;
33 import com.android.systemui.qs.QuickQSPanel;
34 import com.android.systemui.qs.QuickStatusBarHeader;
35 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
36 import com.android.systemui.statusbar.phone.LockIcon;
37 import com.android.systemui.statusbar.phone.NotificationPanelView;
38 
39 import java.lang.reflect.InvocationTargetException;
40 import java.lang.reflect.Method;
41 import java.lang.reflect.Modifier;
42 
43 import javax.inject.Inject;
44 import javax.inject.Named;
45 import javax.inject.Singleton;
46 
47 import dagger.Module;
48 import dagger.Provides;
49 import dagger.Subcomponent;
50 
51 /**
52  * Manages inflation that requires dagger injection.
53  * See docs/dagger.md for details.
54  */
55 @Singleton
56 public class InjectionInflationController {
57 
58     public static final String VIEW_CONTEXT = "view_context";
59     private final ViewCreator mViewCreator;
60     private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>();
61     private final LayoutInflater.Factory2 mFactory = new InjectionFactory();
62 
63     @Inject
InjectionInflationController(SystemUIFactory.SystemUIRootComponent rootComponent)64     public InjectionInflationController(SystemUIFactory.SystemUIRootComponent rootComponent) {
65         mViewCreator = rootComponent.createViewCreator();
66         initInjectionMap();
67     }
68 
getInjectionMap()69     ArrayMap<String, Method> getInjectionMap() {
70         return mInjectionMap;
71     }
72 
getFragmentCreator()73     ViewCreator getFragmentCreator() {
74         return mViewCreator;
75     }
76 
77     /**
78      * Wraps a {@link LayoutInflater} to support creating dagger injected views.
79      * See docs/dagger.md for details.
80      */
injectable(LayoutInflater inflater)81     public LayoutInflater injectable(LayoutInflater inflater) {
82         LayoutInflater ret = inflater.cloneInContext(inflater.getContext());
83         ret.setPrivateFactory(mFactory);
84         return ret;
85     }
86 
initInjectionMap()87     private void initInjectionMap() {
88         for (Method method : ViewInstanceCreator.class.getDeclaredMethods()) {
89             if (View.class.isAssignableFrom(method.getReturnType())
90                     && (method.getModifiers() & Modifier.PUBLIC) != 0) {
91                 mInjectionMap.put(method.getReturnType().getName(), method);
92             }
93         }
94     }
95 
96     /**
97      * The subcomponent of dagger that holds all views that need injection.
98      */
99     @Subcomponent
100     public interface ViewCreator {
101         /**
102          * Creates another subcomponent to actually generate the view.
103          */
createInstanceCreator(ViewAttributeProvider attributeProvider)104         ViewInstanceCreator createInstanceCreator(ViewAttributeProvider attributeProvider);
105     }
106 
107     /**
108      * Secondary sub-component that actually creates the views.
109      *
110      * Having two subcomponents lets us hide the complexity of providing the named context
111      * and AttributeSet from the SystemUIRootComponent, instead we have one subcomponent that
112      * creates a new ViewInstanceCreator any time we need to inflate a view.
113      */
114     @Subcomponent(modules = ViewAttributeProvider.class)
115     public interface ViewInstanceCreator {
116         /**
117          * Creates the QuickStatusBarHeader.
118          */
createQsHeader()119         QuickStatusBarHeader createQsHeader();
120         /**
121          * Creates the QSFooterImpl.
122          */
createQsFooter()123         QSFooterImpl createQsFooter();
124 
125         /**
126          * Creates the NotificationStackScrollLayout.
127          */
createNotificationStackScrollLayout()128         NotificationStackScrollLayout createNotificationStackScrollLayout();
129 
130         /**
131          * Creates the NotificationPanelView.
132          */
createPanelView()133         NotificationPanelView createPanelView();
134 
135         /**
136          * Creates the QSCarrierGroup
137          */
createQSCarrierGroup()138         QSCarrierGroup createQSCarrierGroup();
139 
140         /**
141          * Creates the KeyguardClockSwitch.
142          */
createKeyguardClockSwitch()143         KeyguardClockSwitch createKeyguardClockSwitch();
144 
145         /**
146          * Creates the KeyguardSliceView.
147          */
createKeyguardSliceView()148         KeyguardSliceView createKeyguardSliceView();
149 
150         /**
151          * Creates the KeyguardMessageArea.
152          */
createKeyguardMessageArea()153         KeyguardMessageArea createKeyguardMessageArea();
154 
155         /**
156          * Creates the keyguard LockIcon.
157          */
createLockIcon()158         LockIcon createLockIcon();
159 
160         /**
161          * Creates the QSPanel.
162          */
createQSPanel()163         QSPanel createQSPanel();
164 
165         /**
166          * Creates the QuickQSPanel.
167          */
createQuickQSPanel()168         QuickQSPanel createQuickQSPanel();
169     }
170 
171     /**
172      * Module for providing view-specific constructor objects.
173      */
174     @Module
175     public class ViewAttributeProvider {
176         private final Context mContext;
177         private final AttributeSet mAttrs;
178 
ViewAttributeProvider(Context context, AttributeSet attrs)179         private ViewAttributeProvider(Context context, AttributeSet attrs) {
180             mContext = context;
181             mAttrs = attrs;
182         }
183 
184         /**
185          * Provides the view-themed context (as opposed to the global sysui application context).
186          */
187         @Provides
188         @Named(VIEW_CONTEXT)
provideContext()189         public Context provideContext() {
190             return mContext;
191         }
192 
193         /**
194          * Provides the AttributeSet for the current view being inflated.
195          */
196         @Provides
provideAttributeSet()197         public AttributeSet provideAttributeSet() {
198             return mAttrs;
199         }
200     }
201 
202     private class InjectionFactory implements LayoutInflater.Factory2 {
203 
204         @Override
onCreateView(String name, Context context, AttributeSet attrs)205         public View onCreateView(String name, Context context, AttributeSet attrs) {
206             Method creationMethod = mInjectionMap.get(name);
207             if (creationMethod != null) {
208                 ViewAttributeProvider provider = new ViewAttributeProvider(context, attrs);
209                 try {
210                     return (View) creationMethod.invoke(
211                             mViewCreator.createInstanceCreator(provider));
212                 } catch (IllegalAccessException e) {
213                     throw new InflateException("Could not inflate " + name, e);
214                 } catch (InvocationTargetException e) {
215                     throw new InflateException("Could not inflate " + name, e);
216                 }
217             }
218             return null;
219         }
220 
221         @Override
onCreateView(View parent, String name, Context context, AttributeSet attrs)222         public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
223             return onCreateView(name, context, attrs);
224         }
225     }
226 }
227