blob: a4c8e689c6cb2b10e1fc185a84466ed3e4c387c5 [file] [log] [blame]
/*
* Copyright 2018 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 androidx.fragment.app.test;
import static org.junit.Assert.assertFalse;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.transition.Transition;
import android.transition.Transition.TransitionListener;
import android.transition.TransitionInflater;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.test.R;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* A simple activity used for Fragment Transitions and lifecycle event ordering
*/
public class FragmentTestActivity extends FragmentActivity {
public final CountDownLatch onDestroyLatch = new CountDownLatch(1);
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_content);
Intent intent = getIntent();
if (intent != null && intent.getBooleanExtra("finishEarly", false)) {
finish();
getSupportFragmentManager().beginTransaction()
.add(new AssertNotDestroyed(), "not destroyed")
.commit();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
onDestroyLatch.countDown();
}
public static class TestFragment extends Fragment {
public static final int ENTER = 0;
public static final int RETURN = 1;
public static final int EXIT = 2;
public static final int REENTER = 3;
public static final int SHARED_ELEMENT_ENTER = 4;
public static final int SHARED_ELEMENT_RETURN = 5;
private static final int TRANSITION_COUNT = 6;
private static final String LAYOUT_ID = "layoutId";
private static final String TRANSITION_KEY = "transition_";
private int mLayoutId = R.layout.fragment_start;
private final int[] mTransitionIds = new int[] {
R.transition.fade,
R.transition.fade,
R.transition.fade,
R.transition.fade,
R.transition.change_bounds,
R.transition.change_bounds,
};
private final Object[] mListeners = new Object[TRANSITION_COUNT];
public TestFragment() {
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
for (int i = 0; i < TRANSITION_COUNT; i++) {
mListeners[i] = new TransitionCalledListener();
}
}
}
public static TestFragment create(int layoutId) {
TestFragment testFragment = new TestFragment();
testFragment.mLayoutId = layoutId;
return testFragment;
}
public void clearTransitions() {
for (int i = 0; i < TRANSITION_COUNT; i++) {
mTransitionIds[i] = 0;
}
}
public void clearNotifications() {
for (int i = 0; i < TRANSITION_COUNT; i++) {
((TransitionCalledListener)mListeners[i]).startLatch = new CountDownLatch(1);
((TransitionCalledListener)mListeners[i]).endLatch = new CountDownLatch(1);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mLayoutId = savedInstanceState.getInt(LAYOUT_ID, mLayoutId);
for (int i = 0; i < TRANSITION_COUNT; i++) {
String key = TRANSITION_KEY + i;
mTransitionIds[i] = savedInstanceState.getInt(key, mTransitionIds[i]);
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(LAYOUT_ID, mLayoutId);
for (int i = 0; i < TRANSITION_COUNT; i++) {
String key = TRANSITION_KEY + i;
outState.putInt(key, mTransitionIds[i]);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(mLayoutId, container, false);
}
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (VERSION.SDK_INT > VERSION_CODES.KITKAT) {
setEnterTransition(loadTransition(ENTER));
setReenterTransition(loadTransition(REENTER));
setExitTransition(loadTransition(EXIT));
setReturnTransition(loadTransition(RETURN));
setSharedElementEnterTransition(loadTransition(SHARED_ELEMENT_ENTER));
setSharedElementReturnTransition(loadTransition(SHARED_ELEMENT_RETURN));
}
}
public boolean wasStartCalled(int transitionKey) {
return ((TransitionCalledListener)mListeners[transitionKey]).startLatch.getCount() == 0;
}
public boolean wasEndCalled(int transitionKey) {
return ((TransitionCalledListener)mListeners[transitionKey]).endLatch.getCount() == 0;
}
public boolean waitForStart(int transitionKey)
throws InterruptedException {
TransitionCalledListener l = ((TransitionCalledListener)mListeners[transitionKey]);
return l.startLatch.await(500,TimeUnit.MILLISECONDS);
}
public boolean waitForEnd(int transitionKey)
throws InterruptedException {
TransitionCalledListener l = ((TransitionCalledListener)mListeners[transitionKey]);
return l.endLatch.await(500,TimeUnit.MILLISECONDS);
}
private Transition loadTransition(int key) {
final int id = mTransitionIds[key];
if (id == 0) {
return null;
}
Transition transition = TransitionInflater.from(getActivity()).inflateTransition(id);
transition.addListener(((TransitionCalledListener)mListeners[key]));
return transition;
}
private class TransitionCalledListener implements TransitionListener {
public CountDownLatch startLatch = new CountDownLatch(1);
public CountDownLatch endLatch = new CountDownLatch(1);
public TransitionCalledListener() {
}
@Override
public void onTransitionStart(Transition transition) {
startLatch.countDown();
}
@Override
public void onTransitionEnd(Transition transition) {
endLatch.countDown();
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
}
}
public static class ParentFragment extends Fragment {
static final String CHILD_FRAGMENT_TAG = "childFragment";
public boolean wasAttachedInTime;
private boolean mRetainChild;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ChildFragment f = getChildFragment();
if (f == null) {
f = new ChildFragment();
if (mRetainChild) {
f.setRetainInstance(true);
}
getChildFragmentManager().beginTransaction().add(f, CHILD_FRAGMENT_TAG).commitNow();
}
wasAttachedInTime = f.attached;
}
public ChildFragment getChildFragment() {
return (ChildFragment) getChildFragmentManager().findFragmentByTag(CHILD_FRAGMENT_TAG);
}
public void setRetainChildInstance(boolean retainChild) {
mRetainChild = retainChild;
}
}
public static class ChildFragment extends Fragment {
private OnAttachListener mOnAttachListener;
public boolean attached;
public boolean onActivityResultCalled;
public int onActivityResultRequestCode;
public int onActivityResultResultCode;
@Override
public void onAttach(Context activity) {
super.onAttach(activity);
attached = true;
if (mOnAttachListener != null) {
mOnAttachListener.onAttach(activity, this);
}
}
public void setOnAttachListener(OnAttachListener listener) {
mOnAttachListener = listener;
}
public interface OnAttachListener {
void onAttach(Context activity, ChildFragment fragment);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
onActivityResultCalled = true;
onActivityResultRequestCode = requestCode;
onActivityResultResultCode = resultCode;
}
}
public static class AssertNotDestroyed extends Fragment {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
assertFalse(getActivity().isDestroyed());
}
}
}
}