xref: /aosp_15_r20/external/dagger2/java/dagger/android/AndroidInjection.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
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;
18 
19 import static android.util.Log.DEBUG;
20 import static dagger.internal.Preconditions.checkNotNull;
21 
22 import android.app.Activity;
23 import android.app.Application;
24 import android.app.Fragment;
25 import android.app.Service;
26 import android.content.BroadcastReceiver;
27 import android.content.ContentProvider;
28 import android.content.Context;
29 import android.util.Log;
30 import dagger.internal.Beta;
31 
32 /** Injects core Android types. */
33 @Beta
34 public final class AndroidInjection {
35   private static final String TAG = "dagger.android";
36 
37   /**
38    * Injects {@code activity} if an associated {@link AndroidInjector} implementation can be found,
39    * otherwise throws an {@link IllegalArgumentException}.
40    *
41    * @throws RuntimeException if the {@link Application} doesn't implement {@link
42    *     HasAndroidInjector}.
43    */
inject(Activity activity)44   public static void inject(Activity activity) {
45     checkNotNull(activity, "activity");
46     Application application = activity.getApplication();
47     if (!(application instanceof HasAndroidInjector)) {
48       throw new RuntimeException(
49           String.format(
50               "%s does not implement %s",
51               application.getClass().getCanonicalName(),
52               HasAndroidInjector.class.getCanonicalName()));
53     }
54 
55     inject(activity, (HasAndroidInjector) application);
56   }
57 
58   /**
59    * Injects {@code fragment} if an associated {@link AndroidInjector} implementation can be found,
60    * otherwise throws an {@link IllegalArgumentException}.
61    *
62    * <p>Uses the following algorithm to find the appropriate {@code AndroidInjector<Fragment>} to
63    * use to inject {@code fragment}:
64    *
65    * <ol>
66    *   <li>Walks the parent-fragment hierarchy to find the a fragment that implements {@link
67    *       HasAndroidInjector}, and if none do
68    *   <li>Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements
69    *       {@link HasAndroidInjector}, and if not
70    *   <li>Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}.
71    * </ol>
72    *
73    * If none of them implement {@link HasAndroidInjector}, a {@link IllegalArgumentException} is
74    * thrown.
75    *
76    * @throws IllegalArgumentException if no parent fragment, activity, or application implements
77    *     {@link HasAndroidInjector}.
78    */
inject(Fragment fragment)79   public static void inject(Fragment fragment) {
80     checkNotNull(fragment, "fragment");
81     HasAndroidInjector hasAndroidInjector = findHasAndroidInjectorForFragment(fragment);
82     if (Log.isLoggable(TAG, DEBUG)) {
83       Log.d(
84           TAG,
85           String.format(
86               "An injector for %s was found in %s",
87               fragment.getClass().getCanonicalName(),
88               hasAndroidInjector.getClass().getCanonicalName()));
89     }
90 
91     inject(fragment, hasAndroidInjector);
92   }
93 
findHasAndroidInjectorForFragment(Fragment fragment)94   private static HasAndroidInjector findHasAndroidInjectorForFragment(Fragment fragment) {
95     Fragment parentFragment = fragment;
96     while ((parentFragment = parentFragment.getParentFragment()) != null) {
97       if (parentFragment instanceof HasAndroidInjector) {
98         return (HasAndroidInjector) parentFragment;
99       }
100     }
101     Activity activity = fragment.getActivity();
102     if (activity instanceof HasAndroidInjector) {
103       return (HasAndroidInjector) activity;
104     }
105     if (activity.getApplication() instanceof HasAndroidInjector) {
106       return (HasAndroidInjector) activity.getApplication();
107     }
108     throw new IllegalArgumentException(
109         String.format("No injector was found for %s", fragment.getClass().getCanonicalName()));
110   }
111 
112   /**
113    * Injects {@code service} if an associated {@link AndroidInjector} implementation can be found,
114    * otherwise throws an {@link IllegalArgumentException}.
115    *
116    * @throws RuntimeException if the {@link Application} doesn't implement {@link
117    *     HasAndroidInjector}.
118    */
inject(Service service)119   public static void inject(Service service) {
120     checkNotNull(service, "service");
121     Application application = service.getApplication();
122     if (!(application instanceof HasAndroidInjector)) {
123       throw new RuntimeException(
124           String.format(
125               "%s does not implement %s",
126               application.getClass().getCanonicalName(),
127               HasAndroidInjector.class.getCanonicalName()));
128     }
129 
130     inject(service, (HasAndroidInjector) application);
131   }
132 
133   /**
134    * Injects {@code broadcastReceiver} if an associated {@link AndroidInjector} implementation can
135    * be found, otherwise throws an {@link IllegalArgumentException}.
136    *
137    * @throws RuntimeException if the {@link Application} from {@link
138    *     Context#getApplicationContext()} doesn't implement {@link HasAndroidInjector}.
139    */
inject(BroadcastReceiver broadcastReceiver, Context context)140   public static void inject(BroadcastReceiver broadcastReceiver, Context context) {
141     checkNotNull(broadcastReceiver, "broadcastReceiver");
142     checkNotNull(context, "context");
143     Application application = (Application) context.getApplicationContext();
144     if (!(application instanceof HasAndroidInjector)) {
145       throw new RuntimeException(
146           String.format(
147               "%s does not implement %s",
148               application.getClass().getCanonicalName(),
149               HasAndroidInjector.class.getCanonicalName()));
150     }
151 
152     inject(broadcastReceiver, (HasAndroidInjector) application);
153   }
154 
155   /**
156    * Injects {@code contentProvider} if an associated {@link AndroidInjector} implementation can be
157    * found, otherwise throws an {@link IllegalArgumentException}.
158    *
159    * @throws RuntimeException if the {@link Application} doesn't implement {@link
160    *     HasAndroidInjector}.
161    */
inject(ContentProvider contentProvider)162   public static void inject(ContentProvider contentProvider) {
163     checkNotNull(contentProvider, "contentProvider");
164     Application application = (Application) contentProvider.getContext().getApplicationContext();
165     if (!(application instanceof HasAndroidInjector)) {
166       throw new RuntimeException(
167           String.format(
168               "%s does not implement %s",
169               application.getClass().getCanonicalName(),
170               HasAndroidInjector.class.getCanonicalName()));
171     }
172 
173     inject(contentProvider, (HasAndroidInjector) application);
174   }
175 
inject(Object target, HasAndroidInjector hasAndroidInjector)176   private static void inject(Object target, HasAndroidInjector hasAndroidInjector) {
177     AndroidInjector<Object> androidInjector = hasAndroidInjector.androidInjector();
178     checkNotNull(
179         androidInjector, "%s.androidInjector() returned null", hasAndroidInjector.getClass());
180 
181     androidInjector.inject(target);
182   }
183 
AndroidInjection()184   private AndroidInjection() {}
185 }
186