249 lines
7.2 KiB
Java
249 lines
7.2 KiB
Java
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under the
|
|
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the specific language governing
|
|
* permissions and limitations under the License.
|
|
*/
|
|
|
|
package android.testing;
|
|
|
|
import static org.junit.Assert.assertNotNull;
|
|
|
|
import android.annotation.Nullable;
|
|
import android.app.Fragment;
|
|
import android.app.FragmentController;
|
|
import android.app.FragmentHostCallback;
|
|
import android.app.FragmentManagerNonConfig;
|
|
import android.graphics.PixelFormat;
|
|
import android.os.Handler;
|
|
import android.os.Parcelable;
|
|
import android.support.test.InstrumentationRegistry;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.WindowManager;
|
|
import android.view.WindowManager.LayoutParams;
|
|
import android.widget.FrameLayout;
|
|
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
|
|
/**
|
|
* Base class for fragment class tests. Just adding one for any fragment will push it through
|
|
* general lifecycle events and ensure no basic leaks are happening. This class also implements
|
|
* the host for subclasses, so they can push it into desired states and do any unit testing
|
|
* required.
|
|
*/
|
|
public abstract class BaseFragmentTest {
|
|
|
|
private static final int VIEW_ID = 42;
|
|
private final Class<? extends Fragment> mCls;
|
|
private Handler mHandler;
|
|
protected FrameLayout mView;
|
|
protected FragmentController mFragments;
|
|
protected Fragment mFragment;
|
|
|
|
@Rule
|
|
public final TestableContext mContext = getContext();
|
|
|
|
public BaseFragmentTest(Class<? extends Fragment> cls) {
|
|
mCls = cls;
|
|
}
|
|
|
|
protected void createRootView() {
|
|
mView = new FrameLayout(mContext);
|
|
}
|
|
|
|
@Before
|
|
public void setupFragment() throws Exception {
|
|
createRootView();
|
|
mView.setId(VIEW_ID);
|
|
|
|
assertNotNull("BaseFragmentTest must be tagged with @RunWithLooper",
|
|
TestableLooper.get(this));
|
|
TestableLooper.get(this).runWithLooper(() -> {
|
|
mHandler = new Handler();
|
|
|
|
mFragment = mCls.newInstance();
|
|
mFragments = FragmentController.createController(new HostCallbacks());
|
|
mFragments.attachHost(null);
|
|
mFragments.getFragmentManager().beginTransaction()
|
|
.replace(VIEW_ID, mFragment)
|
|
.commit();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Allows tests to sub-class TestableContext if they want to provide any extended functionality
|
|
* or provide a {@link LeakCheck} to the TestableContext upon instantiation.
|
|
*/
|
|
protected TestableContext getContext() {
|
|
return new TestableContext(InstrumentationRegistry.getContext());
|
|
}
|
|
|
|
@After
|
|
public void tearDown() throws Exception {
|
|
if (mFragments != null) {
|
|
// Set mFragments to null to let it know not to destroy.
|
|
TestableLooper.get(this).runWithLooper(() -> mFragments.dispatchDestroy());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testCreateDestroy() {
|
|
mFragments.dispatchCreate();
|
|
processAllMessages();
|
|
destroyFragments();
|
|
}
|
|
|
|
@Test
|
|
public void testStartStop() {
|
|
mFragments.dispatchStart();
|
|
processAllMessages();
|
|
mFragments.dispatchStop();
|
|
processAllMessages();
|
|
}
|
|
|
|
@Test
|
|
public void testResumePause() {
|
|
mFragments.dispatchResume();
|
|
processAllMessages();
|
|
mFragments.dispatchPause();
|
|
processAllMessages();
|
|
}
|
|
|
|
@Test
|
|
public void testAttachDetach() {
|
|
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
|
|
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
|
|
LayoutParams.TYPE_SYSTEM_ALERT,
|
|
0, PixelFormat.TRANSLUCENT);
|
|
mFragments.dispatchResume();
|
|
processAllMessages();
|
|
attachFragmentToWindow();
|
|
detachFragmentToWindow();
|
|
mFragments.dispatchPause();
|
|
processAllMessages();
|
|
}
|
|
|
|
@Test
|
|
public void testRecreate() {
|
|
mFragments.dispatchResume();
|
|
processAllMessages();
|
|
recreateFragment();
|
|
processAllMessages();
|
|
}
|
|
|
|
@Test
|
|
public void testMultipleResumes() {
|
|
mFragments.dispatchResume();
|
|
processAllMessages();
|
|
mFragments.dispatchStop();
|
|
processAllMessages();
|
|
mFragments.dispatchResume();
|
|
processAllMessages();
|
|
}
|
|
|
|
protected void recreateFragment() {
|
|
mFragments.dispatchPause();
|
|
Parcelable p = mFragments.saveAllState();
|
|
mFragments.dispatchDestroy();
|
|
|
|
mFragments = FragmentController.createController(new HostCallbacks());
|
|
mFragments.attachHost(null);
|
|
mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
|
|
mFragments.dispatchResume();
|
|
mFragment = mFragments.getFragmentManager().findFragmentById(VIEW_ID);
|
|
}
|
|
|
|
protected void attachFragmentToWindow() {
|
|
ViewUtils.attachView(mView);
|
|
TestableLooper.get(this).processAllMessages();
|
|
}
|
|
|
|
protected void detachFragmentToWindow() {
|
|
ViewUtils.detachView(mView);
|
|
TestableLooper.get(this).processAllMessages();
|
|
}
|
|
|
|
protected void destroyFragments() {
|
|
mFragments.dispatchDestroy();
|
|
processAllMessages();
|
|
mFragments = null;
|
|
}
|
|
|
|
protected void processAllMessages() {
|
|
TestableLooper.get(this).processAllMessages();
|
|
}
|
|
|
|
private View findViewById(int id) {
|
|
return mView.findViewById(id);
|
|
}
|
|
|
|
private class HostCallbacks extends FragmentHostCallback<BaseFragmentTest> {
|
|
public HostCallbacks() {
|
|
super(mContext, BaseFragmentTest.this.mHandler, 0);
|
|
}
|
|
|
|
@Override
|
|
public BaseFragmentTest onGetHost() {
|
|
return BaseFragmentTest.this;
|
|
}
|
|
|
|
@Override
|
|
public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
|
|
}
|
|
|
|
@Override
|
|
public boolean onShouldSaveFragmentState(Fragment fragment) {
|
|
return true; // True for now.
|
|
}
|
|
|
|
@Override
|
|
public LayoutInflater onGetLayoutInflater() {
|
|
return LayoutInflater.from(mContext);
|
|
}
|
|
|
|
@Override
|
|
public boolean onUseFragmentManagerInflaterFactory() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onHasWindowAnimations() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int onGetWindowAnimations() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void onAttachFragment(Fragment fragment) {
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public View onFindViewById(int id) {
|
|
return BaseFragmentTest.this.findViewById(id);
|
|
}
|
|
|
|
@Override
|
|
public boolean onHasView() {
|
|
return true;
|
|
}
|
|
}
|
|
}
|