blob: f1e4d21c1a35e0ed156d49d8dfd7a4d2a911a940 [file] [log] [blame]
Jason Monk88529052016-11-04 13:29:58 -04001/*
Jason Monk340b0e52017-03-08 14:57:56 -05002 * Copyright (C) 2017 The Android Open Source Project
Jason Monk88529052016-11-04 13:29:58 -04003 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
Jason Monk340b0e52017-03-08 14:57:56 -050015package android.testing;
16
17import static org.junit.Assert.assertNotNull;
Jason Monk88529052016-11-04 13:29:58 -040018
19import android.annotation.Nullable;
20import android.app.Fragment;
21import android.app.FragmentController;
22import android.app.FragmentHostCallback;
23import android.app.FragmentManagerNonConfig;
Jason Monkde850bb2017-02-01 19:26:30 -050024import android.graphics.PixelFormat;
Jason Monk88529052016-11-04 13:29:58 -040025import android.os.Handler;
Jason Monk88529052016-11-04 13:29:58 -040026import android.os.Parcelable;
Jason Monk340b0e52017-03-08 14:57:56 -050027import android.support.test.InstrumentationRegistry;
Jason Monk88529052016-11-04 13:29:58 -040028import android.view.LayoutInflater;
29import android.view.View;
Jason Monkde850bb2017-02-01 19:26:30 -050030import android.view.WindowManager;
31import android.view.WindowManager.LayoutParams;
Jason Monk88529052016-11-04 13:29:58 -040032import android.widget.FrameLayout;
33
34import org.junit.After;
35import org.junit.Before;
Jason Monk340b0e52017-03-08 14:57:56 -050036import org.junit.Rule;
Jason Monk88529052016-11-04 13:29:58 -040037import org.junit.Test;
38
39import java.io.FileDescriptor;
40import java.io.PrintWriter;
41
42/**
43 * Base class for fragment class tests. Just adding one for any fragment will push it through
44 * general lifecycle events and ensure no basic leaks are happening. This class also implements
45 * the host for subclasses, so they can push it into desired states and do any unit testing
46 * required.
47 */
Jason Monk340b0e52017-03-08 14:57:56 -050048public abstract class BaseFragmentTest {
Jason Monk88529052016-11-04 13:29:58 -040049
50 private static final int VIEW_ID = 42;
51 private final Class<? extends Fragment> mCls;
Jason Monk88529052016-11-04 13:29:58 -040052 private Handler mHandler;
Siarhei Vishniakou6ad0e392017-06-02 17:20:34 -070053 protected FrameLayout mView;
Jason Monk88529052016-11-04 13:29:58 -040054 protected FragmentController mFragments;
55 protected Fragment mFragment;
56
Jason Monk340b0e52017-03-08 14:57:56 -050057 @Rule
58 public final TestableContext mContext = getContext();
59
60 public BaseFragmentTest(Class<? extends Fragment> cls) {
Jason Monk88529052016-11-04 13:29:58 -040061 mCls = cls;
62 }
63
Siarhei Vishniakou6ad0e392017-06-02 17:20:34 -070064 protected void createRootView() {
65 mView = new FrameLayout(mContext);
66 }
67
Jason Monk88529052016-11-04 13:29:58 -040068 @Before
Jason Monk28d5d222017-02-02 13:08:31 -050069 public void setupFragment() throws Exception {
Siarhei Vishniakou6ad0e392017-06-02 17:20:34 -070070 createRootView();
Jason Monk88529052016-11-04 13:29:58 -040071 mView.setId(VIEW_ID);
Jason Monk28d5d222017-02-02 13:08:31 -050072
Jason Monk340b0e52017-03-08 14:57:56 -050073 assertNotNull("BaseFragmentTest must be tagged with @RunWithLooper",
74 TestableLooper.get(this));
Jason Monk28d5d222017-02-02 13:08:31 -050075 TestableLooper.get(this).runWithLooper(() -> {
76 mHandler = new Handler();
77
78 mFragment = mCls.newInstance();
Jason Monk88529052016-11-04 13:29:58 -040079 mFragments = FragmentController.createController(new HostCallbacks());
80 mFragments.attachHost(null);
81 mFragments.getFragmentManager().beginTransaction()
82 .replace(VIEW_ID, mFragment)
83 .commit();
84 });
85 }
86
Jason Monk340b0e52017-03-08 14:57:56 -050087 protected TestableContext getContext() {
88 return new TestableContext(InstrumentationRegistry.getContext());
Jason Monk28d5d222017-02-02 13:08:31 -050089 }
90
Jason Monk88529052016-11-04 13:29:58 -040091 @After
Jason Monk28d5d222017-02-02 13:08:31 -050092 public void tearDown() throws Exception {
Jason Monk88529052016-11-04 13:29:58 -040093 if (mFragments != null) {
94 // Set mFragments to null to let it know not to destroy.
Jason Monk28d5d222017-02-02 13:08:31 -050095 TestableLooper.get(this).runWithLooper(() -> mFragments.dispatchDestroy());
Jason Monk88529052016-11-04 13:29:58 -040096 }
Jason Monk88529052016-11-04 13:29:58 -040097 }
98
99 @Test
100 public void testCreateDestroy() {
Jason Monk28d5d222017-02-02 13:08:31 -0500101 mFragments.dispatchCreate();
102 processAllMessages();
Jason Monk88529052016-11-04 13:29:58 -0400103 destroyFragments();
104 }
105
106 @Test
107 public void testStartStop() {
Jason Monk28d5d222017-02-02 13:08:31 -0500108 mFragments.dispatchStart();
109 processAllMessages();
110 mFragments.dispatchStop();
111 processAllMessages();
Jason Monk88529052016-11-04 13:29:58 -0400112 }
113
114 @Test
115 public void testResumePause() {
Jason Monk28d5d222017-02-02 13:08:31 -0500116 mFragments.dispatchResume();
117 processAllMessages();
118 mFragments.dispatchPause();
119 processAllMessages();
Jason Monk88529052016-11-04 13:29:58 -0400120 }
121
122 @Test
Jason Monkde850bb2017-02-01 19:26:30 -0500123 public void testAttachDetach() {
124 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
125 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
126 LayoutParams.TYPE_SYSTEM_ALERT,
127 0, PixelFormat.TRANSLUCENT);
Jason Monk28d5d222017-02-02 13:08:31 -0500128 mFragments.dispatchResume();
129 processAllMessages();
Jason Monkde850bb2017-02-01 19:26:30 -0500130 attachFragmentToWindow();
131 detachFragmentToWindow();
Jason Monk28d5d222017-02-02 13:08:31 -0500132 mFragments.dispatchPause();
133 processAllMessages();
Jason Monkde850bb2017-02-01 19:26:30 -0500134 }
135
136 @Test
Jason Monk88529052016-11-04 13:29:58 -0400137 public void testRecreate() {
Jason Monk28d5d222017-02-02 13:08:31 -0500138 mFragments.dispatchResume();
139 processAllMessages();
Jason Monk64b214e2017-03-27 13:40:59 -0400140 recreateFragment();
Jason Monk28d5d222017-02-02 13:08:31 -0500141 processAllMessages();
Jason Monk88529052016-11-04 13:29:58 -0400142 }
143
144 @Test
145 public void testMultipleResumes() {
Jason Monk28d5d222017-02-02 13:08:31 -0500146 mFragments.dispatchResume();
147 processAllMessages();
148 mFragments.dispatchStop();
149 processAllMessages();
150 mFragments.dispatchResume();
151 processAllMessages();
152 }
153
Jason Monk64b214e2017-03-27 13:40:59 -0400154 protected void recreateFragment() {
155 mFragments.dispatchPause();
156 Parcelable p = mFragments.saveAllState();
157 mFragments.dispatchDestroy();
158
159 mFragments = FragmentController.createController(new HostCallbacks());
160 mFragments.attachHost(null);
161 mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
162 mFragments.dispatchResume();
163 mFragment = mFragments.getFragmentManager().findFragmentById(VIEW_ID);
164 }
165
Jason Monk28d5d222017-02-02 13:08:31 -0500166 protected void attachFragmentToWindow() {
167 ViewUtils.attachView(mView);
Jason Monk1660a272017-04-28 15:53:59 -0400168 TestableLooper.get(this).processAllMessages();
Jason Monk28d5d222017-02-02 13:08:31 -0500169 }
170
171 protected void detachFragmentToWindow() {
172 ViewUtils.detachView(mView);
Jason Monk1660a272017-04-28 15:53:59 -0400173 TestableLooper.get(this).processAllMessages();
Jason Monk88529052016-11-04 13:29:58 -0400174 }
175
176 protected void destroyFragments() {
Jason Monk28d5d222017-02-02 13:08:31 -0500177 mFragments.dispatchDestroy();
178 processAllMessages();
Jason Monk88529052016-11-04 13:29:58 -0400179 mFragments = null;
180 }
181
Jason Monk28d5d222017-02-02 13:08:31 -0500182 protected void processAllMessages() {
183 TestableLooper.get(this).processAllMessages();
Jason Monk88529052016-11-04 13:29:58 -0400184 }
185
186 private View findViewById(int id) {
187 return mView.findViewById(id);
188 }
189
Jason Monk340b0e52017-03-08 14:57:56 -0500190 private class HostCallbacks extends FragmentHostCallback<BaseFragmentTest> {
Jason Monk88529052016-11-04 13:29:58 -0400191 public HostCallbacks() {
Jason Monk340b0e52017-03-08 14:57:56 -0500192 super(mContext, BaseFragmentTest.this.mHandler, 0);
Jason Monk88529052016-11-04 13:29:58 -0400193 }
194
195 @Override
Jason Monk340b0e52017-03-08 14:57:56 -0500196 public BaseFragmentTest onGetHost() {
197 return BaseFragmentTest.this;
Jason Monk88529052016-11-04 13:29:58 -0400198 }
199
200 @Override
201 public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
202 }
203
204 @Override
205 public boolean onShouldSaveFragmentState(Fragment fragment) {
206 return true; // True for now.
207 }
208
209 @Override
210 public LayoutInflater onGetLayoutInflater() {
211 return LayoutInflater.from(mContext);
212 }
213
214 @Override
215 public boolean onUseFragmentManagerInflaterFactory() {
216 return true;
217 }
218
219 @Override
220 public boolean onHasWindowAnimations() {
221 return false;
222 }
223
224 @Override
225 public int onGetWindowAnimations() {
226 return 0;
227 }
228
229 @Override
230 public void onAttachFragment(Fragment fragment) {
231 }
232
233 @Nullable
234 @Override
235 public View onFindViewById(int id) {
Jason Monk340b0e52017-03-08 14:57:56 -0500236 return BaseFragmentTest.this.findViewById(id);
Jason Monk88529052016-11-04 13:29:58 -0400237 }
238
239 @Override
240 public boolean onHasView() {
241 return true;
242 }
243 }
244}