1/*
2 * Copyright 2018 The Android Open Source Project
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 */
16package androidx.fragment.app;
17
18import static org.junit.Assert.assertEquals;
19import static org.junit.Assert.assertTrue;
20import static org.junit.Assert.fail;
21import static org.mockito.ArgumentMatchers.eq;
22import static org.mockito.ArgumentMatchers.same;
23import static org.mockito.Mockito.mock;
24import static org.mockito.Mockito.verify;
25import static org.mockito.Mockito.verifyNoMoreInteractions;
26
27import android.app.Activity;
28import android.app.PendingIntent;
29import android.content.Intent;
30import android.content.IntentSender;
31import android.support.test.InstrumentationRegistry;
32import android.support.test.filters.SmallTest;
33import android.support.test.rule.ActivityTestRule;
34import android.support.test.runner.AndroidJUnit4;
35
36import androidx.core.app.ActivityCompat;
37import androidx.fragment.app.test.FragmentResultActivity;
38import androidx.fragment.app.test.FragmentTestActivity;
39import androidx.fragment.test.R;
40
41import org.junit.Before;
42import org.junit.Rule;
43import org.junit.Test;
44import org.junit.runner.RunWith;
45
46import java.util.concurrent.CountDownLatch;
47import java.util.concurrent.TimeUnit;
48
49/**
50 * Tests for Fragment startActivityForResult and startIntentSenderForResult.
51 */
52@RunWith(AndroidJUnit4.class)
53public class FragmentReceiveResultTest {
54    @Rule
55    public ActivityTestRule<FragmentTestActivity> mActivityRule =
56            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
57
58    private FragmentTestActivity mActivity;
59    private TestFragment mFragment;
60
61
62    @Before
63    public void setup() throws Throwable {
64        mActivity = mActivityRule.getActivity();
65        mFragment = attachTestFragment();
66    }
67
68    @Test
69    @SmallTest
70    public void testStartActivityForResultOk() throws Throwable {
71        startActivityForResult(10, Activity.RESULT_OK, "content 10");
72
73        assertTrue("Fragment should receive result", mFragment.mHasResult);
74        assertEquals(10, mFragment.mRequestCode);
75        assertEquals(Activity.RESULT_OK, mFragment.mResultCode);
76        assertEquals("content 10", mFragment.mResultContent);
77    }
78
79    @Test
80    @SmallTest
81    public void testStartActivityForResultCanceled() throws Throwable {
82        startActivityForResult(20, Activity.RESULT_CANCELED, "content 20");
83
84        assertTrue("Fragment should receive result", mFragment.mHasResult);
85        assertEquals(20, mFragment.mRequestCode);
86        assertEquals(Activity.RESULT_CANCELED, mFragment.mResultCode);
87        assertEquals("content 20", mFragment.mResultContent);
88    }
89
90    @Test
91    @SmallTest
92    public void testStartIntentSenderForResultOk() throws Throwable {
93        startIntentSenderForResult(30, Activity.RESULT_OK, "content 30");
94
95        assertTrue("Fragment should receive result", mFragment.mHasResult);
96        assertEquals(30, mFragment.mRequestCode);
97        assertEquals(Activity.RESULT_OK, mFragment.mResultCode);
98        assertEquals("content 30", mFragment.mResultContent);
99    }
100
101    @Test
102    @SmallTest
103    public void testStartIntentSenderForResultCanceled() throws Throwable {
104        startIntentSenderForResult(40, Activity.RESULT_CANCELED, "content 40");
105
106        assertTrue("Fragment should receive result", mFragment.mHasResult);
107        assertEquals(40, mFragment.mRequestCode);
108        assertEquals(Activity.RESULT_CANCELED, mFragment.mResultCode);
109        assertEquals("content 40", mFragment.mResultContent);
110    }
111
112    @Test
113    @SmallTest
114    public void testActivityResult_withDelegate() {
115        ActivityCompat.PermissionCompatDelegate
116                delegate = mock(ActivityCompat.PermissionCompatDelegate.class);
117
118        Intent data = new Intent();
119        ActivityCompat.setPermissionCompatDelegate(delegate);
120
121        mActivityRule.getActivity().onActivityResult(42, 43, data);
122
123        verify(delegate).onActivityResult(same(mActivityRule.getActivity()), eq(42), eq(43),
124                same(data));
125
126        ActivityCompat.setPermissionCompatDelegate(null);
127        mActivityRule.getActivity().onActivityResult(42, 43, data);
128        verifyNoMoreInteractions(delegate);
129    }
130
131    private TestFragment attachTestFragment() throws Throwable {
132        final TestFragment fragment = new TestFragment();
133        mActivityRule.runOnUiThread(new Runnable() {
134            @Override
135            public void run() {
136                mActivity.getSupportFragmentManager().beginTransaction()
137                        .add(R.id.content, fragment)
138                        .addToBackStack(null)
139                        .commitAllowingStateLoss();
140                mActivity.getFragmentManager().executePendingTransactions();
141            }
142        });
143        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
144        return fragment;
145    }
146
147    private void startActivityForResult(final int requestCode, final int resultCode,
148            final String content) throws Throwable {
149        mActivityRule.runOnUiThread(new Runnable() {
150            @Override
151            public void run() {
152                Intent intent = new Intent(mActivity, FragmentResultActivity.class);
153                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CODE, resultCode);
154                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT, content);
155
156                mFragment.startActivityForResult(intent, requestCode);
157            }
158        });
159        assertTrue(mFragment.mResultReceiveLatch.await(1, TimeUnit.SECONDS));
160        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
161    }
162
163    private void startIntentSenderForResult(final int requestCode, final int resultCode,
164            final String content) throws Throwable {
165        mActivityRule.runOnUiThread(new Runnable() {
166            @Override
167            public void run() {
168                Intent intent = new Intent(mActivity, FragmentResultActivity.class);
169                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CODE, resultCode);
170                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT, content);
171
172                PendingIntent pendingIntent = PendingIntent.getActivity(mActivity,
173                        requestCode, intent, 0);
174
175                try {
176                    mFragment.startIntentSenderForResult(pendingIntent.getIntentSender(),
177                            requestCode, null, 0, 0, 0, null);
178                } catch (IntentSender.SendIntentException e) {
179                    fail("IntentSender failed");
180                }
181            }
182        });
183        assertTrue(mFragment.mResultReceiveLatch.await(1, TimeUnit.SECONDS));
184        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
185    }
186
187    public static class TestFragment extends Fragment {
188        boolean mHasResult = false;
189        int mRequestCode = -1;
190        int mResultCode = 100;
191        String mResultContent;
192        final CountDownLatch mResultReceiveLatch = new CountDownLatch(1);
193
194        @Override
195        public void onActivityResult(int requestCode, int resultCode, Intent data) {
196            mHasResult = true;
197            mRequestCode = requestCode;
198            mResultCode = resultCode;
199            mResultContent = data.getStringExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT);
200            mResultReceiveLatch.countDown();
201        }
202    }
203}
204