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