Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4a7136f authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Allow ContentProviders to be injected into.

This also allows ContentProviders to call Dependency.get() and similar,
dagger-dependent functions.

Bug: 139479357
Test: atest SystemUITests
Change-Id: I48f370f9506417b04394923fab6bf8cbf19804a4
parent 42e3357d
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package com.android.systemui;

import android.app.Service;

/**
 * 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);
    Service resolveService(String className);
}
+14 −7
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui;

import android.app.Service;

import java.util.Map;

import javax.inject.Inject;
@@ -25,21 +27,26 @@ 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;
    private final Map<Class<?>, Provider<Service>> mServiceCreators;

    @Inject
    ContextComponentResolver(Map<Class<?>, Provider<Object>> creators) {
        mCreators = creators;
    ContextComponentResolver(
            Map<Class<?>, Provider<Service>> serviceCreators) {
        mServiceCreators = serviceCreators;
    }

    /**
     * Looks up the class name to see if Dagger has an instance of it.
     * Looks up the Service 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()) {
    public Service resolveService(String className) {
        return resolve(className, mServiceCreators);
    }

    private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
        for (Map.Entry<Class<?>, Provider<T>> p : creators.entrySet()) {
            if (p.getKey().getName().equals(className)) {
                return (T) p.getValue().get();
                return p.getValue().get();
            }
        }

+3 −2
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui;

import android.app.Service;

import com.android.systemui.doze.DozeService;

import dagger.Binds;
@@ -36,6 +38,5 @@ public abstract class ServiceBinder {
    @Binds
    @IntoMap
    @ClassKey(DozeService.class)
    public abstract Object bindDozeService(DozeService service);

    public abstract Service bindDozeService(DozeService service);
}
+48 −18
Original line number Diff line number Diff line
@@ -18,16 +18,25 @@ package com.android.systemui;

import android.app.Application;
import android.app.Service;
import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;

import androidx.core.app.CoreComponentFactory;
import androidx.annotation.NonNull;
import androidx.core.app.AppComponentFactory;

import javax.inject.Inject;

/**
 * Implementation of AppComponentFactory that injects into constructors.
 *
 * This class sets up dependency injection when creating our application.
 *
 * Services support dependency injection into their constructors.
 *
 * ContentProviders support injection into member variables - _not_ constructors.
 */
public class SystemUIAppComponentFactory extends CoreComponentFactory {
public class SystemUIAppComponentFactory extends AppComponentFactory {

    @Inject
    public ContextComponentHelper mComponentHelper;
@@ -36,12 +45,14 @@ public class SystemUIAppComponentFactory extends CoreComponentFactory {
        super();
    }

    @NonNull
    @Override
    public Application instantiateApplication(ClassLoader cl, String className)
    public Application instantiateApplicationCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Application app = super.instantiateApplication(cl, className);
        if (app instanceof SystemUIApplication) {
            ((SystemUIApplication) app).setContextAvailableCallback(
        Application app = super.instantiateApplicationCompat(cl, className);
        if (app instanceof ContextProvider) {
            ((ContextProvider) app).setContextAvailableCallback(
                    context -> {
                        SystemUIFactory.createFromConfig(context);
                        SystemUIFactory.getInstance().getRootComponent().inject(
@@ -53,24 +64,43 @@ public class SystemUIAppComponentFactory extends CoreComponentFactory {
        return app;
    }

    @NonNull
    @Override
    public Service instantiateService(ClassLoader cl, String className, Intent intent)
    public ContentProvider instantiateProviderCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Service service = mComponentHelper.resolve(className);
        if (service != null) {
            return checkCompatWrapper(service);

        ContentProvider contentProvider = super.instantiateProviderCompat(cl, className);
        if (contentProvider instanceof ContextProvider) {
            ((ContextProvider) contentProvider).setContextAvailableCallback(
                    context -> {
                        SystemUIFactory.createFromConfig(context);
                        SystemUIFactory.getInstance().getRootComponent().inject(
                                contentProvider);
                    }
        return super.instantiateService(cl, className, intent);
            );
        }

        return contentProvider;
    }

    static <T> T checkCompatWrapper(T obj) {
        if (obj instanceof CompatWrapped) {
            T wrapper = (T) ((CompatWrapped) obj).getWrapper();
            if (wrapper != null) {
                return wrapper;
    @NonNull
    @Override
    public Service instantiateServiceCompat(
            @NonNull ClassLoader cl, @NonNull String className, Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Service service = mComponentHelper.resolveService(className);
        if (service != null) {
            return service;
        }
        return super.instantiateServiceCompat(cl, className, intent);
    }

    interface ContextAvailableCallback {
        void onContextAvailable(Context context);
    }

        return obj;
    interface ContextProvider {
        void setContextAvailableCallback(ContextAvailableCallback callback);
    }
}
+6 −6
Original line number Diff line number Diff line
@@ -48,7 +48,8 @@ import java.util.Map;
/**
 * Application class for SystemUI.
 */
public class SystemUIApplication extends Application implements SysUiServiceProvider {
public class SystemUIApplication extends Application implements SysUiServiceProvider,
        SystemUIAppComponentFactory.ContextProvider {

    public static final String TAG = "SystemUIService";
    private static final boolean DEBUG = false;
@@ -60,7 +61,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
    private boolean mServicesStarted;
    private boolean mBootCompleted;
    private final Map<Class<?>, Object> mComponents = new HashMap<>();
    private ContextAvailableCallback mContextAvailableCallback;
    private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;

    @Override
    public void onCreate() {
@@ -290,11 +291,10 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
        return mServices;
    }

    void setContextAvailableCallback(ContextAvailableCallback callback) {
    @Override
    public void setContextAvailableCallback(
            SystemUIAppComponentFactory.ContextAvailableCallback callback) {
        mContextAvailableCallback = callback;
    }

    interface ContextAvailableCallback {
        void onContextAvailable(Context context);
    }
}
Loading