xref: /aosp_15_r20/external/dagger2/javatests/dagger/hilt/android/InjectionTest.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1 /*
2  * Copyright (C) 2020 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.hilt.android;
18 
19 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
20 import static com.google.common.truth.Truth.assertThat;
21 import static java.lang.annotation.RetentionPolicy.RUNTIME;
22 import static org.junit.Assert.fail;
23 
24 import android.annotation.TargetApi;
25 import android.app.Activity;
26 import android.app.IntentService;
27 import android.app.Service;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.os.Build;
32 import android.os.Bundle;
33 import android.os.IBinder;
34 import androidx.fragment.app.Fragment;
35 import androidx.fragment.app.FragmentActivity;
36 import android.util.AttributeSet;
37 import android.widget.LinearLayout;
38 import androidx.test.ext.junit.runners.AndroidJUnit4;
39 import dagger.Module;
40 import dagger.Provides;
41 import dagger.hilt.InstallIn;
42 import dagger.hilt.android.components.ActivityComponent;
43 import dagger.hilt.android.components.FragmentComponent;
44 import dagger.hilt.android.components.ServiceComponent;
45 import dagger.hilt.android.testing.HiltAndroidRule;
46 import dagger.hilt.android.testing.HiltAndroidTest;
47 import dagger.hilt.android.testing.HiltTestApplication;
48 import dagger.hilt.components.SingletonComponent;
49 import java.lang.annotation.ElementType;
50 import java.lang.annotation.Retention;
51 import java.lang.annotation.Target;
52 import java.util.concurrent.atomic.AtomicLong;
53 import javax.inject.Inject;
54 import javax.inject.Qualifier;
55 import javax.inject.Singleton;
56 import org.junit.Before;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.robolectric.Robolectric;
61 import org.robolectric.android.controller.ActivityController;
62 import org.robolectric.annotation.Config;
63 
64 @HiltAndroidTest
65 @RunWith(AndroidJUnit4.class)
66 // Robolectric requires Java9 to run API 29 and above, so use API 28 instead
67 @Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
68 public final class InjectionTest {
69   private static final String APP_BINDING = "APP_BINDING";
70   private static final String ACTIVITY_BINDING = "ACTIVIY_BINDING";
71   private static final String FRAGMENT_BINDING = "FRAGMENT_BINDING";
72   private static final String SERVICE_BINDING = "SERVICE_BINDING";
73 
74   @Retention(RUNTIME)
75   @Qualifier
76   @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
77   @interface ApplicationLevel {}
78 
79   @Retention(RUNTIME)
80   @Qualifier
81   @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
82   @interface ActivityLevel {}
83 
84   @Retention(RUNTIME)
85   @Qualifier
86   @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
87   @interface FragmentLevel {}
88 
89   @Retention(RUNTIME)
90   @Qualifier
91   @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
92   @interface ServiceLevel {}
93 
94   /** Application level bindings */
95   @Module
96   @InstallIn(SingletonComponent.class)
97   static final class AppModule {
98     @Provides
99     @ApplicationLevel
providesAppBinding()100     static String providesAppBinding() {
101       return APP_BINDING;
102     }
103 
104     @Provides
105     @Singleton
provideCounter()106     static AtomicLong provideCounter() {
107       return new AtomicLong();
108     }
109 
110     @Provides
provideCount(AtomicLong counter)111     static Long provideCount(AtomicLong counter) {
112       return counter.incrementAndGet();
113     }
114   }
115 
116   /** Activity level bindings */
117   @Module
118   @InstallIn(ActivityComponent.class)
119   static final class ActivityModule {
120     @Provides
121     @ActivityLevel
providesActivityBinding()122     static String providesActivityBinding() {
123       return ACTIVITY_BINDING;
124     }
125   }
126 
127   /** Fragment level bindings */
128   @Module
129   @InstallIn(FragmentComponent.class)
130   static final class FragmentModule {
131     @Provides
132     @FragmentLevel
providesFragmentBinding()133     static String providesFragmentBinding() {
134       return FRAGMENT_BINDING;
135     }
136   }
137 
138   /** Service level bindings */
139   @Module
140   @InstallIn(ServiceComponent.class)
141   static final class ServiceModule {
142     @Provides
143     @ServiceLevel
providesServiceBinding()144     static String providesServiceBinding() {
145       return SERVICE_BINDING;
146     }
147   }
148 
149   /** Hilt Activity */
150   @AndroidEntryPoint(FragmentActivity.class)
151   public static final class TestActivity extends Hilt_InjectionTest_TestActivity {
152     @Inject @ApplicationLevel String appBinding;
153     @Inject @ActivityLevel String activityBinding;
154     boolean onCreateCalled;
155 
156     @Override
onCreate(Bundle onSavedInstanceState)157     public void onCreate(Bundle onSavedInstanceState) {
158       assertThat(appBinding).isNull();
159       assertThat(activityBinding).isNull();
160 
161       super.onCreate(onSavedInstanceState);
162 
163       assertThat(appBinding).isEqualTo(APP_BINDING);
164       assertThat(activityBinding).isEqualTo(ACTIVITY_BINDING);
165 
166       onCreateCalled = true;
167     }
168   }
169 
170   /** Non-Hilt Activity */
171   public static final class NonHiltActivity extends FragmentActivity {}
172 
173   /** Hilt Fragment */
174   @AndroidEntryPoint(Fragment.class)
175   public static final class TestFragment extends Hilt_InjectionTest_TestFragment {
176     @Inject @ApplicationLevel String appBinding;
177     @Inject @ActivityLevel String activityBinding;
178     @Inject @FragmentLevel String fragmentBinding;
179     boolean onAttachContextCalled;
180     boolean onAttachActivityCalled;
181 
182     @Override
onAttach(Context context)183     public void onAttach(Context context) {
184       preInjectionAssert();
185       super.onAttach(context);
186       postInjectionAssert();
187       onAttachContextCalled = true;
188     }
189 
190     @Override
onAttach(Activity activity)191     public void onAttach(Activity activity) {
192       preInjectionAssert();
193       super.onAttach(activity);
194       postInjectionAssert();
195       onAttachActivityCalled = true;
196     }
197 
preInjectionAssert()198     private void preInjectionAssert() {
199       assertThat(appBinding).isNull();
200       assertThat(activityBinding).isNull();
201       assertThat(fragmentBinding).isNull();
202     }
203 
postInjectionAssert()204     private void postInjectionAssert() {
205       assertThat(appBinding).isEqualTo(APP_BINDING);
206       assertThat(activityBinding).isEqualTo(ACTIVITY_BINDING);
207       assertThat(fragmentBinding).isEqualTo(FRAGMENT_BINDING);
208     }
209   }
210 
211   /** Non-Hilt Fragment */
212   public static final class NonHiltFragment extends Fragment {}
213 
214   /** Hilt extends parameterized fragment. */
215   @AndroidEntryPoint(ParameterizedFragment.class)
216   public static final class TestParameterizedFragment
217       extends Hilt_InjectionTest_TestParameterizedFragment<Integer> {
218     @Inject @ApplicationLevel String appBinding;
219     @Inject @ActivityLevel String activityBinding;
220     @Inject @FragmentLevel String fragmentBinding;
221     boolean onAttachContextCalled;
222     boolean onAttachActivityCalled;
223 
224     @Override
onAttach(Context context)225     public void onAttach(Context context) {
226       preInjectionAssert();
227       super.onAttach(context);
228       postInjectionAssert();
229       onAttachContextCalled = true;
230     }
231 
232     @Override
onAttach(Activity activity)233     public void onAttach(Activity activity) {
234       preInjectionAssert();
235       super.onAttach(activity);
236       postInjectionAssert();
237       onAttachActivityCalled = true;
238     }
239 
preInjectionAssert()240     private void preInjectionAssert() {
241       assertThat(appBinding).isNull();
242       assertThat(activityBinding).isNull();
243       assertThat(fragmentBinding).isNull();
244     }
245 
postInjectionAssert()246     private void postInjectionAssert() {
247       assertThat(appBinding).isEqualTo(APP_BINDING);
248       assertThat(activityBinding).isEqualTo(ACTIVITY_BINDING);
249       assertThat(fragmentBinding).isEqualTo(FRAGMENT_BINDING);
250     }
251   }
252 
253   /** Non-Hilt parameterized fragment */
254   public static class ParameterizedFragment<T> extends Fragment {}
255 
256   /** Hilt View */
257   @AndroidEntryPoint(LinearLayout.class)
258   public static final class TestView extends Hilt_InjectionTest_TestView {
259     @Inject @ApplicationLevel String appBinding;
260     @Inject @ActivityLevel String activityBinding;
261 
TestView(Context context)262     TestView(Context context) {
263       super(context);
264     }
265 
TestView(Context context, AttributeSet attrs)266     TestView(Context context, AttributeSet attrs) {
267       super(context, attrs);
268     }
269 
TestView(Context context, AttributeSet attrs, int defStyleAttr)270     TestView(Context context, AttributeSet attrs, int defStyleAttr) {
271       super(context, attrs, defStyleAttr);
272     }
273 
274     @TargetApi(21)
TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)275     TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
276       super(context, attrs, defStyleAttr, defStyleRes);
277     }
278   }
279 
280   /** Hilt View (With Fragment bindings) */
281   @WithFragmentBindings
282   @AndroidEntryPoint(LinearLayout.class)
283   public static final class TestViewWithFragmentBindings
284       extends Hilt_InjectionTest_TestViewWithFragmentBindings {
285     @Inject @ApplicationLevel String appBinding;
286     @Inject @ActivityLevel String activityBinding;
287     @Inject @FragmentLevel String fragmentBinding;
288 
TestViewWithFragmentBindings(Context context)289     TestViewWithFragmentBindings(Context context) {
290       super(context);
291     }
292   }
293 
294   @AndroidEntryPoint(Service.class)
295   public static final class TestService extends Hilt_InjectionTest_TestService {
296     @Inject @ApplicationLevel String appBinding;
297     @Inject @ServiceLevel String serviceBinding;
298 
299     @Override
onBind(Intent intent)300     public IBinder onBind(Intent intent) {
301       return null;
302     }
303   }
304 
305   @AndroidEntryPoint(IntentService.class)
306   public static final class TestIntentService extends Hilt_InjectionTest_TestIntentService {
307     private static final String NAME = "TestIntentServiceName";
308     @Inject @ApplicationLevel String appBinding;
309     @Inject @ServiceLevel String serviceBinding;
310 
TestIntentService()311     TestIntentService() {
312       super(NAME);
313     }
314 
315     @Override
onHandleIntent(Intent intent)316     public void onHandleIntent(Intent intent) {}
317   }
318 
319   @AndroidEntryPoint(BroadcastReceiver.class)
320   public static final class TestBroadcastReceiver extends Hilt_InjectionTest_TestBroadcastReceiver {
321     @Inject @ApplicationLevel String appBinding;
322     Intent lastIntent = null;
323 
324     @Override
onReceive(Context context, Intent intent)325     public void onReceive(Context context, Intent intent) {
326       super.onReceive(context, intent);
327       lastIntent = intent;
328     }
329   }
330 
331   @AndroidEntryPoint(BaseBroadcastReceiver.class)
332   public static final class TestBroadcastReceiverWithBaseImplementingOnReceive
333       extends Hilt_InjectionTest_TestBroadcastReceiverWithBaseImplementingOnReceive {
334     @Inject @ApplicationLevel String appBinding;
335     Intent baseLastIntent = null;
336 
337     @Override
onReceive(Context context, Intent intent)338     public void onReceive(Context context, Intent intent) {
339       super.onReceive(context, intent);
340       baseLastIntent = intent;
341     }
342   }
343 
344   abstract static class BaseBroadcastReceiver extends BroadcastReceiver {
345     Intent lastIntent = null;
346 
347     @Override
onReceive(Context context, Intent intent)348     public void onReceive(Context context, Intent intent) {
349       lastIntent = intent;
350     }
351   }
352 
353   @Rule public final HiltAndroidRule rule = new HiltAndroidRule(this);
354 
355   @Inject @ApplicationLevel String appBinding;
356 
357   @Before
setup()358   public void setup() {
359     rule.inject();
360   }
361 
362   @Test
testAppInjection()363   public void testAppInjection() throws Exception {
364     assertThat(appBinding).isEqualTo(APP_BINDING);
365   }
366 
367   @Test
testActivityInjection()368   public void testActivityInjection() throws Exception {
369     ActivityController<TestActivity> controller = Robolectric.buildActivity(TestActivity.class);
370 
371     assertThat(controller.get().onCreateCalled).isFalse();
372     controller.create();
373     assertThat(controller.get().onCreateCalled).isTrue();
374   }
375 
376   @Test
testFragmentInjection()377   public void testFragmentInjection() throws Exception {
378     TestFragment fragment = new TestFragment();
379     assertThat(fragment.onAttachContextCalled).isFalse();
380     assertThat(fragment.onAttachActivityCalled).isFalse();
381     setupFragment(TestActivity.class, fragment);
382     assertThat(fragment.onAttachContextCalled).isTrue();
383     assertThat(fragment.onAttachActivityCalled).isTrue();
384   }
385 
386   @Test
testParameterizedFragmentInjection()387   public void testParameterizedFragmentInjection() throws Exception {
388     TestParameterizedFragment fragment = new TestParameterizedFragment();
389     assertThat(fragment.onAttachContextCalled).isFalse();
390     assertThat(fragment.onAttachActivityCalled).isFalse();
391     setupFragment(TestActivity.class, fragment);
392     assertThat(fragment.onAttachContextCalled).isTrue();
393     assertThat(fragment.onAttachActivityCalled).isTrue();
394   }
395 
396   @Test
testViewNoFragmentBindingsWithActivity()397   public void testViewNoFragmentBindingsWithActivity() throws Exception {
398     TestActivity activity = Robolectric.setupActivity(TestActivity.class);
399     TestView view = new TestView(activity);
400     assertThat(view.appBinding).isEqualTo(APP_BINDING);
401     assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING);
402   }
403 
404   @Test
testViewNoFragmentBindingsWithFragment()405   public void testViewNoFragmentBindingsWithFragment() throws Exception {
406     TestFragment fragment = setupFragment(TestActivity.class, new TestFragment());
407     TestView view = new TestView(fragment.getContext());
408     assertThat(view.appBinding).isEqualTo(APP_BINDING);
409     assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING);
410   }
411 
412   @Test
testViewNoFragmentBindingsWithFragment_secondConstructor()413   public void testViewNoFragmentBindingsWithFragment_secondConstructor() throws Exception {
414     TestFragment fragment = setupFragment(TestActivity.class, new TestFragment());
415     TestView view = new TestView(fragment.getContext(), /* attrs= */ null);
416     assertThat(view.appBinding).isEqualTo(APP_BINDING);
417     assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING);
418   }
419 
420   @Test
testViewNoFragmentBindingsWithFragment_thirdConstructor()421   public void testViewNoFragmentBindingsWithFragment_thirdConstructor() throws Exception {
422     TestFragment fragment = setupFragment(TestActivity.class, new TestFragment());
423     TestView view = new TestView(fragment.getContext(), /* attrs= */ null, /* defStyleAttr= */ 0);
424     assertThat(view.appBinding).isEqualTo(APP_BINDING);
425     assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING);
426   }
427 
428   @Test
429   @Config(sdk = 21)
testViewNoFragmentBindingsWithFragment_fourthConstructor_presentOnTwentyOne()430   public void testViewNoFragmentBindingsWithFragment_fourthConstructor_presentOnTwentyOne()
431       throws Exception {
432     TestFragment fragment = setupFragment(TestActivity.class, new TestFragment());
433     TestView view =
434         new TestView(
435             fragment.getContext(), /* attrs= */ null, /* defStyleAttr= */ 0, /* defStyleRes= */ 0);
436     assertThat(view.appBinding).isEqualTo(APP_BINDING);
437     assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING);
438   }
439 
440   @Test
testServiceInjection()441   public void testServiceInjection() throws Exception {
442     TestService testService = Robolectric.setupService(TestService.class);
443     assertThat(testService.appBinding).isEqualTo(APP_BINDING);
444     assertThat(testService.serviceBinding).isEqualTo(SERVICE_BINDING);
445   }
446 
447   @Test
testIntentServiceInjection()448   public void testIntentServiceInjection() throws Exception {
449     TestIntentService testIntentService = Robolectric.setupService(TestIntentService.class);
450     assertThat(testIntentService.appBinding).isEqualTo(APP_BINDING);
451     assertThat(testIntentService.serviceBinding).isEqualTo(SERVICE_BINDING);
452   }
453 
454   @Test
testBroadcastReceiverInjection()455   public void testBroadcastReceiverInjection() throws Exception {
456     TestBroadcastReceiver testBroadcastReceiver = new TestBroadcastReceiver();
457     Intent intent = new Intent();
458     testBroadcastReceiver.onReceive(getApplicationContext(), intent);
459     assertThat(testBroadcastReceiver.appBinding).isEqualTo(APP_BINDING);
460     assertThat(testBroadcastReceiver.lastIntent).isSameInstanceAs(intent);
461   }
462 
463   @Test
testBroadcastReceiverWithBaseImplementingOnReceiveInjection()464   public void testBroadcastReceiverWithBaseImplementingOnReceiveInjection() throws Exception {
465     TestBroadcastReceiverWithBaseImplementingOnReceive testBroadcastReceiver =
466         new TestBroadcastReceiverWithBaseImplementingOnReceive();
467     Intent intent = new Intent();
468     testBroadcastReceiver.onReceive(getApplicationContext(), intent);
469     assertThat(testBroadcastReceiver.appBinding).isEqualTo(APP_BINDING);
470     assertThat(testBroadcastReceiver.lastIntent).isSameInstanceAs(intent);
471     assertThat(testBroadcastReceiver.baseLastIntent).isSameInstanceAs(intent);
472   }
473 
474   @Test
testViewWithFragmentBindingsWithFragment()475   public void testViewWithFragmentBindingsWithFragment() throws Exception {
476     TestFragment fragment = setupFragment(TestActivity.class, new TestFragment());
477 
478     Context fragmentContext = fragment.getContext();
479     TestViewWithFragmentBindings view = new TestViewWithFragmentBindings(fragmentContext);
480     assertThat(view.appBinding).isEqualTo(APP_BINDING);
481     assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING);
482     assertThat(view.fragmentBinding).isEqualTo(FRAGMENT_BINDING);
483   }
484 
485   @Test
testViewWithFragmentBindingsFailsWithActivity()486   public void testViewWithFragmentBindingsFailsWithActivity() throws Exception {
487     TestActivity activity = Robolectric.setupActivity(TestActivity.class);
488     try {
489       new TestViewWithFragmentBindings(activity);
490       fail("Expected test to fail but it passes!");
491     } catch (IllegalStateException e) {
492       assertThat(e)
493           .hasMessageThat()
494           .contains(
495               "@WithFragmentBindings Hilt view must be attached to an @AndroidEntryPoint Fragment");
496     }
497   }
498 
499   @Test
testFragmentAttachedToNonHiltActivityFails()500   public void testFragmentAttachedToNonHiltActivityFails() throws Exception {
501     NonHiltActivity activity = Robolectric.setupActivity(NonHiltActivity.class);
502     try {
503       activity
504           .getSupportFragmentManager()
505           .beginTransaction()
506           .add(new TestFragment(), null)
507           .commitNow();
508       fail("Expected test to fail but it passes!");
509     } catch (IllegalStateException e) {
510       assertThat(e)
511           .hasMessageThat()
512           .contains("Hilt Fragments must be attached to an @AndroidEntryPoint Activity");
513     }
514   }
515 
516   @Test
testViewAttachedToNonHiltActivityFails()517   public void testViewAttachedToNonHiltActivityFails() throws Exception {
518     NonHiltActivity activity = Robolectric.setupActivity(NonHiltActivity.class);
519     try {
520       new TestView(activity);
521       fail("Expected test to fail but it passes!");
522     } catch (IllegalStateException e) {
523       assertThat(e)
524           .hasMessageThat()
525           .contains("Hilt view must be attached to an @AndroidEntryPoint Fragment or Activity");
526     }
527   }
528 
529   @Test
testViewAttachedToNonHiltFragmentFails()530   public void testViewAttachedToNonHiltFragmentFails() throws Exception {
531     NonHiltActivity activity = Robolectric.setupActivity(NonHiltActivity.class);
532     NonHiltFragment fragment = new NonHiltFragment();
533     activity.getSupportFragmentManager().beginTransaction().add(fragment, null).commitNow();
534     Context nonHiltContext = fragment.getContext();
535     try {
536       new TestView(nonHiltContext);
537       fail("Expected test to fail but it passes!");
538     } catch (IllegalStateException e) {
539       assertThat(e)
540           .hasMessageThat()
541           .contains("Hilt view must be attached to an @AndroidEntryPoint Fragment or Activity");
542     }
543   }
544 
545   @Test
testViewAttachedToApplicationContextFails()546   public void testViewAttachedToApplicationContextFails() throws Exception {
547     try {
548       new TestView(getApplicationContext());
549       fail("Expected test to fail but it passes!");
550     } catch (IllegalStateException e) {
551       assertThat(e)
552           .hasMessageThat()
553           .contains(
554               "Hilt view cannot be created using the application context. "
555                   + "Use a Hilt Fragment or Activity context");
556     }
557   }
558 
559   /** Hilt Activity that manually calls inject(). */
560   @AndroidEntryPoint(FragmentActivity.class)
561   public static final class DoubleInjectActivity extends Hilt_InjectionTest_DoubleInjectActivity {
562     @Inject Long counter;
563 
564     @Override
onCreate(Bundle onSavedInstanceState)565     public void onCreate(Bundle onSavedInstanceState) {
566       inject();
567       super.onCreate(onSavedInstanceState);
568     }
569   }
570 
571   @Test
testActivityDoesNotInjectTwice()572   public void testActivityDoesNotInjectTwice() throws Exception {
573     ActivityController<DoubleInjectActivity> controller =
574         Robolectric.buildActivity(DoubleInjectActivity.class);
575     controller.create();
576     assertThat(controller.get().counter).isEqualTo(1L);
577   }
578 
579   /** Hilt Fragment that manually calls inject(). */
580   @AndroidEntryPoint(Fragment.class)
581   public static final class DoubleInjectFragment extends Hilt_InjectionTest_DoubleInjectFragment {
582     @Inject Long counter;
583 
584     @Override
onAttach(Context context)585     public void onAttach(Context context) {
586       inject();
587       super.onAttach(context);
588     }
589 
590     @Override
onAttach(Activity activity)591     public void onAttach(Activity activity) {
592       inject();
593       super.onAttach(activity);
594     }
595   }
596 
597   @Test
testFragmentDoesNotInjectTwice()598   public void testFragmentDoesNotInjectTwice() throws Exception {
599     DoubleInjectFragment fragment = setupFragment(TestActivity.class, new DoubleInjectFragment());
600     assertThat(fragment.counter).isEqualTo(1L);
601   }
602 
603   /** Hilt View that manually calls inject(). */
604   @AndroidEntryPoint(LinearLayout.class)
605   public static final class DoubleInjectView extends Hilt_InjectionTest_DoubleInjectView {
606     @Inject Long counter;
607 
DoubleInjectView(Context context)608     DoubleInjectView(Context context) {
609       super(context);
610       inject();
611     }
612 
DoubleInjectView(Context context, AttributeSet attrs)613     DoubleInjectView(Context context, AttributeSet attrs) {
614       super(context, attrs);
615       inject();
616     }
617 
DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr)618     DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr) {
619       super(context, attrs, defStyleAttr);
620       inject();
621     }
622 
623     @TargetApi(21)
DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)624     DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
625       super(context, attrs, defStyleAttr, defStyleRes);
626       inject();
627     }
628   }
629 
630   @Test
testViewDoesNotInjectTwice()631   public void testViewDoesNotInjectTwice() throws Exception {
632     TestActivity activity = Robolectric.setupActivity(TestActivity.class);
633     DoubleInjectView view = new DoubleInjectView(activity);
634     assertThat(view.counter).isEqualTo(1L);
635   }
636 
637   /** Hilt Service that manually calls inject(). */
638   @AndroidEntryPoint(Service.class)
639   public static final class DoubleInjectService extends Hilt_InjectionTest_DoubleInjectService {
640     @Inject Long counter;
641 
onCreate()642     @Override public void onCreate() {
643       inject();
644       super.onCreate();
645     }
646 
647     @Override
onBind(Intent intent)648     public IBinder onBind(Intent intent) {
649       return null;
650     }
651   }
652 
653   @Test
testServiceDoesNotInjectTwice()654   public void testServiceDoesNotInjectTwice() throws Exception {
655     DoubleInjectService testService = Robolectric.setupService(DoubleInjectService.class);
656     assertThat(testService.counter).isEqualTo(1L);
657   }
658 
659   /** Hilt BroadcastReceiver that manually calls inject(). */
660   @AndroidEntryPoint(BroadcastReceiver.class)
661   public static final class DoubleInjectBroadcastReceiver
662       extends Hilt_InjectionTest_DoubleInjectBroadcastReceiver {
663     @Inject Long counter;
664 
665     @Override
onReceive(Context context, Intent intent)666     public void onReceive(Context context, Intent intent) {
667       inject(context);
668       super.onReceive(context, intent);
669     }
670   }
671 
672   @Test
testBroadcastReceiverDoesNotInjectTwice()673   public void testBroadcastReceiverDoesNotInjectTwice() throws Exception {
674     DoubleInjectBroadcastReceiver testBroadcastReceiver = new DoubleInjectBroadcastReceiver();
675     Intent intent = new Intent();
676     testBroadcastReceiver.onReceive(getApplicationContext(), intent);
677     assertThat(testBroadcastReceiver.counter).isEqualTo(1L);
678   }
679 
setupFragment( Class<? extends FragmentActivity> activityClass, T fragment)680   private static <T extends Fragment> T setupFragment(
681       Class<? extends FragmentActivity> activityClass, T fragment) {
682     FragmentActivity activity = Robolectric.setupActivity(activityClass);
683     attachFragment(activity, fragment);
684     return fragment;
685   }
686 
attachFragment(FragmentActivity activity, Fragment fragment)687   private static void attachFragment(FragmentActivity activity, Fragment fragment) {
688     activity.getSupportFragmentManager().beginTransaction().add(fragment, "").commitNow();
689   }
690 }
691