/** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.drawable.Drawable; import com.facebook.litho.testing.ComponentTestHelper; import com.facebook.litho.testing.testrunner.ComponentsTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; @RunWith(ComponentsTestRunner.class) public class LifecycleMethodsTest { private enum LifecycleStep { ON_CREATE_LAYOUT, ON_PREPARE, ON_MEASURE, ON_BOUNDS_DEFINED, ON_CREATE_MOUNT_CONTENT, ON_MOUNT, ON_BIND, ON_UNBIND, ON_UNMOUNT } private LithoView mLithoView; private ComponentTree mComponentTree; private LifecycleMethodsComponent mLifecycle; private LifecycleMethodsInstance mComponent; @Before public void setup() throws Exception { mLithoView = new LithoView(RuntimeEnvironment.application); mLifecycle = new LifecycleMethodsComponent(); mComponent = mLifecycle.create(10); final ComponentContext c = new ComponentContext(RuntimeEnvironment.application); mComponentTree = ComponentTree.create(c, mComponent) .incrementalMount(false) .layoutDiffing(false) .build(); mLithoView.setComponentTree(mComponentTree); } @Test public void testLifecycle() { mLithoView.onAttachedToWindow(); ComponentTestHelper.measureAndLayout(mLithoView); assertEquals(LifecycleStep.ON_BIND, mComponent.getCurrentStep()); mLithoView.onDetachedFromWindow(); assertEquals(LifecycleStep.ON_UNBIND, mComponent.getCurrentStep()); mLithoView.onAttachedToWindow(); assertEquals(LifecycleStep.ON_BIND, mComponent.getCurrentStep()); mComponentTree.setRoot(mLifecycle.create(20)); ComponentTestHelper.measureAndLayout(mLithoView); assertEquals(LifecycleStep.ON_UNMOUNT, mComponent.getCurrentStep()); mComponentTree.setRoot(mComponent); ComponentTestHelper.measureAndLayout(mLithoView); assertEquals(LifecycleStep.ON_BIND, mComponent.getCurrentStep()); mLithoView.onDetachedFromWindow(); mComponentTree.setRoot(mComponent); ComponentTestHelper.measureAndLayout(mLithoView); assertEquals(LifecycleStep.ON_UNBIND, mComponent.getCurrentStep()); } private class LifecycleMethodsComponent extends ComponentLifecycle { @Override protected ComponentLayout onCreateLayout(ComponentContext c, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_CREATE_LAYOUT); return super.onCreateLayout(c, component); } @Override protected void onPrepare(ComponentContext c, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_PREPARE); } @Override protected boolean canMeasure() { return true; } @Override protected void onMeasure( ComponentContext c, ComponentLayout layout, int widthSpec, int heightSpec, Size size, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_MEASURE); size.width = instance.getSize(); size.height = instance.getSize(); } @Override protected void onBoundsDefined( ComponentContext c, ComponentLayout layout, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_BOUNDS_DEFINED); } @Override protected Object onCreateMountContent(ComponentContext context) { mComponent.setCurrentStep(LifecycleStep.ON_CREATE_MOUNT_CONTENT); return new LifecycleMethodsDrawable(mComponent); } @Override protected void onMount( ComponentContext c, Object convertContent, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_MOUNT); final LifecycleMethodsDrawable d = (LifecycleMethodsDrawable) convertContent; d.setComponent(instance); } @Override protected void onUnmount( ComponentContext c, Object mountedContent, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_UNMOUNT); } @Override protected void onBind( ComponentContext c, Object mountedContent, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_BIND); } @Override protected void onUnbind( ComponentContext c, Object mountedContent, Component<?> component) { LifecycleMethodsInstance instance = (LifecycleMethodsInstance) component; instance.setCurrentStep(LifecycleStep.ON_UNBIND); } @Override protected boolean shouldUpdate(Component previous, Component next) { return true; } @Override public MountType getMountType() { return MountType.DRAWABLE; } public LifecycleMethodsInstance create(int size) { return new LifecycleMethodsInstance(this, size); } } private static class LifecycleMethodsInstance extends Component<LifecycleMethodsComponent> implements Cloneable { private final int mSize; LifecycleStep mCurrentStep = LifecycleStep.ON_UNMOUNT; protected LifecycleMethodsInstance(LifecycleMethodsComponent l, int size) { super(l); mSize = size; } @Override public String getSimpleName() { return "LifecycleMethodsInstance"; } LifecycleStep getCurrentStep() { return mCurrentStep; } void setCurrentStep(LifecycleStep currentStep) { switch (currentStep) { case ON_CREATE_LAYOUT: assertEquals(LifecycleStep.ON_UNMOUNT, mCurrentStep); break; case ON_PREPARE: assertEquals(LifecycleStep.ON_CREATE_LAYOUT, mCurrentStep); break; case ON_MEASURE: assertTrue( mCurrentStep == LifecycleStep.ON_PREPARE || mCurrentStep == LifecycleStep.ON_MEASURE); break; case ON_BOUNDS_DEFINED: assertTrue( mCurrentStep == LifecycleStep.ON_PREPARE || mCurrentStep == LifecycleStep.ON_MEASURE); break; case ON_CREATE_MOUNT_CONTENT: assertTrue( mCurrentStep == LifecycleStep.ON_BOUNDS_DEFINED); case ON_MOUNT: assertTrue( mCurrentStep == LifecycleStep.ON_BOUNDS_DEFINED || mCurrentStep == LifecycleStep.ON_CREATE_MOUNT_CONTENT); break; case ON_BIND: assertTrue( mCurrentStep == LifecycleStep.ON_MOUNT || mCurrentStep == LifecycleStep.ON_UNBIND); break; case ON_UNBIND: assertEquals(LifecycleStep.ON_BIND, mCurrentStep); break; case ON_UNMOUNT: assertEquals(LifecycleStep.ON_UNBIND, mCurrentStep); break; } mCurrentStep = currentStep; } int getSize() { return mSize; } @Override public Component<LifecycleMethodsComponent> makeShallowCopy() { return this; } } private static class LifecycleMethodsDrawable extends Drawable { private LifecycleMethodsInstance mComponent; private LifecycleMethodsDrawable(LifecycleMethodsInstance component) { assertEquals(LifecycleStep.ON_CREATE_MOUNT_CONTENT, component.getCurrentStep()); } void setComponent(LifecycleMethodsInstance component) { mComponent = component; assertEquals(LifecycleStep.ON_MOUNT, mComponent.getCurrentStep()); } @Override public void setBounds(int l, int t, int r, int b) { super.setBounds(l, t, r, b); assertTrue( mComponent.getCurrentStep() == LifecycleStep.ON_BIND || mComponent.getCurrentStep() == LifecycleStep.ON_UNBIND); } @Override public void draw(Canvas canvas) { assertEquals(mComponent.getCurrentStep(), LifecycleStep.ON_BIND); } @Override public void setAlpha(int alpha) { } @Override public void setColorFilter(ColorFilter cf) { } @Override public int getOpacity() { return 0; } } }