/* * 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}. */ public static void inject(Activity activity) { checkNotNull(activity, "activity"); Application application = activity.getApplication(); if (!(application instanceof HasAndroidInjector)) { throw new RuntimeException( String.format( "%s does not implement %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName())); } inject(activity, (HasAndroidInjector) application); } /** * 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 {@code AndroidInjector} to * use to inject {@code fragment}: * *

    *
  1. Walks the parent-fragment hierarchy to find the a fragment that implements {@link * HasAndroidInjector}, and if none do *
  2. Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements * {@link HasAndroidInjector}, and if not *
  3. Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}. *
* * If none of them implement {@link HasAndroidInjector}, a {@link IllegalArgumentException} is * thrown. * * @throws IllegalArgumentException if no parent fragment, activity, or application implements * {@link HasAndroidInjector}. */ public static void inject(Fragment fragment) { checkNotNull(fragment, "fragment"); HasAndroidInjector hasAndroidInjector = findHasAndroidInjectorForFragment(fragment); if (Log.isLoggable(TAG, DEBUG)) { Log.d( TAG, String.format( "An injector for %s was found in %s", fragment.getClass().getCanonicalName(), hasAndroidInjector.getClass().getCanonicalName())); } inject(fragment, hasAndroidInjector); } private static HasAndroidInjector findHasAndroidInjectorForFragment(Fragment fragment) { Fragment parentFragment = fragment; while ((parentFragment = parentFragment.getParentFragment()) != null) { if (parentFragment instanceof HasAndroidInjector) { return (HasAndroidInjector) parentFragment; } } Activity activity = fragment.getActivity(); if (activity instanceof HasAndroidInjector) { return (HasAndroidInjector) activity; } if (activity.getApplication() instanceof HasAndroidInjector) { return (HasAndroidInjector) activity.getApplication(); } 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}. */ public static void inject(Service service) { checkNotNull(service, "service"); Application application = service.getApplication(); if (!(application instanceof HasAndroidInjector)) { throw new RuntimeException( String.format( "%s does not implement %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName())); } inject(service, (HasAndroidInjector) application); } /** * 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}. */ public static void inject(BroadcastReceiver broadcastReceiver, Context context) { checkNotNull(broadcastReceiver, "broadcastReceiver"); checkNotNull(context, "context"); Application application = (Application) context.getApplicationContext(); if (!(application instanceof HasAndroidInjector)) { throw new RuntimeException( String.format( "%s does not implement %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName())); } inject(broadcastReceiver, (HasAndroidInjector) application); } /** * 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}. */ public static void inject(ContentProvider contentProvider) { checkNotNull(contentProvider, "contentProvider"); Application application = (Application) contentProvider.getContext().getApplicationContext(); if (!(application instanceof HasAndroidInjector)) { throw new RuntimeException( String.format( "%s does not implement %s", application.getClass().getCanonicalName(), HasAndroidInjector.class.getCanonicalName())); } inject(contentProvider, (HasAndroidInjector) application); } private static void inject(Object target, HasAndroidInjector hasAndroidInjector) { AndroidInjector androidInjector = hasAndroidInjector.androidInjector(); checkNotNull( androidInjector, "%s.androidInjector() returned null", hasAndroidInjector.getClass()); androidInjector.inject(target); } private AndroidInjection() {} }