18852905b0b3837e326127c6dfef6f699124ce715Jason Monk/* 2340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * Copyright (C) 2017 The Android Open Source Project 38852905b0b3837e326127c6dfef6f699124ce715Jason Monk * 48852905b0b3837e326127c6dfef6f699124ce715Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 58852905b0b3837e326127c6dfef6f699124ce715Jason Monk * except in compliance with the License. You may obtain a copy of the License at 68852905b0b3837e326127c6dfef6f699124ce715Jason Monk * 78852905b0b3837e326127c6dfef6f699124ce715Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 88852905b0b3837e326127c6dfef6f699124ce715Jason Monk * 98852905b0b3837e326127c6dfef6f699124ce715Jason Monk * Unless required by applicable law or agreed to in writing, software distributed under the 108852905b0b3837e326127c6dfef6f699124ce715Jason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 118852905b0b3837e326127c6dfef6f699124ce715Jason Monk * KIND, either express or implied. See the License for the specific language governing 128852905b0b3837e326127c6dfef6f699124ce715Jason Monk * permissions and limitations under the License. 138852905b0b3837e326127c6dfef6f699124ce715Jason Monk */ 148852905b0b3837e326127c6dfef6f699124ce715Jason Monk 15340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpackage android.testing; 16340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk 17340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport static org.junit.Assert.assertNotNull; 188852905b0b3837e326127c6dfef6f699124ce715Jason Monk 198852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.annotation.Nullable; 208852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.app.Fragment; 218852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.app.FragmentController; 228852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.app.FragmentHostCallback; 238852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.app.FragmentManagerNonConfig; 24de850bbcaa61c1874b803f2086443febbafd81a4Jason Monkimport android.graphics.PixelFormat; 258852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.os.Handler; 268852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.os.Parcelable; 27340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport android.support.test.InstrumentationRegistry; 288852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.view.LayoutInflater; 298852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.view.View; 30de850bbcaa61c1874b803f2086443febbafd81a4Jason Monkimport android.view.WindowManager; 31de850bbcaa61c1874b803f2086443febbafd81a4Jason Monkimport android.view.WindowManager.LayoutParams; 328852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport android.widget.FrameLayout; 338852905b0b3837e326127c6dfef6f699124ce715Jason Monk 348852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport org.junit.After; 358852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport org.junit.Before; 36340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport org.junit.Rule; 378852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport org.junit.Test; 388852905b0b3837e326127c6dfef6f699124ce715Jason Monk 398852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport java.io.FileDescriptor; 408852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport java.io.PrintWriter; 418852905b0b3837e326127c6dfef6f699124ce715Jason Monk 428852905b0b3837e326127c6dfef6f699124ce715Jason Monk/** 438852905b0b3837e326127c6dfef6f699124ce715Jason Monk * Base class for fragment class tests. Just adding one for any fragment will push it through 448852905b0b3837e326127c6dfef6f699124ce715Jason Monk * general lifecycle events and ensure no basic leaks are happening. This class also implements 458852905b0b3837e326127c6dfef6f699124ce715Jason Monk * the host for subclasses, so they can push it into desired states and do any unit testing 468852905b0b3837e326127c6dfef6f699124ce715Jason Monk * required. 478852905b0b3837e326127c6dfef6f699124ce715Jason Monk */ 48340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpublic abstract class BaseFragmentTest { 498852905b0b3837e326127c6dfef6f699124ce715Jason Monk 508852905b0b3837e326127c6dfef6f699124ce715Jason Monk private static final int VIEW_ID = 42; 518852905b0b3837e326127c6dfef6f699124ce715Jason Monk private final Class<? extends Fragment> mCls; 528852905b0b3837e326127c6dfef6f699124ce715Jason Monk private Handler mHandler; 536ad0e39f338d47e75bd1b964259ba21c00043f45Siarhei Vishniakou protected FrameLayout mView; 548852905b0b3837e326127c6dfef6f699124ce715Jason Monk protected FragmentController mFragments; 558852905b0b3837e326127c6dfef6f699124ce715Jason Monk protected Fragment mFragment; 568852905b0b3837e326127c6dfef6f699124ce715Jason Monk 57340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk @Rule 58340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk public final TestableContext mContext = getContext(); 59340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk 60340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk public BaseFragmentTest(Class<? extends Fragment> cls) { 618852905b0b3837e326127c6dfef6f699124ce715Jason Monk mCls = cls; 628852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 638852905b0b3837e326127c6dfef6f699124ce715Jason Monk 646ad0e39f338d47e75bd1b964259ba21c00043f45Siarhei Vishniakou protected void createRootView() { 656ad0e39f338d47e75bd1b964259ba21c00043f45Siarhei Vishniakou mView = new FrameLayout(mContext); 666ad0e39f338d47e75bd1b964259ba21c00043f45Siarhei Vishniakou } 676ad0e39f338d47e75bd1b964259ba21c00043f45Siarhei Vishniakou 688852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Before 6928d5d220cc66eb4263aaae083a8496950258642bJason Monk public void setupFragment() throws Exception { 706ad0e39f338d47e75bd1b964259ba21c00043f45Siarhei Vishniakou createRootView(); 718852905b0b3837e326127c6dfef6f699124ce715Jason Monk mView.setId(VIEW_ID); 7228d5d220cc66eb4263aaae083a8496950258642bJason Monk 73340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk assertNotNull("BaseFragmentTest must be tagged with @RunWithLooper", 74340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk TestableLooper.get(this)); 7528d5d220cc66eb4263aaae083a8496950258642bJason Monk TestableLooper.get(this).runWithLooper(() -> { 7628d5d220cc66eb4263aaae083a8496950258642bJason Monk mHandler = new Handler(); 7728d5d220cc66eb4263aaae083a8496950258642bJason Monk 7828d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragment = mCls.newInstance(); 798852905b0b3837e326127c6dfef6f699124ce715Jason Monk mFragments = FragmentController.createController(new HostCallbacks()); 808852905b0b3837e326127c6dfef6f699124ce715Jason Monk mFragments.attachHost(null); 818852905b0b3837e326127c6dfef6f699124ce715Jason Monk mFragments.getFragmentManager().beginTransaction() 828852905b0b3837e326127c6dfef6f699124ce715Jason Monk .replace(VIEW_ID, mFragment) 838852905b0b3837e326127c6dfef6f699124ce715Jason Monk .commit(); 848852905b0b3837e326127c6dfef6f699124ce715Jason Monk }); 858852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 868852905b0b3837e326127c6dfef6f699124ce715Jason Monk 87340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk protected TestableContext getContext() { 88340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk return new TestableContext(InstrumentationRegistry.getContext()); 8928d5d220cc66eb4263aaae083a8496950258642bJason Monk } 9028d5d220cc66eb4263aaae083a8496950258642bJason Monk 918852905b0b3837e326127c6dfef6f699124ce715Jason Monk @After 9228d5d220cc66eb4263aaae083a8496950258642bJason Monk public void tearDown() throws Exception { 938852905b0b3837e326127c6dfef6f699124ce715Jason Monk if (mFragments != null) { 948852905b0b3837e326127c6dfef6f699124ce715Jason Monk // Set mFragments to null to let it know not to destroy. 9528d5d220cc66eb4263aaae083a8496950258642bJason Monk TestableLooper.get(this).runWithLooper(() -> mFragments.dispatchDestroy()); 968852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 978852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 988852905b0b3837e326127c6dfef6f699124ce715Jason Monk 998852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Test 1008852905b0b3837e326127c6dfef6f699124ce715Jason Monk public void testCreateDestroy() { 10128d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchCreate(); 10228d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 1038852905b0b3837e326127c6dfef6f699124ce715Jason Monk destroyFragments(); 1048852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1058852905b0b3837e326127c6dfef6f699124ce715Jason Monk 1068852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Test 1078852905b0b3837e326127c6dfef6f699124ce715Jason Monk public void testStartStop() { 10828d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchStart(); 10928d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 11028d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchStop(); 11128d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 1128852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1138852905b0b3837e326127c6dfef6f699124ce715Jason Monk 1148852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Test 1158852905b0b3837e326127c6dfef6f699124ce715Jason Monk public void testResumePause() { 11628d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchResume(); 11728d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 11828d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchPause(); 11928d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 1208852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1218852905b0b3837e326127c6dfef6f699124ce715Jason Monk 1228852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Test 123de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk public void testAttachDetach() { 124de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 125de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 126de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk LayoutParams.TYPE_SYSTEM_ALERT, 127de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk 0, PixelFormat.TRANSLUCENT); 12828d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchResume(); 12928d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 130de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk attachFragmentToWindow(); 131de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk detachFragmentToWindow(); 13228d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchPause(); 13328d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 134de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk } 135de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk 136de850bbcaa61c1874b803f2086443febbafd81a4Jason Monk @Test 1378852905b0b3837e326127c6dfef6f699124ce715Jason Monk public void testRecreate() { 13828d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchResume(); 13928d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 14064b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk recreateFragment(); 14128d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 1428852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1438852905b0b3837e326127c6dfef6f699124ce715Jason Monk 1448852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Test 1458852905b0b3837e326127c6dfef6f699124ce715Jason Monk public void testMultipleResumes() { 14628d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchResume(); 14728d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 14828d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchStop(); 14928d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 15028d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchResume(); 15128d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 1528852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1538852905b0b3837e326127c6dfef6f699124ce715Jason Monk 15464b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk protected void recreateFragment() { 15564b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk mFragments.dispatchPause(); 15664b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk Parcelable p = mFragments.saveAllState(); 15764b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk mFragments.dispatchDestroy(); 15864b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk 15964b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk mFragments = FragmentController.createController(new HostCallbacks()); 16064b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk mFragments.attachHost(null); 16164b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk mFragments.restoreAllState(p, (FragmentManagerNonConfig) null); 16264b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk mFragments.dispatchResume(); 16364b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk mFragment = mFragments.getFragmentManager().findFragmentById(VIEW_ID); 16464b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk } 16564b214ea16c787fdcf2bb44ad81b1336cafebafeJason Monk 16628d5d220cc66eb4263aaae083a8496950258642bJason Monk protected void attachFragmentToWindow() { 16728d5d220cc66eb4263aaae083a8496950258642bJason Monk ViewUtils.attachView(mView); 1681660a27b5d682cbb0bd9e2ce66e5ca39d6ab7816Jason Monk TestableLooper.get(this).processAllMessages(); 1698852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1708852905b0b3837e326127c6dfef6f699124ce715Jason Monk 17128d5d220cc66eb4263aaae083a8496950258642bJason Monk protected void detachFragmentToWindow() { 17228d5d220cc66eb4263aaae083a8496950258642bJason Monk ViewUtils.detachView(mView); 1731660a27b5d682cbb0bd9e2ce66e5ca39d6ab7816Jason Monk TestableLooper.get(this).processAllMessages(); 17428d5d220cc66eb4263aaae083a8496950258642bJason Monk } 17528d5d220cc66eb4263aaae083a8496950258642bJason Monk 17628d5d220cc66eb4263aaae083a8496950258642bJason Monk protected void destroyFragments() { 17728d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments.dispatchDestroy(); 17828d5d220cc66eb4263aaae083a8496950258642bJason Monk processAllMessages(); 17928d5d220cc66eb4263aaae083a8496950258642bJason Monk mFragments = null; 1808852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1818852905b0b3837e326127c6dfef6f699124ce715Jason Monk 18228d5d220cc66eb4263aaae083a8496950258642bJason Monk protected void processAllMessages() { 18328d5d220cc66eb4263aaae083a8496950258642bJason Monk TestableLooper.get(this).processAllMessages(); 1848852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1858852905b0b3837e326127c6dfef6f699124ce715Jason Monk 1868852905b0b3837e326127c6dfef6f699124ce715Jason Monk private View findViewById(int id) { 1878852905b0b3837e326127c6dfef6f699124ce715Jason Monk return mView.findViewById(id); 1888852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1898852905b0b3837e326127c6dfef6f699124ce715Jason Monk 190340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk private class HostCallbacks extends FragmentHostCallback<BaseFragmentTest> { 1918852905b0b3837e326127c6dfef6f699124ce715Jason Monk public HostCallbacks() { 192340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk super(mContext, BaseFragmentTest.this.mHandler, 0); 1938852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1948852905b0b3837e326127c6dfef6f699124ce715Jason Monk 1958852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 196340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk public BaseFragmentTest onGetHost() { 197340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk return BaseFragmentTest.this; 1988852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 1998852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2008852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2018852905b0b3837e326127c6dfef6f699124ce715Jason Monk public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 2028852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2038852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2048852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2058852905b0b3837e326127c6dfef6f699124ce715Jason Monk public boolean onShouldSaveFragmentState(Fragment fragment) { 2068852905b0b3837e326127c6dfef6f699124ce715Jason Monk return true; // True for now. 2078852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2088852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2098852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2108852905b0b3837e326127c6dfef6f699124ce715Jason Monk public LayoutInflater onGetLayoutInflater() { 2118852905b0b3837e326127c6dfef6f699124ce715Jason Monk return LayoutInflater.from(mContext); 2128852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2138852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2148852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2158852905b0b3837e326127c6dfef6f699124ce715Jason Monk public boolean onUseFragmentManagerInflaterFactory() { 2168852905b0b3837e326127c6dfef6f699124ce715Jason Monk return true; 2178852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2188852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2198852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2208852905b0b3837e326127c6dfef6f699124ce715Jason Monk public boolean onHasWindowAnimations() { 2218852905b0b3837e326127c6dfef6f699124ce715Jason Monk return false; 2228852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2238852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2248852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2258852905b0b3837e326127c6dfef6f699124ce715Jason Monk public int onGetWindowAnimations() { 2268852905b0b3837e326127c6dfef6f699124ce715Jason Monk return 0; 2278852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2288852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2298852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2308852905b0b3837e326127c6dfef6f699124ce715Jason Monk public void onAttachFragment(Fragment fragment) { 2318852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2328852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2338852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Nullable 2348852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2358852905b0b3837e326127c6dfef6f699124ce715Jason Monk public View onFindViewById(int id) { 236340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk return BaseFragmentTest.this.findViewById(id); 2378852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2388852905b0b3837e326127c6dfef6f699124ce715Jason Monk 2398852905b0b3837e326127c6dfef6f699124ce715Jason Monk @Override 2408852905b0b3837e326127c6dfef6f699124ce715Jason Monk public boolean onHasView() { 2418852905b0b3837e326127c6dfef6f699124ce715Jason Monk return true; 2428852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2438852905b0b3837e326127c6dfef6f699124ce715Jason Monk } 2448852905b0b3837e326127c6dfef6f699124ce715Jason Monk} 245