xref: /aosp_15_r20/external/dagger2/java/dagger/android/AndroidInjection.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
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