|
2 | 2 |
|
3 | 3 | import static com.google.common.truth.Truth.assertThat;
|
4 | 4 | import static org.junit.Assert.assertThrows;
|
| 5 | +import static org.junit.Assert.fail; |
| 6 | +import static org.junit.Assume.assumeTrue; |
5 | 7 |
|
| 8 | +import android.os.Build; |
6 | 9 | import android.os.Bundle;
|
7 | 10 | import android.view.LayoutInflater;
|
8 | 11 | import android.view.View;
|
|
13 | 16 | import androidx.fragment.app.FragmentActivity;
|
14 | 17 | import androidx.fragment.app.FragmentManager;
|
15 | 18 | import androidx.fragment.app.testing.FragmentScenario;
|
| 19 | +import androidx.lifecycle.Lifecycle.Event; |
16 | 20 | import androidx.lifecycle.Lifecycle.State;
|
| 21 | +import androidx.lifecycle.LifecycleObserver; |
| 22 | +import androidx.lifecycle.LifecycleOwner; |
| 23 | +import androidx.lifecycle.OnLifecycleEvent; |
17 | 24 | import androidx.test.core.app.ActivityScenario;
|
18 | 25 | import androidx.test.core.app.ActivityScenario.ActivityAction;
|
19 | 26 | import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
20 | 27 | import androidx.test.ext.junit.runners.AndroidJUnit4;
|
21 | 28 | import com.bumptech.glide.instrumentation.R;
|
22 | 29 | import com.bumptech.glide.test.DefaultFragmentActivity;
|
23 | 30 | import com.bumptech.glide.testutil.TearDownGlide;
|
| 31 | +import java.util.concurrent.atomic.AtomicReference; |
24 | 32 | import org.junit.Before;
|
25 | 33 | import org.junit.Rule;
|
26 | 34 | import org.junit.Test;
|
@@ -59,6 +67,70 @@ public void get_withActivityBeforeCreate_startsRequestManager() {
|
59 | 67 | scenario.onActivity(activity -> assertThat(Glide.with(activity).isPaused()).isFalse());
|
60 | 68 | }
|
61 | 69 |
|
| 70 | + // See b/262668610 |
| 71 | + @SuppressWarnings("OnLifecycleEvent") |
| 72 | + @Test |
| 73 | + public void get_withActivityOnDestroy_QPlus_doesNotCrash() { |
| 74 | + // Activity#isDestroyed's behavior seems to have changed in Q. On Q+, isDestroyed returns false |
| 75 | + // during onDestroy, so we have to handle that case explicitly. |
| 76 | + assumeTrue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q); |
| 77 | + scenario.moveToState(State.CREATED); |
| 78 | + |
| 79 | + class GetOnDestroy implements LifecycleObserver { |
| 80 | + private final FragmentActivity activity; |
| 81 | + |
| 82 | + GetOnDestroy(FragmentActivity activity) { |
| 83 | + this.activity = activity; |
| 84 | + } |
| 85 | + |
| 86 | + @OnLifecycleEvent(Event.ON_DESTROY) |
| 87 | + public void onDestroy(@NonNull LifecycleOwner owner) { |
| 88 | + Glide.with(activity); |
| 89 | + } |
| 90 | + } |
| 91 | + scenario.onActivity( |
| 92 | + activity -> activity.getLifecycle().addObserver(new GetOnDestroy(activity))); |
| 93 | + scenario.moveToState(State.DESTROYED); |
| 94 | + } |
| 95 | + |
| 96 | + @SuppressWarnings("OnLifecycleEvent") |
| 97 | + @Test |
| 98 | + public void get_withActivityOnDestroy_afterJellyBeanAndbeforeQ_doesNotCrash() { |
| 99 | + // Activity#isDestroyed's behavior seems to have changed in Q. On <Q, isDestroyed returns true |
| 100 | + // during onDestroy, triggering an assertion in Glide. < Jelly bean, isDestroyed is not |
| 101 | + // available as a method. |
| 102 | + assumeTrue( |
| 103 | + Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN |
| 104 | + && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q); |
| 105 | + AtomicReference<Exception> thrownException = new AtomicReference<>(); |
| 106 | + scenario.moveToState(State.CREATED); |
| 107 | + |
| 108 | + class GetOnDestroy implements LifecycleObserver { |
| 109 | + private final FragmentActivity activity; |
| 110 | + |
| 111 | + GetOnDestroy(FragmentActivity activity) { |
| 112 | + this.activity = activity; |
| 113 | + } |
| 114 | + |
| 115 | + @OnLifecycleEvent(Event.ON_DESTROY) |
| 116 | + public void onDestroy(@NonNull LifecycleOwner owner) { |
| 117 | + try { |
| 118 | + Glide.with(activity); |
| 119 | + fail("Failed to throw expected exception"); |
| 120 | + } catch (Exception e) { |
| 121 | + thrownException.set(e); |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + scenario.onActivity( |
| 126 | + activity -> activity.getLifecycle().addObserver(new GetOnDestroy(activity))); |
| 127 | + scenario.moveToState(State.DESTROYED); |
| 128 | + |
| 129 | + assertThat(thrownException.get()) |
| 130 | + .hasMessageThat() |
| 131 | + .contains("You cannot start a load for a destroyed activity"); |
| 132 | + } |
| 133 | + |
62 | 134 | @Test
|
63 | 135 | public void get_withFragment_beforeFragmentIsAdded_throws() {
|
64 | 136 | Fragment fragment = new Fragment();
|
|
0 commit comments