/* * Copyright (C) 2017 The Dagger Authors. * * 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 dagger.android; import static android.util.Log.DEBUG; import static dagger.internal.Preconditions.checkNotNull; import android.app.Activity; import android.app.Application; import android.app.Fragment; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentProvider; import android.content.Context; import android.util.Log; import dagger.internal.Beta; /** Injects core Android types. */ @Beta public final class AndroidInjection { private static final String TAG = "dagger.android"; /** * Injects {@code activity} if an associated {@link AndroidInjector} implementation can be found, * otherwise throws an {@link IllegalArgumentException}. * * @throws RuntimeException if the {@link Application} doesn't implement {@link * HasAndroidInjector} or {@link HasActivityInjector}. */ public static void inject(Activity activity) { checkNotNull(activity, "activity"); Application application = activity.getApplication(); AndroidInjector injector; if (application instanceof HasAndroidInjector) { injector = ((HasAndroidInjector) application).androidInjector(); checkNotNull(injector, "%s.androidInjector() returned null", application.getClass()); } else if (application instanceof HasActivityInjector) { injector = ((HasActivityInjector) application).activityInjector(); checkNotNull(injector, "%s.activityInjector() returned null", application.getClass()); } else { throw new RuntimeException( String.format( "%s does not implement %s or %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName(), HasActivityInjector.class.getCanonicalName())); } injector.inject(activity); } /** * Injects {@code fragment} if an associated {@link AndroidInjector} implementation can be found, * otherwise throws an {@link IllegalArgumentException}. * *

Uses the following algorithm to find the appropriate {@link AndroidInjector} to use to * inject {@code fragment}: * *

    *
  1. Walks the parent-fragment hierarchy to find a fragment that implements {@link * HasAndroidInjector} or {@link HasFragmentInjector}, and if none do *
  2. Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements * {@link HasAndroidInjector} or {@link HasFragmentInjector}, and if not *
  3. Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector} * {@link HasFragmentInjector}. *
* * If none of them implement {@link HasAndroidInjector} or {@link HasFragmentInjector}, a {@link * IllegalArgumentException} is thrown. * * @throws IllegalArgumentException if no parent fragment, activity, or application implements * {@link HasAndroidInjector} or {@link HasFragmentInjector}. */ public static void inject(Fragment fragment) { checkNotNull(fragment, "fragment"); Object hasInjector = findHasFragmentInjector(fragment); AndroidInjector injector; if (hasInjector instanceof HasAndroidInjector) { injector = ((HasAndroidInjector) hasInjector).androidInjector(); checkNotNull(injector, "%s.androidInjector() returned null", hasInjector.getClass()); } else if (hasInjector instanceof HasFragmentInjector) { injector = ((HasFragmentInjector) hasInjector).fragmentInjector(); checkNotNull(injector, "%s.fragmentInjector() returned null", hasInjector.getClass()); } else { throw new RuntimeException( String.format( "%s does not implement %s or %s", hasInjector.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName(), HasFragmentInjector.class.getCanonicalName())); } if (Log.isLoggable(TAG, DEBUG)) { Log.d( TAG, String.format( "An injector for %s was found in %s", fragment.getClass().getCanonicalName(), hasInjector.getClass().getCanonicalName())); } injector.inject(fragment); } private static Object findHasFragmentInjector(Fragment fragment) { Fragment parentFragment = fragment; while ((parentFragment = parentFragment.getParentFragment()) != null) { if (parentFragment instanceof HasAndroidInjector || parentFragment instanceof HasFragmentInjector) { return parentFragment; } } Activity activity = fragment.getActivity(); if (activity instanceof HasAndroidInjector || activity instanceof HasFragmentInjector) { return activity; } Application application = activity.getApplication(); if (application instanceof HasAndroidInjector || application instanceof HasFragmentInjector) { return application; } throw new IllegalArgumentException( String.format("No injector was found for %s", fragment.getClass().getCanonicalName())); } /** * Injects {@code service} if an associated {@link AndroidInjector} implementation can be found, * otherwise throws an {@link IllegalArgumentException}. * * @throws RuntimeException if the {@link Application} doesn't implement {@link * HasAndroidInjector} or {@link HasServiceInjector}. */ public static void inject(Service service) { checkNotNull(service, "service"); Application application = service.getApplication(); AndroidInjector injector; if (application instanceof HasAndroidInjector) { injector = ((HasAndroidInjector) application).androidInjector(); checkNotNull(injector, "%s.androidInjector() returned null", application.getClass()); } else if (application instanceof HasServiceInjector) { injector = ((HasServiceInjector) application).serviceInjector(); checkNotNull(injector, "%s.serviceInjector() returned null", application.getClass()); } else { throw new RuntimeException( String.format( "%s does not implement %s or %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName(), HasServiceInjector.class.getCanonicalName())); } injector.inject(service); } /** * Injects {@code broadcastReceiver} if an associated {@link AndroidInjector} implementation can * be found, otherwise throws an {@link IllegalArgumentException}. * * @throws RuntimeException if the {@link Application} from {@link * Context#getApplicationContext()} doesn't implement {@link HasAndroidInjector} or {@link * HasBroadcastReceiverInjector}. */ public static void inject(BroadcastReceiver broadcastReceiver, Context context) { checkNotNull(broadcastReceiver, "broadcastReceiver"); checkNotNull(context, "context"); Application application = (Application) context.getApplicationContext(); AndroidInjector injector; if (application instanceof HasAndroidInjector) { injector = ((HasAndroidInjector) application).androidInjector(); checkNotNull(injector, "%s.androidInjector() returned null", application.getClass()); } else if (application instanceof HasBroadcastReceiverInjector) { injector = ((HasBroadcastReceiverInjector) application).broadcastReceiverInjector(); checkNotNull( injector, "%s.broadcastReceiverInjector() returned null", application.getClass()); } else { throw new RuntimeException( String.format( "%s does not implement %s or %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName(), HasBroadcastReceiverInjector.class.getCanonicalName())); } injector.inject(broadcastReceiver); } /** * Injects {@code contentProvider} if an associated {@link AndroidInjector} implementation can be * found, otherwise throws an {@link IllegalArgumentException}. * * @throws RuntimeException if the {@link Application} doesn't implement {@link * HasAndroidInjector} or {@link HasContentProviderInjector}. */ public static void inject(ContentProvider contentProvider) { checkNotNull(contentProvider, "contentProvider"); Application application = (Application) contentProvider.getContext().getApplicationContext(); AndroidInjector injector; if (application instanceof HasAndroidInjector) { injector = ((HasAndroidInjector) application).androidInjector(); checkNotNull(injector, "%s.androidInjector() returned null", application.getClass()); } else if (application instanceof HasContentProviderInjector) { injector = ((HasContentProviderInjector) application).contentProviderInjector(); checkNotNull(injector, "%s.contentProviderInjector() returned null", application.getClass()); } else { throw new RuntimeException( String.format( "%s does not implement %s or %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName(), HasBroadcastReceiverInjector.class.getCanonicalName())); } injector.inject(contentProvider); } private AndroidInjection() {} }