blob: ede30046d6c3c4a0513e541eebf8eddbb82816f2 [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;
Jason Monkea54e8a2018-12-20 10:01:48 -050029import com.android.systemui.SystemUIFactory;
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;
Selim Cineke3c6e462019-06-24 19:37:06 -070035import com.android.systemui.statusbar.NotificationShelf;
Gus Prevas59ec2ff2018-12-28 16:20:28 -050036import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070037import com.android.systemui.statusbar.phone.LockIcon;
Selim Cinekd5921a82019-01-29 19:04:08 -080038import com.android.systemui.statusbar.phone.NotificationPanelView;
Jason Monkea54e8a2018-12-20 10:01:48 -050039
40import java.lang.reflect.InvocationTargetException;
41import java.lang.reflect.Method;
42import java.lang.reflect.Modifier;
43
44import javax.inject.Inject;
45import javax.inject.Named;
46import javax.inject.Singleton;
47
48import dagger.Module;
49import dagger.Provides;
50import dagger.Subcomponent;
51
52/**
53 * Manages inflation that requires dagger injection.
54 * See docs/dagger.md for details.
55 */
56@Singleton
57public class InjectionInflationController {
58
59 public static final String VIEW_CONTEXT = "view_context";
60 private final ViewCreator mViewCreator;
61 private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>();
62 private final LayoutInflater.Factory2 mFactory = new InjectionFactory();
63
64 @Inject
65 public InjectionInflationController(SystemUIFactory.SystemUIRootComponent rootComponent) {
66 mViewCreator = rootComponent.createViewCreator();
67 initInjectionMap();
68 }
69
70 ArrayMap<String, Method> getInjectionMap() {
71 return mInjectionMap;
72 }
73
74 ViewCreator getFragmentCreator() {
75 return mViewCreator;
76 }
77
78 /**
79 * Wraps a {@link LayoutInflater} to support creating dagger injected views.
80 * See docs/dagger.md for details.
81 */
82 public LayoutInflater injectable(LayoutInflater inflater) {
83 LayoutInflater ret = inflater.cloneInContext(inflater.getContext());
84 ret.setPrivateFactory(mFactory);
85 return ret;
86 }
87
88 private void initInjectionMap() {
89 for (Method method : ViewInstanceCreator.class.getDeclaredMethods()) {
90 if (View.class.isAssignableFrom(method.getReturnType())
91 && (method.getModifiers() & Modifier.PUBLIC) != 0) {
92 mInjectionMap.put(method.getReturnType().getName(), method);
93 }
94 }
95 }
96
97 /**
98 * The subcomponent of dagger that holds all views that need injection.
99 */
100 @Subcomponent
101 public interface ViewCreator {
102 /**
103 * Creates another subcomponent to actually generate the view.
104 */
105 ViewInstanceCreator createInstanceCreator(ViewAttributeProvider attributeProvider);
106 }
107
108 /**
109 * Secondary sub-component that actually creates the views.
110 *
111 * Having two subcomponents lets us hide the complexity of providing the named context
112 * and AttributeSet from the SystemUIRootComponent, instead we have one subcomponent that
113 * creates a new ViewInstanceCreator any time we need to inflate a view.
114 */
115 @Subcomponent(modules = ViewAttributeProvider.class)
116 public interface ViewInstanceCreator {
117 /**
118 * Creates the QuickStatusBarHeader.
119 */
120 QuickStatusBarHeader createQsHeader();
Jason Monk7a56b832018-12-27 13:45:51 -0500121 /**
122 * Creates the QSFooterImpl.
123 */
124 QSFooterImpl createQsFooter();
Gus Prevas59ec2ff2018-12-28 16:20:28 -0500125
126 /**
127 * Creates the NotificationStackScrollLayout.
128 */
129 NotificationStackScrollLayout createNotificationStackScrollLayout();
Selim Cinekd5921a82019-01-29 19:04:08 -0800130
131 /**
132 * Creates the NotificationPanelView.
133 */
134 NotificationPanelView createPanelView();
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500135
136 /**
137 * Creates the QSCarrierGroup
138 */
139 QSCarrierGroup createQSCarrierGroup();
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400140
141 /**
Selim Cineke3c6e462019-06-24 19:37:06 -0700142 * Creates the Shelf.
143 */
144 NotificationShelf creatNotificationShelf();
145
146 /**
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400147 * Creates the KeyguardClockSwitch.
148 */
149 KeyguardClockSwitch createKeyguardClockSwitch();
Lucas Dupinad079442019-04-03 13:14:11 -0700150
151 /**
152 * Creates the KeyguardSliceView.
153 */
154 KeyguardSliceView createKeyguardSliceView();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700155
156 /**
157 * Creates the KeyguardMessageArea.
158 */
159 KeyguardMessageArea createKeyguardMessageArea();
160
161 /**
162 * Creates the keyguard LockIcon.
163 */
164 LockIcon createLockIcon();
Fabian Kozynski00d494d2019-04-04 09:53:50 -0400165
166 /**
167 * Creates the QSPanel.
168 */
169 QSPanel createQSPanel();
170
171 /**
172 * Creates the QuickQSPanel.
173 */
174 QuickQSPanel createQuickQSPanel();
Jason Monkea54e8a2018-12-20 10:01:48 -0500175 }
176
177 /**
178 * Module for providing view-specific constructor objects.
179 */
180 @Module
181 public class ViewAttributeProvider {
182 private final Context mContext;
183 private final AttributeSet mAttrs;
184
185 private ViewAttributeProvider(Context context, AttributeSet attrs) {
186 mContext = context;
187 mAttrs = attrs;
188 }
189
190 /**
191 * Provides the view-themed context (as opposed to the global sysui application context).
192 */
193 @Provides
194 @Named(VIEW_CONTEXT)
195 public Context provideContext() {
196 return mContext;
197 }
198
199 /**
200 * Provides the AttributeSet for the current view being inflated.
201 */
202 @Provides
203 public AttributeSet provideAttributeSet() {
204 return mAttrs;
205 }
206 }
207
208 private class InjectionFactory implements LayoutInflater.Factory2 {
209
210 @Override
211 public View onCreateView(String name, Context context, AttributeSet attrs) {
212 Method creationMethod = mInjectionMap.get(name);
213 if (creationMethod != null) {
214 ViewAttributeProvider provider = new ViewAttributeProvider(context, attrs);
215 try {
216 return (View) creationMethod.invoke(
217 mViewCreator.createInstanceCreator(provider));
218 } catch (IllegalAccessException e) {
219 throw new InflateException("Could not inflate " + name, e);
220 } catch (InvocationTargetException e) {
221 throw new InflateException("Could not inflate " + name, e);
222 }
223 }
224 return null;
225 }
226
227 @Override
228 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
229 return onCreateView(name, context, attrs);
230 }
231 }
232}