blob: 5ed027d37defc2178937d5251e8b54cdf8eed53c [file] [log] [blame]
Jason Monkea54e8a2018-12-20 10:01:48 -05001/*
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
17package com.android.systemui.util;
18
19import android.content.Context;
20import android.util.ArrayMap;
21import android.util.AttributeSet;
22import android.view.InflateException;
23import android.view.LayoutInflater;
24import android.view.View;
25
Robert Snoebergerbe35b762019-03-15 14:33:02 -040026import com.android.keyguard.KeyguardClockSwitch;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070027import com.android.keyguard.KeyguardMessageArea;
Lucas Dupinad079442019-04-03 13:14:11 -070028import com.android.keyguard.KeyguardSliceView;
Dave Mankofff4736812019-10-18 17:25:50 -040029import com.android.systemui.dagger.SystemUIRootComponent;
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050030import com.android.systemui.qs.QSCarrierGroup;
Jason Monk7a56b832018-12-27 13:45:51 -050031import com.android.systemui.qs.QSFooterImpl;
Fabian Kozynski00d494d2019-04-04 09:53:50 -040032import com.android.systemui.qs.QSPanel;
33import com.android.systemui.qs.QuickQSPanel;
Jason Monkea54e8a2018-12-20 10:01:48 -050034import com.android.systemui.qs.QuickStatusBarHeader;
Fabian Kozynskif4b368e2019-08-13 10:34:06 -040035import com.android.systemui.qs.customize.QSCustomizer;
Selim Cineke3c6e462019-06-24 19:37:06 -070036import com.android.systemui.statusbar.NotificationShelf;
Gus Prevas59ec2ff2018-12-28 16:20:28 -050037import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070038import com.android.systemui.statusbar.phone.LockIcon;
Selim Cinekd5921a82019-01-29 19:04:08 -080039import com.android.systemui.statusbar.phone.NotificationPanelView;
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -040040import com.android.systemui.statusbar.policy.Clock;
Jason Monkea54e8a2018-12-20 10:01:48 -050041
42import java.lang.reflect.InvocationTargetException;
43import java.lang.reflect.Method;
44import java.lang.reflect.Modifier;
45
46import javax.inject.Inject;
47import javax.inject.Named;
48import javax.inject.Singleton;
49
50import dagger.Module;
51import dagger.Provides;
52import dagger.Subcomponent;
53
54/**
55 * Manages inflation that requires dagger injection.
56 * See docs/dagger.md for details.
57 */
58@Singleton
59public class InjectionInflationController {
60
61 public static final String VIEW_CONTEXT = "view_context";
62 private final ViewCreator mViewCreator;
63 private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>();
64 private final LayoutInflater.Factory2 mFactory = new InjectionFactory();
65
66 @Inject
Dave Mankoff1a0e3822019-07-03 13:26:55 -040067 public InjectionInflationController(SystemUIRootComponent rootComponent) {
Jason Monkea54e8a2018-12-20 10:01:48 -050068 mViewCreator = rootComponent.createViewCreator();
69 initInjectionMap();
70 }
71
72 ArrayMap<String, Method> getInjectionMap() {
73 return mInjectionMap;
74 }
75
76 ViewCreator getFragmentCreator() {
77 return mViewCreator;
78 }
79
80 /**
81 * Wraps a {@link LayoutInflater} to support creating dagger injected views.
82 * See docs/dagger.md for details.
83 */
84 public LayoutInflater injectable(LayoutInflater inflater) {
85 LayoutInflater ret = inflater.cloneInContext(inflater.getContext());
86 ret.setPrivateFactory(mFactory);
87 return ret;
88 }
89
90 private void initInjectionMap() {
91 for (Method method : ViewInstanceCreator.class.getDeclaredMethods()) {
92 if (View.class.isAssignableFrom(method.getReturnType())
93 && (method.getModifiers() & Modifier.PUBLIC) != 0) {
94 mInjectionMap.put(method.getReturnType().getName(), method);
95 }
96 }
97 }
98
99 /**
100 * The subcomponent of dagger that holds all views that need injection.
101 */
102 @Subcomponent
103 public interface ViewCreator {
104 /**
105 * Creates another subcomponent to actually generate the view.
106 */
107 ViewInstanceCreator createInstanceCreator(ViewAttributeProvider attributeProvider);
108 }
109
110 /**
111 * Secondary sub-component that actually creates the views.
112 *
113 * Having two subcomponents lets us hide the complexity of providing the named context
114 * and AttributeSet from the SystemUIRootComponent, instead we have one subcomponent that
115 * creates a new ViewInstanceCreator any time we need to inflate a view.
116 */
117 @Subcomponent(modules = ViewAttributeProvider.class)
118 public interface ViewInstanceCreator {
119 /**
120 * Creates the QuickStatusBarHeader.
121 */
122 QuickStatusBarHeader createQsHeader();
Jason Monk7a56b832018-12-27 13:45:51 -0500123 /**
124 * Creates the QSFooterImpl.
125 */
126 QSFooterImpl createQsFooter();
Gus Prevas59ec2ff2018-12-28 16:20:28 -0500127
128 /**
129 * Creates the NotificationStackScrollLayout.
130 */
131 NotificationStackScrollLayout createNotificationStackScrollLayout();
Selim Cinekd5921a82019-01-29 19:04:08 -0800132
133 /**
134 * Creates the NotificationPanelView.
135 */
136 NotificationPanelView createPanelView();
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500137
138 /**
139 * Creates the QSCarrierGroup
140 */
141 QSCarrierGroup createQSCarrierGroup();
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400142
143 /**
Selim Cineke3c6e462019-06-24 19:37:06 -0700144 * Creates the Shelf.
145 */
146 NotificationShelf creatNotificationShelf();
147
148 /**
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400149 * Creates the KeyguardClockSwitch.
150 */
151 KeyguardClockSwitch createKeyguardClockSwitch();
Lucas Dupinad079442019-04-03 13:14:11 -0700152
153 /**
154 * Creates the KeyguardSliceView.
155 */
156 KeyguardSliceView createKeyguardSliceView();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700157
158 /**
159 * Creates the KeyguardMessageArea.
160 */
161 KeyguardMessageArea createKeyguardMessageArea();
162
163 /**
164 * Creates the keyguard LockIcon.
165 */
166 LockIcon createLockIcon();
Fabian Kozynski00d494d2019-04-04 09:53:50 -0400167
168 /**
169 * Creates the QSPanel.
170 */
171 QSPanel createQSPanel();
172
173 /**
174 * Creates the QuickQSPanel.
175 */
176 QuickQSPanel createQuickQSPanel();
Fabian Kozynskif4b368e2019-08-13 10:34:06 -0400177
178 /**
179 * Creates the QSCustomizer.
180 */
181 QSCustomizer createQSCustomizer();
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400182
183 /**
184 * Creates a Clock.
185 */
186 Clock createClock();
Jason Monkea54e8a2018-12-20 10:01:48 -0500187 }
188
189 /**
190 * Module for providing view-specific constructor objects.
191 */
192 @Module
193 public class ViewAttributeProvider {
194 private final Context mContext;
195 private final AttributeSet mAttrs;
196
197 private ViewAttributeProvider(Context context, AttributeSet attrs) {
198 mContext = context;
199 mAttrs = attrs;
200 }
201
202 /**
203 * Provides the view-themed context (as opposed to the global sysui application context).
204 */
205 @Provides
206 @Named(VIEW_CONTEXT)
207 public Context provideContext() {
208 return mContext;
209 }
210
211 /**
212 * Provides the AttributeSet for the current view being inflated.
213 */
214 @Provides
215 public AttributeSet provideAttributeSet() {
216 return mAttrs;
217 }
218 }
219
220 private class InjectionFactory implements LayoutInflater.Factory2 {
221
222 @Override
223 public View onCreateView(String name, Context context, AttributeSet attrs) {
224 Method creationMethod = mInjectionMap.get(name);
225 if (creationMethod != null) {
226 ViewAttributeProvider provider = new ViewAttributeProvider(context, attrs);
227 try {
228 return (View) creationMethod.invoke(
229 mViewCreator.createInstanceCreator(provider));
230 } catch (IllegalAccessException e) {
231 throw new InflateException("Could not inflate " + name, e);
232 } catch (InvocationTargetException e) {
233 throw new InflateException("Could not inflate " + name, e);
234 }
235 }
236 return null;
237 }
238
239 @Override
240 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
241 return onCreateView(name, context, attrs);
242 }
243 }
244}