1 /*
2  * Copyright (C) 2019 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;
18 
19 import android.app.Activity;
20 import android.app.Application;
21 import android.app.Service;
22 import android.content.BroadcastReceiver;
23 import android.content.ContentProvider;
24 import android.content.Context;
25 import android.content.Intent;
26 
27 import androidx.annotation.NonNull;
28 import androidx.annotation.Nullable;
29 import androidx.core.app.AppComponentFactory;
30 
31 import com.android.systemui.dagger.ContextComponentHelper;
32 
33 import javax.inject.Inject;
34 
35 /**
36  * Implementation of AppComponentFactory that injects into constructors.
37  *
38  * This class sets up dependency injection when creating our application.
39  *
40  * Services support dependency injection into their constructors.
41  *
42  * ContentProviders support injection into member variables - _not_ constructors.
43  */
44 public class SystemUIAppComponentFactory extends AppComponentFactory {
45 
46     private static final String TAG = "AppComponentFactory";
47     @Inject
48     public ContextComponentHelper mComponentHelper;
49 
SystemUIAppComponentFactory()50     public SystemUIAppComponentFactory() {
51         super();
52     }
53 
54     @NonNull
55     @Override
instantiateApplicationCompat( @onNull ClassLoader cl, @NonNull String className)56     public Application instantiateApplicationCompat(
57             @NonNull ClassLoader cl, @NonNull String className)
58             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
59         Application app = super.instantiateApplicationCompat(cl, className);
60         if (app instanceof ContextInitializer) {
61             ((ContextInitializer) app).setContextAvailableCallback(
62                     context -> {
63                         SystemUIFactory.createFromConfig(context);
64                         SystemUIFactory.getInstance().getRootComponent().inject(
65                                 SystemUIAppComponentFactory.this);
66                     }
67             );
68         }
69 
70         return app;
71     }
72 
73     @NonNull
74     @Override
instantiateProviderCompat( @onNull ClassLoader cl, @NonNull String className)75     public ContentProvider instantiateProviderCompat(
76             @NonNull ClassLoader cl, @NonNull String className)
77             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
78 
79         ContentProvider contentProvider = super.instantiateProviderCompat(cl, className);
80         if (contentProvider instanceof ContextInitializer) {
81             ((ContextInitializer) contentProvider).setContextAvailableCallback(
82                     context -> {
83                         SystemUIFactory.createFromConfig(context);
84                         SystemUIFactory.getInstance().getRootComponent().inject(
85                                 contentProvider);
86                     }
87             );
88         }
89 
90         return contentProvider;
91     }
92 
93     @NonNull
94     @Override
instantiateActivityCompat(@onNull ClassLoader cl, @NonNull String className, @Nullable Intent intent)95     public Activity instantiateActivityCompat(@NonNull ClassLoader cl, @NonNull String className,
96             @Nullable Intent intent)
97             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
98         if (mComponentHelper == null) {
99             // This shouldn't happen, but is seen on occasion.
100             // Bug filed against framework to take a look: http://b/141008541
101             SystemUIFactory.getInstance().getRootComponent().inject(
102                     SystemUIAppComponentFactory.this);
103         }
104         Activity activity = mComponentHelper.resolveActivity(className);
105         if (activity != null) {
106             return activity;
107         }
108         return super.instantiateActivityCompat(cl, className, intent);
109     }
110 
111     @NonNull
112     @Override
instantiateServiceCompat( @onNull ClassLoader cl, @NonNull String className, Intent intent)113     public Service instantiateServiceCompat(
114             @NonNull ClassLoader cl, @NonNull String className, Intent intent)
115             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
116         if (mComponentHelper == null) {
117             // This shouldn't happen, but does when a device is freshly formatted.
118             // Bug filed against framework to take a look: http://b/141008541
119             SystemUIFactory.getInstance().getRootComponent().inject(
120                     SystemUIAppComponentFactory.this);
121         }
122         Service service = mComponentHelper.resolveService(className);
123         if (service != null) {
124             return service;
125         }
126         return super.instantiateServiceCompat(cl, className, intent);
127     }
128 
129     @NonNull
130     @Override
instantiateReceiverCompat(@onNull ClassLoader cl, @NonNull String className, @Nullable Intent intent)131     public BroadcastReceiver instantiateReceiverCompat(@NonNull ClassLoader cl,
132             @NonNull String className, @Nullable Intent intent)
133             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
134         if (mComponentHelper == null) {
135             // This shouldn't happen, but does when a device is freshly formatted.
136             // Bug filed against framework to take a look: http://b/141008541
137             SystemUIFactory.getInstance().getRootComponent().inject(
138                     SystemUIAppComponentFactory.this);
139         }
140         BroadcastReceiver receiver = mComponentHelper.resolveBroadcastReceiver(className);
141         if (receiver != null) {
142             return receiver;
143         }
144 
145         return super.instantiateReceiverCompat(cl, className, intent);
146     }
147 
148     /**
149      * A callback that receives a Context when one is ready.
150      */
151     public interface ContextAvailableCallback {
onContextAvailable(Context context)152         void onContextAvailable(Context context);
153     }
154 
155     /**
156      * Implemented in classes that get started by the system before a context is available.
157      */
158     public interface ContextInitializer {
setContextAvailableCallback(ContextAvailableCallback callback)159         void setContextAvailableCallback(ContextAvailableCallback callback);
160     }
161 }
162