Allow Services to be created through Dagger.
This is a significant change that allows Services to have their constructed injected into. This change includes DozeService as an example, injecting the FalsingManager into its constructor. Bug: 136279712 Test: atest SystemUITests Change-Id: Ib58f8763c996fbc2aea07ead56493d2d9e936f5b
This commit is contained in:
@@ -26,8 +26,8 @@ android_app {
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"CarNotificationLib",
|
||||
"SystemUI-core",
|
||||
"CarNotificationLib",
|
||||
"SystemUIPluginLib",
|
||||
"SystemUISharedLib",
|
||||
"SettingsLib",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
package="com.android.systemui"
|
||||
android:sharedUserId="android.uid.systemui"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
coreApp="true">
|
||||
|
||||
<!-- Using OpenGL ES 2.0 -->
|
||||
@@ -259,7 +260,8 @@
|
||||
android:theme="@style/Theme.SystemUI"
|
||||
android:defaultToDeviceProtectedStorage="true"
|
||||
android:directBootAware="true"
|
||||
android:appComponentFactory="androidx.core.app.CoreComponentFactory">
|
||||
tools:replace="android:appComponentFactory"
|
||||
android:appComponentFactory=".SystemUIAppComponentFactory">
|
||||
<!-- Keep theme in sync with SystemUIApplication.onCreate().
|
||||
Setting the theme on the application does not affect views inflated by services.
|
||||
The application theme is set again from onCreate to take effect for those views. -->
|
||||
|
||||
@@ -53,7 +53,7 @@ variants (like other form factors e.g. Car).
|
||||
### Adding injection to a new SystemUI object
|
||||
|
||||
Anything that depends on any `@Singleton` provider from SystemUIRootComponent
|
||||
should be declared as an `@Subcomponent` of the root component, this requires
|
||||
should be declared as a `@Subcomponent` of the root component. This requires
|
||||
declaring your own interface for generating your own modules or just the
|
||||
object you need injected. The subcomponent also needs to be added to
|
||||
SystemUIRootComponent in SystemUIFactory so it can be acquired.
|
||||
@@ -204,6 +204,13 @@ public CustomView(@Named(VIEW_CONTEXT) Context themedViewContext, AttributeSet a
|
||||
}
|
||||
```
|
||||
|
||||
## Updating Dagger2
|
||||
|
||||
Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded
|
||||
into
|
||||
[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/)
|
||||
|
||||
|
||||
## TODO List
|
||||
|
||||
- Eliminate usages of Dependency#get
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
/**
|
||||
* Interface necessary to make Dagger happy. See {@link ContextComponentResolver}.
|
||||
*/
|
||||
public interface ContextComponentHelper {
|
||||
/** Turns a classname into an instance of the class or returns null. */
|
||||
<T> T resolve(String className);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
/**
|
||||
* Used during Service and Activity instantiation to make them injectable.
|
||||
*/
|
||||
public class ContextComponentResolver implements ContextComponentHelper {
|
||||
private final Map<Class<?>, Provider<Object>> mCreators;
|
||||
|
||||
@Inject
|
||||
ContextComponentResolver(Map<Class<?>, Provider<Object>> creators) {
|
||||
mCreators = creators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the class name to see if Dagger has an instance of it.
|
||||
*/
|
||||
@Override
|
||||
public <T> T resolve(String className) {
|
||||
for (Map.Entry<Class<?>, Provider<Object>> p : mCreators.entrySet()) {
|
||||
if (p.getKey().getName().equals(className)) {
|
||||
return (T) p.getValue().get();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import com.android.systemui.doze.DozeService;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.ClassKey;
|
||||
import dagger.multibindings.IntoMap;
|
||||
|
||||
/**
|
||||
* Services and Activities that are injectable should go here.
|
||||
*/
|
||||
@Module
|
||||
public abstract class ServiceBinder {
|
||||
|
||||
@Binds
|
||||
public abstract ContextComponentHelper bindComponentHelper(
|
||||
ContextComponentResolver componentHelper);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(DozeService.class)
|
||||
public abstract Object bindDozeService(DozeService service);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.core.app.CoreComponentFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Implementation of AppComponentFactory that injects into constructors.
|
||||
*/
|
||||
public class SystemUIAppComponentFactory extends CoreComponentFactory {
|
||||
|
||||
@Inject
|
||||
public ContextComponentHelper mComponentHelper;
|
||||
|
||||
public SystemUIAppComponentFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Application instantiateApplication(ClassLoader cl, String className)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
Application app = super.instantiateApplication(cl, className);
|
||||
if (app instanceof SystemUIApplication) {
|
||||
((SystemUIApplication) app).setContextAvailableCallback(
|
||||
context -> {
|
||||
SystemUIFactory.createFromConfig(context);
|
||||
SystemUIFactory.getInstance().getRootComponent().inject(
|
||||
SystemUIAppComponentFactory.this);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Service instantiateService(ClassLoader cl, String className, Intent intent)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
Service service = mComponentHelper.resolve(className);
|
||||
if (service != null) {
|
||||
return checkCompatWrapper(service);
|
||||
}
|
||||
return super.instantiateService(cl, className, intent);
|
||||
}
|
||||
|
||||
static <T> T checkCompatWrapper(T obj) {
|
||||
if (obj instanceof CompatWrapped) {
|
||||
T wrapper = (T) ((CompatWrapped) obj).getWrapper();
|
||||
if (wrapper != null) {
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
@@ -60,16 +60,20 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
|
||||
private boolean mServicesStarted;
|
||||
private boolean mBootCompleted;
|
||||
private final Map<Class<?>, Object> mComponents = new HashMap<>();
|
||||
private ContextAvailableCallback mContextAvailableCallback;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// This line is used to setup Dagger's dependency injection and should be kept at the
|
||||
// top of this method.
|
||||
mContextAvailableCallback.onContextAvailable(this);
|
||||
|
||||
// Set the application theme that is inherited by all services. Note that setting the
|
||||
// application theme in the manifest does only work for activities. Keep this in sync with
|
||||
// the theme set there.
|
||||
setTheme(R.style.Theme_SystemUI);
|
||||
|
||||
SystemUIFactory.createFromConfig(this);
|
||||
|
||||
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
|
||||
IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
|
||||
@@ -286,4 +290,12 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
|
||||
public SystemUI[] getServices() {
|
||||
return mServices;
|
||||
}
|
||||
|
||||
void setContextAvailableCallback(ContextAvailableCallback callback) {
|
||||
mContextAvailableCallback = callback;
|
||||
}
|
||||
|
||||
interface ContextAvailableCallback {
|
||||
void onContextAvailable(Context context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.keyguard.ViewMediatorCallback;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.dock.DockManager;
|
||||
import com.android.systemui.fragments.FragmentService;
|
||||
import com.android.systemui.keyguard.DismissCallbackRegistry;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
@@ -68,8 +67,6 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
import com.android.systemui.statusbar.phone.UnlockMethodCache;
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
|
||||
import com.android.systemui.util.AsyncSensorManager;
|
||||
import com.android.systemui.util.InjectionInflationController;
|
||||
import com.android.systemui.util.leak.GarbageMonitor;
|
||||
import com.android.systemui.volume.VolumeDialogComponent;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
@@ -77,7 +74,6 @@ import java.util.function.Consumer;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Component;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@@ -115,7 +111,7 @@ public class SystemUIFactory {
|
||||
public SystemUIFactory() {}
|
||||
|
||||
protected void init(Context context) {
|
||||
initWithRootComponent(DaggerSystemUIFactory_SystemUIRootComponent.builder()
|
||||
initWithRootComponent(DaggerSystemUIRootComponent.builder()
|
||||
.systemUIFactory(this)
|
||||
.dependencyProvider(new com.android.systemui.DependencyProvider())
|
||||
.contextHolder(new ContextHolder(context))
|
||||
@@ -276,29 +272,4 @@ public class SystemUIFactory {
|
||||
return mContext;
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class,
|
||||
ContextHolder.class})
|
||||
public interface SystemUIRootComponent {
|
||||
@Singleton
|
||||
Dependency.DependencyInjector createDependency();
|
||||
|
||||
@Singleton
|
||||
StatusBar.StatusBarInjector getStatusBarInjector();
|
||||
|
||||
/**
|
||||
* FragmentCreator generates all Fragments that need injection.
|
||||
*/
|
||||
@Singleton
|
||||
FragmentService.FragmentCreator createFragmentCreator();
|
||||
|
||||
/**
|
||||
* ViewCreator generates all Views that need injection.
|
||||
*/
|
||||
InjectionInflationController.ViewCreator createViewCreator();
|
||||
|
||||
@Singleton
|
||||
GarbageMonitor createGarbageMonitor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import com.android.systemui.fragments.FragmentService;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.util.InjectionInflationController;
|
||||
import com.android.systemui.util.leak.GarbageMonitor;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
/**
|
||||
* Root component for Dagger injection.
|
||||
*/
|
||||
@Singleton
|
||||
@Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class,
|
||||
ServiceBinder.class, SystemUIFactory.ContextHolder.class})
|
||||
public interface SystemUIRootComponent {
|
||||
/**
|
||||
* Main dependency providing module.
|
||||
*/
|
||||
@Singleton
|
||||
Dependency.DependencyInjector createDependency();
|
||||
|
||||
/**
|
||||
* Injects the StatusBar.
|
||||
*/
|
||||
@Singleton
|
||||
StatusBar.StatusBarInjector getStatusBarInjector();
|
||||
|
||||
/**
|
||||
* FragmentCreator generates all Fragments that need injection.
|
||||
*/
|
||||
@Singleton
|
||||
FragmentService.FragmentCreator createFragmentCreator();
|
||||
|
||||
/**
|
||||
* ViewCreator generates all Views that need injection.
|
||||
*/
|
||||
InjectionInflationController.ViewCreator createViewCreator();
|
||||
|
||||
/**
|
||||
* Creatse a GarbageMonitor.
|
||||
*/
|
||||
@Singleton
|
||||
GarbageMonitor createGarbageMonitor();
|
||||
|
||||
/**
|
||||
* Injects into the supplied argument.
|
||||
*/
|
||||
void inject(SystemUIAppComponentFactory factory);
|
||||
}
|
||||
@@ -32,17 +32,22 @@ import com.android.systemui.shared.plugins.PluginManager;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DozeService extends DreamService
|
||||
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
|
||||
private static final String TAG = "DozeService";
|
||||
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private final FalsingManager mFalsingManager;
|
||||
|
||||
private DozeMachine mDozeMachine;
|
||||
private DozeServicePlugin mDozePlugin;
|
||||
private PluginManager mPluginManager;
|
||||
|
||||
public DozeService() {
|
||||
@Inject
|
||||
public DozeService(FalsingManager falsingManager) {
|
||||
setDebug(DEBUG);
|
||||
mFalsingManager = falsingManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,8 +62,7 @@ public class DozeService extends DreamService
|
||||
}
|
||||
mPluginManager = Dependency.get(PluginManager.class);
|
||||
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
|
||||
mDozeMachine = new DozeFactory().assembleMachine(
|
||||
this, Dependency.get(FalsingManager.class));
|
||||
mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,7 +22,7 @@ import android.view.View;
|
||||
|
||||
import com.android.systemui.ConfigurationChangedReceiver;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.SystemUIFactory;
|
||||
import com.android.systemui.SystemUIRootComponent;
|
||||
import com.android.systemui.qs.QSFragment;
|
||||
import com.android.systemui.statusbar.phone.NavigationBarFragment;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class FragmentService implements ConfigurationChangedReceiver, Dumpable {
|
||||
private final FragmentCreator mFragmentCreator;
|
||||
|
||||
@Inject
|
||||
public FragmentService(SystemUIFactory.SystemUIRootComponent rootComponent) {
|
||||
public FragmentService(SystemUIRootComponent rootComponent) {
|
||||
mFragmentCreator = rootComponent.createFragmentCreator();
|
||||
initInjectionMap();
|
||||
}
|
||||
|
||||
@@ -2063,10 +2063,11 @@ public class KeyguardViewMediator extends SystemUI {
|
||||
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
|
||||
ViewGroup container, NotificationPanelView panelView,
|
||||
BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer,
|
||||
View notificationContainer, KeyguardBypassController bypassController, FalsingManager falsingManager) {
|
||||
View notificationContainer, KeyguardBypassController bypassController,
|
||||
FalsingManager falsingManager) {
|
||||
mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
|
||||
biometricUnlockController, mDismissCallbackRegistry, lockIconContainer,
|
||||
notificationContainer, bypassController, falsingManager);
|
||||
notificationContainer, bypassController, falsingManager);
|
||||
return mStatusBarKeyguardViewManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ import android.metrics.LogMaker;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
@@ -26,7 +26,7 @@ import android.view.View;
|
||||
import com.android.keyguard.KeyguardClockSwitch;
|
||||
import com.android.keyguard.KeyguardMessageArea;
|
||||
import com.android.keyguard.KeyguardSliceView;
|
||||
import com.android.systemui.SystemUIFactory;
|
||||
import com.android.systemui.SystemUIRootComponent;
|
||||
import com.android.systemui.qs.QSCarrierGroup;
|
||||
import com.android.systemui.qs.QSFooterImpl;
|
||||
import com.android.systemui.qs.QSPanel;
|
||||
@@ -62,7 +62,7 @@ public class InjectionInflationController {
|
||||
private final LayoutInflater.Factory2 mFactory = new InjectionFactory();
|
||||
|
||||
@Inject
|
||||
public InjectionInflationController(SystemUIFactory.SystemUIRootComponent rootComponent) {
|
||||
public InjectionInflationController(SystemUIRootComponent rootComponent) {
|
||||
mViewCreator = rootComponent.createViewCreator();
|
||||
initInjectionMap();
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
BiometricUnlockController fingerprintUnlockController,
|
||||
DismissCallbackRegistry dismissCallbackRegistry,
|
||||
ViewGroup lockIconContainer, View notificationContainer,
|
||||
KeyguardBypassController bypassController) {
|
||||
KeyguardBypassController bypassController, FalsingManager falsingManager) {
|
||||
super.registerStatusBar(statusBar, container, notificationPanelView,
|
||||
fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer,
|
||||
notificationContainer, bypassController, falsingManager);
|
||||
|
||||
Reference in New Issue
Block a user