1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2017 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.android; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static android.util.Log.DEBUG; 20*f585d8a3SJacky Wang import static dagger.internal.Preconditions.checkNotNull; 21*f585d8a3SJacky Wang 22*f585d8a3SJacky Wang import android.app.Activity; 23*f585d8a3SJacky Wang import android.app.Application; 24*f585d8a3SJacky Wang import android.app.Fragment; 25*f585d8a3SJacky Wang import android.app.Service; 26*f585d8a3SJacky Wang import android.content.BroadcastReceiver; 27*f585d8a3SJacky Wang import android.content.ContentProvider; 28*f585d8a3SJacky Wang import android.content.Context; 29*f585d8a3SJacky Wang import android.util.Log; 30*f585d8a3SJacky Wang import dagger.internal.Beta; 31*f585d8a3SJacky Wang 32*f585d8a3SJacky Wang /** Injects core Android types. */ 33*f585d8a3SJacky Wang @Beta 34*f585d8a3SJacky Wang public final class AndroidInjection { 35*f585d8a3SJacky Wang private static final String TAG = "dagger.android"; 36*f585d8a3SJacky Wang 37*f585d8a3SJacky Wang /** 38*f585d8a3SJacky Wang * Injects {@code activity} if an associated {@link AndroidInjector} implementation can be found, 39*f585d8a3SJacky Wang * otherwise throws an {@link IllegalArgumentException}. 40*f585d8a3SJacky Wang * 41*f585d8a3SJacky Wang * @throws RuntimeException if the {@link Application} doesn't implement {@link 42*f585d8a3SJacky Wang * HasAndroidInjector}. 43*f585d8a3SJacky Wang */ inject(Activity activity)44*f585d8a3SJacky Wang public static void inject(Activity activity) { 45*f585d8a3SJacky Wang checkNotNull(activity, "activity"); 46*f585d8a3SJacky Wang Application application = activity.getApplication(); 47*f585d8a3SJacky Wang if (!(application instanceof HasAndroidInjector)) { 48*f585d8a3SJacky Wang throw new RuntimeException( 49*f585d8a3SJacky Wang String.format( 50*f585d8a3SJacky Wang "%s does not implement %s", 51*f585d8a3SJacky Wang application.getClass().getCanonicalName(), 52*f585d8a3SJacky Wang HasAndroidInjector.class.getCanonicalName())); 53*f585d8a3SJacky Wang } 54*f585d8a3SJacky Wang 55*f585d8a3SJacky Wang inject(activity, (HasAndroidInjector) application); 56*f585d8a3SJacky Wang } 57*f585d8a3SJacky Wang 58*f585d8a3SJacky Wang /** 59*f585d8a3SJacky Wang * Injects {@code fragment} if an associated {@link AndroidInjector} implementation can be found, 60*f585d8a3SJacky Wang * otherwise throws an {@link IllegalArgumentException}. 61*f585d8a3SJacky Wang * 62*f585d8a3SJacky Wang * <p>Uses the following algorithm to find the appropriate {@code AndroidInjector<Fragment>} to 63*f585d8a3SJacky Wang * use to inject {@code fragment}: 64*f585d8a3SJacky Wang * 65*f585d8a3SJacky Wang * <ol> 66*f585d8a3SJacky Wang * <li>Walks the parent-fragment hierarchy to find the a fragment that implements {@link 67*f585d8a3SJacky Wang * HasAndroidInjector}, and if none do 68*f585d8a3SJacky Wang * <li>Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements 69*f585d8a3SJacky Wang * {@link HasAndroidInjector}, and if not 70*f585d8a3SJacky Wang * <li>Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}. 71*f585d8a3SJacky Wang * </ol> 72*f585d8a3SJacky Wang * 73*f585d8a3SJacky Wang * If none of them implement {@link HasAndroidInjector}, a {@link IllegalArgumentException} is 74*f585d8a3SJacky Wang * thrown. 75*f585d8a3SJacky Wang * 76*f585d8a3SJacky Wang * @throws IllegalArgumentException if no parent fragment, activity, or application implements 77*f585d8a3SJacky Wang * {@link HasAndroidInjector}. 78*f585d8a3SJacky Wang */ inject(Fragment fragment)79*f585d8a3SJacky Wang public static void inject(Fragment fragment) { 80*f585d8a3SJacky Wang checkNotNull(fragment, "fragment"); 81*f585d8a3SJacky Wang HasAndroidInjector hasAndroidInjector = findHasAndroidInjectorForFragment(fragment); 82*f585d8a3SJacky Wang if (Log.isLoggable(TAG, DEBUG)) { 83*f585d8a3SJacky Wang Log.d( 84*f585d8a3SJacky Wang TAG, 85*f585d8a3SJacky Wang String.format( 86*f585d8a3SJacky Wang "An injector for %s was found in %s", 87*f585d8a3SJacky Wang fragment.getClass().getCanonicalName(), 88*f585d8a3SJacky Wang hasAndroidInjector.getClass().getCanonicalName())); 89*f585d8a3SJacky Wang } 90*f585d8a3SJacky Wang 91*f585d8a3SJacky Wang inject(fragment, hasAndroidInjector); 92*f585d8a3SJacky Wang } 93*f585d8a3SJacky Wang findHasAndroidInjectorForFragment(Fragment fragment)94*f585d8a3SJacky Wang private static HasAndroidInjector findHasAndroidInjectorForFragment(Fragment fragment) { 95*f585d8a3SJacky Wang Fragment parentFragment = fragment; 96*f585d8a3SJacky Wang while ((parentFragment = parentFragment.getParentFragment()) != null) { 97*f585d8a3SJacky Wang if (parentFragment instanceof HasAndroidInjector) { 98*f585d8a3SJacky Wang return (HasAndroidInjector) parentFragment; 99*f585d8a3SJacky Wang } 100*f585d8a3SJacky Wang } 101*f585d8a3SJacky Wang Activity activity = fragment.getActivity(); 102*f585d8a3SJacky Wang if (activity instanceof HasAndroidInjector) { 103*f585d8a3SJacky Wang return (HasAndroidInjector) activity; 104*f585d8a3SJacky Wang } 105*f585d8a3SJacky Wang if (activity.getApplication() instanceof HasAndroidInjector) { 106*f585d8a3SJacky Wang return (HasAndroidInjector) activity.getApplication(); 107*f585d8a3SJacky Wang } 108*f585d8a3SJacky Wang throw new IllegalArgumentException( 109*f585d8a3SJacky Wang String.format("No injector was found for %s", fragment.getClass().getCanonicalName())); 110*f585d8a3SJacky Wang } 111*f585d8a3SJacky Wang 112*f585d8a3SJacky Wang /** 113*f585d8a3SJacky Wang * Injects {@code service} if an associated {@link AndroidInjector} implementation can be found, 114*f585d8a3SJacky Wang * otherwise throws an {@link IllegalArgumentException}. 115*f585d8a3SJacky Wang * 116*f585d8a3SJacky Wang * @throws RuntimeException if the {@link Application} doesn't implement {@link 117*f585d8a3SJacky Wang * HasAndroidInjector}. 118*f585d8a3SJacky Wang */ inject(Service service)119*f585d8a3SJacky Wang public static void inject(Service service) { 120*f585d8a3SJacky Wang checkNotNull(service, "service"); 121*f585d8a3SJacky Wang Application application = service.getApplication(); 122*f585d8a3SJacky Wang if (!(application instanceof HasAndroidInjector)) { 123*f585d8a3SJacky Wang throw new RuntimeException( 124*f585d8a3SJacky Wang String.format( 125*f585d8a3SJacky Wang "%s does not implement %s", 126*f585d8a3SJacky Wang application.getClass().getCanonicalName(), 127*f585d8a3SJacky Wang HasAndroidInjector.class.getCanonicalName())); 128*f585d8a3SJacky Wang } 129*f585d8a3SJacky Wang 130*f585d8a3SJacky Wang inject(service, (HasAndroidInjector) application); 131*f585d8a3SJacky Wang } 132*f585d8a3SJacky Wang 133*f585d8a3SJacky Wang /** 134*f585d8a3SJacky Wang * Injects {@code broadcastReceiver} if an associated {@link AndroidInjector} implementation can 135*f585d8a3SJacky Wang * be found, otherwise throws an {@link IllegalArgumentException}. 136*f585d8a3SJacky Wang * 137*f585d8a3SJacky Wang * @throws RuntimeException if the {@link Application} from {@link 138*f585d8a3SJacky Wang * Context#getApplicationContext()} doesn't implement {@link HasAndroidInjector}. 139*f585d8a3SJacky Wang */ inject(BroadcastReceiver broadcastReceiver, Context context)140*f585d8a3SJacky Wang public static void inject(BroadcastReceiver broadcastReceiver, Context context) { 141*f585d8a3SJacky Wang checkNotNull(broadcastReceiver, "broadcastReceiver"); 142*f585d8a3SJacky Wang checkNotNull(context, "context"); 143*f585d8a3SJacky Wang Application application = (Application) context.getApplicationContext(); 144*f585d8a3SJacky Wang if (!(application instanceof HasAndroidInjector)) { 145*f585d8a3SJacky Wang throw new RuntimeException( 146*f585d8a3SJacky Wang String.format( 147*f585d8a3SJacky Wang "%s does not implement %s", 148*f585d8a3SJacky Wang application.getClass().getCanonicalName(), 149*f585d8a3SJacky Wang HasAndroidInjector.class.getCanonicalName())); 150*f585d8a3SJacky Wang } 151*f585d8a3SJacky Wang 152*f585d8a3SJacky Wang inject(broadcastReceiver, (HasAndroidInjector) application); 153*f585d8a3SJacky Wang } 154*f585d8a3SJacky Wang 155*f585d8a3SJacky Wang /** 156*f585d8a3SJacky Wang * Injects {@code contentProvider} if an associated {@link AndroidInjector} implementation can be 157*f585d8a3SJacky Wang * found, otherwise throws an {@link IllegalArgumentException}. 158*f585d8a3SJacky Wang * 159*f585d8a3SJacky Wang * @throws RuntimeException if the {@link Application} doesn't implement {@link 160*f585d8a3SJacky Wang * HasAndroidInjector}. 161*f585d8a3SJacky Wang */ inject(ContentProvider contentProvider)162*f585d8a3SJacky Wang public static void inject(ContentProvider contentProvider) { 163*f585d8a3SJacky Wang checkNotNull(contentProvider, "contentProvider"); 164*f585d8a3SJacky Wang Application application = (Application) contentProvider.getContext().getApplicationContext(); 165*f585d8a3SJacky Wang if (!(application instanceof HasAndroidInjector)) { 166*f585d8a3SJacky Wang throw new RuntimeException( 167*f585d8a3SJacky Wang String.format( 168*f585d8a3SJacky Wang "%s does not implement %s", 169*f585d8a3SJacky Wang application.getClass().getCanonicalName(), 170*f585d8a3SJacky Wang HasAndroidInjector.class.getCanonicalName())); 171*f585d8a3SJacky Wang } 172*f585d8a3SJacky Wang 173*f585d8a3SJacky Wang inject(contentProvider, (HasAndroidInjector) application); 174*f585d8a3SJacky Wang } 175*f585d8a3SJacky Wang inject(Object target, HasAndroidInjector hasAndroidInjector)176*f585d8a3SJacky Wang private static void inject(Object target, HasAndroidInjector hasAndroidInjector) { 177*f585d8a3SJacky Wang AndroidInjector<Object> androidInjector = hasAndroidInjector.androidInjector(); 178*f585d8a3SJacky Wang checkNotNull( 179*f585d8a3SJacky Wang androidInjector, "%s.androidInjector() returned null", hasAndroidInjector.getClass()); 180*f585d8a3SJacky Wang 181*f585d8a3SJacky Wang androidInjector.inject(target); 182*f585d8a3SJacky Wang } 183*f585d8a3SJacky Wang AndroidInjection()184*f585d8a3SJacky Wang private AndroidInjection() {} 185*f585d8a3SJacky Wang } 186