1 /* 2 * Copyright (C) 2017 The Dagger Authors. 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 dagger.android.support; 18 19 import static android.util.Log.DEBUG; 20 import static dagger.internal.Preconditions.checkNotNull; 21 22 import android.app.Activity; 23 import androidx.fragment.app.Fragment; 24 import android.util.Log; 25 import dagger.android.AndroidInjector; 26 import dagger.android.HasAndroidInjector; 27 import dagger.internal.Beta; 28 29 /** Injects core Android types from support libraries. */ 30 @Beta 31 public final class AndroidSupportInjection { 32 private static final String TAG = "dagger.android.support"; 33 34 /** 35 * Injects {@code fragment} if an associated {@link AndroidInjector} implementation can be found, 36 * otherwise throws an {@link IllegalArgumentException}. 37 * 38 * <p>Uses the following algorithm to find the appropriate {@code AndroidInjector<Fragment>} to 39 * use to inject {@code fragment}: 40 * 41 * <ol> 42 * <li>Walks the parent-fragment hierarchy to find the a fragment that implements {@link 43 * HasAndroidInjector}, and if none do 44 * <li>Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements 45 * {@link HasAndroidInjector}, and if not 46 * <li>Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}. 47 * </ol> 48 * 49 * If none of them implement {@link HasAndroidInjector}, a {@link IllegalArgumentException} is 50 * thrown. 51 * 52 * @throws IllegalArgumentException if no parent fragment, activity, or application implements 53 * {@link HasAndroidInjector}. 54 */ inject(Fragment fragment)55 public static void inject(Fragment fragment) { 56 checkNotNull(fragment, "fragment"); 57 HasAndroidInjector hasAndroidInjector = findHasAndroidInjectorForFragment(fragment); 58 if (Log.isLoggable(TAG, DEBUG)) { 59 Log.d( 60 TAG, 61 String.format( 62 "An injector for %s was found in %s", 63 fragment.getClass().getCanonicalName(), 64 hasAndroidInjector.getClass().getCanonicalName())); 65 } 66 67 inject(fragment, hasAndroidInjector); 68 } 69 inject(Object target, HasAndroidInjector hasAndroidInjector)70 private static void inject(Object target, HasAndroidInjector hasAndroidInjector) { 71 AndroidInjector<Object> androidInjector = hasAndroidInjector.androidInjector(); 72 checkNotNull( 73 androidInjector, "%s.androidInjector() returned null", hasAndroidInjector.getClass()); 74 75 androidInjector.inject(target); 76 } 77 findHasAndroidInjectorForFragment(Fragment fragment)78 private static HasAndroidInjector findHasAndroidInjectorForFragment(Fragment fragment) { 79 Fragment parentFragment = fragment; 80 while ((parentFragment = parentFragment.getParentFragment()) != null) { 81 if (parentFragment instanceof HasAndroidInjector) { 82 return (HasAndroidInjector) parentFragment; 83 } 84 } 85 Activity activity = fragment.getActivity(); 86 if (activity instanceof HasAndroidInjector) { 87 return (HasAndroidInjector) activity; 88 } 89 if (activity.getApplication() instanceof HasAndroidInjector) { 90 return (HasAndroidInjector) activity.getApplication(); 91 } 92 throw new IllegalArgumentException( 93 String.format("No injector was found for %s", fragment.getClass().getCanonicalName())); 94 } 95 AndroidSupportInjection()96 private AndroidSupportInjection() {} 97 } 98