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