blob: e6b6672d35448471914e719714e62cf33b371017 [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
26import com.android.systemui.SystemUIFactory;
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050027import com.android.systemui.qs.QSCarrierGroup;
Jason Monk7a56b832018-12-27 13:45:51 -050028import com.android.systemui.qs.QSFooterImpl;
Jason Monkea54e8a2018-12-20 10:01:48 -050029import com.android.systemui.qs.QuickStatusBarHeader;
Gus Prevas59ec2ff2018-12-28 16:20:28 -050030import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Selim Cinekd5921a82019-01-29 19:04:08 -080031import com.android.systemui.statusbar.phone.NotificationPanelView;
Jason Monkea54e8a2018-12-20 10:01:48 -050032
33import java.lang.reflect.InvocationTargetException;
34import java.lang.reflect.Method;
35import java.lang.reflect.Modifier;
36
37import javax.inject.Inject;
38import javax.inject.Named;
39import javax.inject.Singleton;
40
41import dagger.Module;
42import dagger.Provides;
43import dagger.Subcomponent;
44
45/**
46 * Manages inflation that requires dagger injection.
47 * See docs/dagger.md for details.
48 */
49@Singleton
50public class InjectionInflationController {
51
52 public static final String VIEW_CONTEXT = "view_context";
53 private final ViewCreator mViewCreator;
54 private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>();
55 private final LayoutInflater.Factory2 mFactory = new InjectionFactory();
56
57 @Inject
58 public InjectionInflationController(SystemUIFactory.SystemUIRootComponent rootComponent) {
59 mViewCreator = rootComponent.createViewCreator();
60 initInjectionMap();
61 }
62
63 ArrayMap<String, Method> getInjectionMap() {
64 return mInjectionMap;
65 }
66
67 ViewCreator getFragmentCreator() {
68 return mViewCreator;
69 }
70
71 /**
72 * Wraps a {@link LayoutInflater} to support creating dagger injected views.
73 * See docs/dagger.md for details.
74 */
75 public LayoutInflater injectable(LayoutInflater inflater) {
76 LayoutInflater ret = inflater.cloneInContext(inflater.getContext());
77 ret.setPrivateFactory(mFactory);
78 return ret;
79 }
80
81 private void initInjectionMap() {
82 for (Method method : ViewInstanceCreator.class.getDeclaredMethods()) {
83 if (View.class.isAssignableFrom(method.getReturnType())
84 && (method.getModifiers() & Modifier.PUBLIC) != 0) {
85 mInjectionMap.put(method.getReturnType().getName(), method);
86 }
87 }
88 }
89
90 /**
91 * The subcomponent of dagger that holds all views that need injection.
92 */
93 @Subcomponent
94 public interface ViewCreator {
95 /**
96 * Creates another subcomponent to actually generate the view.
97 */
98 ViewInstanceCreator createInstanceCreator(ViewAttributeProvider attributeProvider);
99 }
100
101 /**
102 * Secondary sub-component that actually creates the views.
103 *
104 * Having two subcomponents lets us hide the complexity of providing the named context
105 * and AttributeSet from the SystemUIRootComponent, instead we have one subcomponent that
106 * creates a new ViewInstanceCreator any time we need to inflate a view.
107 */
108 @Subcomponent(modules = ViewAttributeProvider.class)
109 public interface ViewInstanceCreator {
110 /**
111 * Creates the QuickStatusBarHeader.
112 */
113 QuickStatusBarHeader createQsHeader();
Jason Monk7a56b832018-12-27 13:45:51 -0500114 /**
115 * Creates the QSFooterImpl.
116 */
117 QSFooterImpl createQsFooter();
Gus Prevas59ec2ff2018-12-28 16:20:28 -0500118
119 /**
120 * Creates the NotificationStackScrollLayout.
121 */
122 NotificationStackScrollLayout createNotificationStackScrollLayout();
Selim Cinekd5921a82019-01-29 19:04:08 -0800123
124 /**
125 * Creates the NotificationPanelView.
126 */
127 NotificationPanelView createPanelView();
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500128
129 /**
130 * Creates the QSCarrierGroup
131 */
132 QSCarrierGroup createQSCarrierGroup();
Jason Monkea54e8a2018-12-20 10:01:48 -0500133 }
134
135 /**
136 * Module for providing view-specific constructor objects.
137 */
138 @Module
139 public class ViewAttributeProvider {
140 private final Context mContext;
141 private final AttributeSet mAttrs;
142
143 private ViewAttributeProvider(Context context, AttributeSet attrs) {
144 mContext = context;
145 mAttrs = attrs;
146 }
147
148 /**
149 * Provides the view-themed context (as opposed to the global sysui application context).
150 */
151 @Provides
152 @Named(VIEW_CONTEXT)
153 public Context provideContext() {
154 return mContext;
155 }
156
157 /**
158 * Provides the AttributeSet for the current view being inflated.
159 */
160 @Provides
161 public AttributeSet provideAttributeSet() {
162 return mAttrs;
163 }
164 }
165
166 private class InjectionFactory implements LayoutInflater.Factory2 {
167
168 @Override
169 public View onCreateView(String name, Context context, AttributeSet attrs) {
170 Method creationMethod = mInjectionMap.get(name);
171 if (creationMethod != null) {
172 ViewAttributeProvider provider = new ViewAttributeProvider(context, attrs);
173 try {
174 return (View) creationMethod.invoke(
175 mViewCreator.createInstanceCreator(provider));
176 } catch (IllegalAccessException e) {
177 throw new InflateException("Could not inflate " + name, e);
178 } catch (InvocationTargetException e) {
179 throw new InflateException("Could not inflate " + name, e);
180 }
181 }
182 return null;
183 }
184
185 @Override
186 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
187 return onCreateView(name, context, attrs);
188 }
189 }
190}