Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8297e0273d | |||
| 46519c2c2c | |||
| 211da8b2ea | |||
| 26db962168 | |||
| f4c1c6ccf5 | |||
| c89caa87e0 | |||
| 2748566437 | |||
| 506c99ed41 | |||
| 4fe0ec5f51 | |||
| afa93f2cc1 | |||
| 836f92b615 | |||
| 94c817bbd9 | |||
| fc1fee3e17 | |||
| 76b7572a01 | |||
| 3fc63b7f5f | |||
| 0ef52211a2 | |||
| 7574131940 | |||
| 1ab9a4c4f6 | |||
| 3bc23bd5cd | |||
| 5f138e5d43 | |||
| 03701d05a9 | |||
| a19968e0c9 | |||
| 5501ab2ac8 | |||
| 804fdb615e | |||
| c01b2a74d6 |
@@ -8,10 +8,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
- name: set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 1.8
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Test with Gradle
|
||||
@@ -23,10 +24,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
- name: set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 1.8
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Test with Gradle
|
||||
|
||||
Generated
+1
@@ -6,3 +6,4 @@
|
||||
/caches
|
||||
/gradle.xml
|
||||
/modules.xml
|
||||
/compiler.xml
|
||||
|
||||
Generated
+9
-1
@@ -118,7 +118,15 @@
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="5" />
|
||||
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="5" />
|
||||
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
|
||||
@@ -20,30 +20,27 @@ Conductor is architecture-agnostic and does not try to force any design decision
|
||||
## Installation
|
||||
|
||||
```gradle
|
||||
implementation 'com.bluelinelabs:conductor:3.0.0'
|
||||
implementation 'com.bluelinelabs:conductor:3.1.1'
|
||||
|
||||
// AndroidX Transition change handlers:
|
||||
implementation 'com.bluelinelabs:conductor-androidx-transition:3.0.0'
|
||||
implementation 'com.bluelinelabs:conductor-androidx-transition:3.1.1'
|
||||
|
||||
// ViewPager PagerAdapter:
|
||||
implementation 'com.bluelinelabs:conductor-viewpager:3.0.0'
|
||||
implementation 'com.bluelinelabs:conductor-viewpager:3.1.1'
|
||||
|
||||
// ViewPager2 Adapter:
|
||||
implementation 'com.bluelinelabs:conductor-viewpager2:3.0.0'
|
||||
|
||||
// RxJava2 lifecycle support:
|
||||
implementation 'com.bluelinelabs:conductor-rxlifecycle2:3.0.0'
|
||||
implementation 'com.bluelinelabs:conductor-viewpager2:3.1.1'
|
||||
|
||||
// RxJava2 Autodispose support:
|
||||
implementation 'com.bluelinelabs:conductor-autodispose:3.0.0'
|
||||
implementation 'com.bluelinelabs:conductor-autodispose:3.1.1'
|
||||
|
||||
// Lifecycle-aware Controllers (architecture components):
|
||||
implementation 'com.bluelinelabs:conductor-archlifecycle:3.0.0'
|
||||
implementation 'com.bluelinelabs:conductor-archlifecycle:3.1.1'
|
||||
```
|
||||
|
||||
**SNAPSHOT**
|
||||
|
||||
Just use `3.0.1-SNAPSHOT` as your version number in any of the dependencies above and add the url to the snapshot repository:
|
||||
Just use `3.1.2-SNAPSHOT` as your version number in any of the dependencies above and add the url to the snapshot repository:
|
||||
|
||||
```gradle
|
||||
allprojects {
|
||||
|
||||
@@ -4,7 +4,6 @@ buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:$agpVersion"
|
||||
@@ -18,7 +17,6 @@ allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
configurations {
|
||||
lintChecks
|
||||
@@ -7,7 +7,9 @@ configurations {
|
||||
dependencies {
|
||||
compileOnly rootProject.ext.lintapi
|
||||
compileOnly rootProject.ext.lintchecks
|
||||
compileOnly rootProject.ext.kotlinStd
|
||||
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.lint
|
||||
testImplementation rootProject.ext.lintTests
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.bluelinelabs.conductor.lint;
|
||||
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.tools.lint.detector.api.ApiKt.CURRENT_API;
|
||||
|
||||
@SuppressWarnings({"unused", "UnstableApiUsage"})
|
||||
public final class IssueRegistry extends com.android.tools.lint.client.api.IssueRegistry {
|
||||
|
||||
@Override
|
||||
public List<Issue> getIssues() {
|
||||
return Arrays.asList(
|
||||
ControllerIssueDetector.ISSUE,
|
||||
ControllerChangeHandlerIssueDetector.ISSUE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getApi() {
|
||||
return CURRENT_API;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.bluelinelabs.conductor.lint
|
||||
|
||||
import com.android.tools.lint.client.api.Vendor
|
||||
import com.android.tools.lint.detector.api.CURRENT_API
|
||||
import com.android.tools.lint.client.api.IssueRegistry as LintIssueRegistry
|
||||
|
||||
@Suppress("UnstableApiUsage", "unused")
|
||||
class IssueRegistry : LintIssueRegistry() {
|
||||
|
||||
override val issues = listOf(
|
||||
ControllerIssueDetector.ISSUE,
|
||||
ControllerChangeHandlerIssueDetector.ISSUE
|
||||
)
|
||||
|
||||
override val api: Int = CURRENT_API
|
||||
|
||||
private val githubIssueLink = "https://github.com/bluelinelabs/Conductor/issues/new"
|
||||
|
||||
override val vendor = Vendor(
|
||||
vendorName = "Conductor",
|
||||
feedbackUrl = githubIssueLink,
|
||||
contact = githubIssueLink
|
||||
)
|
||||
}
|
||||
+6
-6
@@ -1,13 +1,13 @@
|
||||
package com.bluelinelabs.conductor.lint;
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.LintDetectorTest;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.android.tools.lint.checks.infrastructure.TestFiles.java;
|
||||
import static com.android.tools.lint.checks.infrastructure.TestLintTask.lint;
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.TestFile;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.junit.Test;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class ControllerChangeHandlerDetectorTest {
|
||||
|
||||
@@ -17,7 +17,7 @@ public class ControllerChangeHandlerDetectorTest {
|
||||
+ "^\n"
|
||||
+ "1 errors, 0 warnings\n";
|
||||
|
||||
private final LintDetectorTest.TestFile controllerChangeHandlerStub = java(
|
||||
private final TestFile controllerChangeHandlerStub = java(
|
||||
"package com.bluelinelabs.conductor;\n"
|
||||
+ "abstract class ControllerChangeHandler {}"
|
||||
);
|
||||
|
||||
+6
-6
@@ -1,13 +1,13 @@
|
||||
package com.bluelinelabs.conductor.lint;
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.LintDetectorTest;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.android.tools.lint.checks.infrastructure.TestFiles.java;
|
||||
import static com.android.tools.lint.checks.infrastructure.TestLintTask.lint;
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.TestFile;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.junit.Test;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class ControllerDetectorTest {
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ControllerDetectorTest {
|
||||
+ "^\n"
|
||||
+ "1 errors, 0 warnings\n";
|
||||
|
||||
private final LintDetectorTest.TestFile controllerStub = java(
|
||||
private final TestFile controllerStub = java(
|
||||
"package com.bluelinelabs.conductor;\n"
|
||||
+ "abstract class Controller {}"
|
||||
);
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api rootProject.ext.rxJava2
|
||||
api rootProject.ext.rxLifecycle2
|
||||
api rootProject.ext.rxLifecycleAndroid2
|
||||
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-rxlifecycle2'
|
||||
@@ -1,3 +0,0 @@
|
||||
POM_NAME=Conductor RxLifecycle2 Extensions
|
||||
POM_ARTIFACT_ID=conductor-rxlifecycle2
|
||||
POM_PACKAGING=aar
|
||||
@@ -1,3 +0,0 @@
|
||||
<manifest package="com.bluelinelabs.conductor.rxlifecycle2">
|
||||
<application />
|
||||
</manifest>
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
public enum ControllerEvent {
|
||||
|
||||
CREATE,
|
||||
CONTEXT_AVAILABLE,
|
||||
CREATE_VIEW,
|
||||
ATTACH,
|
||||
DETACH,
|
||||
DESTROY_VIEW,
|
||||
CONTEXT_UNAVAILABLE,
|
||||
DESTROY
|
||||
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.trello.rxlifecycle2.OutsideLifecycleException;
|
||||
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
||||
public class ControllerLifecycleSubjectHelper {
|
||||
private ControllerLifecycleSubjectHelper() {
|
||||
}
|
||||
|
||||
public static BehaviorSubject<ControllerEvent> create(Controller controller) {
|
||||
ControllerEvent initialState;
|
||||
if (controller.isBeingDestroyed() || controller.isDestroyed()) {
|
||||
throw new OutsideLifecycleException("Cannot bind to Controller lifecycle when outside of it.");
|
||||
} else if (controller.isAttached()) {
|
||||
initialState = ControllerEvent.ATTACH;
|
||||
} else if (controller.getView() != null) {
|
||||
initialState = ControllerEvent.CREATE_VIEW;
|
||||
} else if (controller.getActivity() != null) {
|
||||
initialState = ControllerEvent.CONTEXT_AVAILABLE;
|
||||
} else {
|
||||
initialState = ControllerEvent.CREATE;
|
||||
}
|
||||
|
||||
final BehaviorSubject<ControllerEvent> subject = BehaviorSubject.createDefault(initialState);
|
||||
|
||||
controller.addLifecycleListener(new Controller.LifecycleListener() {
|
||||
@Override
|
||||
public void preContextAvailable(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_AVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCreateView(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CREATE_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
subject.onNext(ControllerEvent.ATTACH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
subject.onNext(ControllerEvent.DETACH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroyView(@NonNull Controller controller, @NonNull View view) {
|
||||
subject.onNext(ControllerEvent.DESTROY_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preContextUnavailable(@NonNull Controller controller, @NonNull Context context) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.DESTROY);
|
||||
}
|
||||
});
|
||||
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.trello.rxlifecycle2.LifecycleProvider;
|
||||
import com.trello.rxlifecycle2.LifecycleTransformer;
|
||||
import com.trello.rxlifecycle2.RxLifecycle;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
||||
/**
|
||||
* A base {@link Controller} that can be used to expose lifecycle events using RxJava
|
||||
*/
|
||||
public abstract class RxController extends Controller implements LifecycleProvider<ControllerEvent> {
|
||||
private final BehaviorSubject<ControllerEvent> lifecycleSubject;
|
||||
|
||||
public RxController(){
|
||||
this(null);
|
||||
}
|
||||
|
||||
public RxController(@Nullable Bundle args) {
|
||||
super(args);
|
||||
lifecycleSubject = ControllerLifecycleSubjectHelper.create(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
@CheckResult
|
||||
public final Observable<ControllerEvent> lifecycle() {
|
||||
return lifecycleSubject.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
@CheckResult
|
||||
public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ControllerEvent event) {
|
||||
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
@CheckResult
|
||||
public final <T> LifecycleTransformer<T> bindToLifecycle() {
|
||||
return RxControllerLifecycle.bindController(lifecycleSubject);
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.trello.rxlifecycle2.LifecycleTransformer;
|
||||
import com.trello.rxlifecycle2.OutsideLifecycleException;
|
||||
import com.trello.rxlifecycle2.RxLifecycle;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.functions.Function;
|
||||
|
||||
public class RxControllerLifecycle {
|
||||
|
||||
/**
|
||||
* Binds the given source to a Controller lifecycle. This is the Controller version of
|
||||
* {@link com.trello.rxlifecycle2.android.RxLifecycleAndroid#bindFragment(Observable)}.
|
||||
*
|
||||
* @param lifecycle the lifecycle sequence of a Controller
|
||||
* @return a reusable {@link io.reactivex.ObservableTransformer} that unsubscribes the source during the Controller lifecycle
|
||||
*/
|
||||
public static <T> LifecycleTransformer<T> bindController(@NonNull final Observable<ControllerEvent> lifecycle) {
|
||||
return RxLifecycle.bind(lifecycle, CONTROLLER_LIFECYCLE);
|
||||
}
|
||||
|
||||
private static final Function<ControllerEvent, ControllerEvent> CONTROLLER_LIFECYCLE =
|
||||
new Function<ControllerEvent, ControllerEvent>() {
|
||||
@Override
|
||||
public ControllerEvent apply(ControllerEvent lastEvent) {
|
||||
switch (lastEvent) {
|
||||
case CREATE:
|
||||
return ControllerEvent.DESTROY;
|
||||
case CONTEXT_AVAILABLE:
|
||||
return ControllerEvent.CONTEXT_UNAVAILABLE;
|
||||
case ATTACH:
|
||||
return ControllerEvent.DETACH;
|
||||
case CREATE_VIEW:
|
||||
return ControllerEvent.DESTROY_VIEW;
|
||||
case DETACH:
|
||||
return ControllerEvent.DESTROY;
|
||||
default:
|
||||
throw new OutsideLifecycleException("Cannot bind to Controller lifecycle when outside of it.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -14,13 +14,13 @@ android {
|
||||
|
||||
dependencies {
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.roboelectric
|
||||
testImplementation rootProject.ext.robolectric
|
||||
|
||||
implementation rootProject.ext.androidxAppCompat
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-viewpager'
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
ext.artifactId = 'conductor-viewpager'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
+8
-49
@@ -1,69 +1,31 @@
|
||||
package com.bluelinelabs.conductor.viewpager
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Looper.getMainLooper
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.bluelinelabs.conductor.Conductor
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import com.bluelinelabs.conductor.RouterTransaction.Companion.with
|
||||
import com.bluelinelabs.conductor.viewpager.util.TestController
|
||||
import com.bluelinelabs.conductor.viewpager.util.TestActivity
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class StateSaveTests {
|
||||
|
||||
private val pager: ViewPager
|
||||
private val pagerAdapter: RouterPagerAdapter
|
||||
private val destroyedItems = mutableListOf<Int>()
|
||||
private val testController = Robolectric.buildActivity(TestActivity::class.java)
|
||||
.setup()
|
||||
.get()
|
||||
.testController()
|
||||
|
||||
init {
|
||||
val activityController = Robolectric.buildActivity(Activity::class.java).setup()
|
||||
val layout = FrameLayout(activityController.get())
|
||||
activityController.get().setContentView(layout)
|
||||
val router = Conductor.attachRouter(activityController.get(), FrameLayout(activityController.get()), null)
|
||||
val controller = TestController()
|
||||
router.setRoot(with(controller))
|
||||
pager = ViewPager(activityController.get()).also {
|
||||
it.id = ViewCompat.generateViewId()
|
||||
}
|
||||
layout.addView(pager)
|
||||
pager.offscreenPageLimit = 1
|
||||
pagerAdapter = object : RouterPagerAdapter(controller) {
|
||||
override fun configureRouter(router: Router, position: Int) {
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(with(TestController()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return 20
|
||||
}
|
||||
|
||||
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
|
||||
super.destroyItem(container, position, `object`)
|
||||
destroyedItems.add(position)
|
||||
}
|
||||
}
|
||||
pager.adapter = pagerAdapter
|
||||
shadowOf(getMainLooper()).idle()
|
||||
}
|
||||
private val pagerAdapter = testController.pagerAdapter
|
||||
private val pager = testController.pager
|
||||
private val destroyedItems = testController.destroyedItems
|
||||
|
||||
@Test
|
||||
fun testNoMaxSaves() {
|
||||
// Load all pages
|
||||
for (i in 0 until pagerAdapter.count) {
|
||||
pager.currentItem = i
|
||||
shadowOf(getMainLooper()).idle()
|
||||
}
|
||||
|
||||
// Ensure all non-visible pages are saved
|
||||
@@ -81,13 +43,11 @@ class StateSaveTests {
|
||||
// Load all pages
|
||||
for (i in 0 until pagerAdapter.count) {
|
||||
pager.currentItem = i
|
||||
shadowOf(getMainLooper()).idle()
|
||||
}
|
||||
|
||||
val firstSelectedItem = pagerAdapter.count / 2
|
||||
for (i in pagerAdapter.count downTo firstSelectedItem) {
|
||||
pager.currentItem = i
|
||||
shadowOf(getMainLooper()).idle()
|
||||
}
|
||||
|
||||
var savedPages = pagerAdapter.savedPages
|
||||
@@ -103,7 +63,6 @@ class StateSaveTests {
|
||||
val secondSelectedItem = 1
|
||||
for (i in firstSelectedItem downTo secondSelectedItem) {
|
||||
pager.currentItem = i
|
||||
shadowOf(getMainLooper()).idle()
|
||||
}
|
||||
|
||||
savedPages = pagerAdapter.savedPages
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.bluelinelabs.conductor.viewpager.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.bluelinelabs.conductor.Conductor
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.asTransaction
|
||||
import com.bluelinelabs.conductor.viewpager.RouterPagerAdapter
|
||||
|
||||
class TestActivity : Activity() {
|
||||
|
||||
private lateinit var router: Router
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
router = Conductor.attachRouter(
|
||||
this,
|
||||
findViewById(android.R.id.content),
|
||||
savedInstanceState
|
||||
)
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(TestController().asTransaction())
|
||||
}
|
||||
}
|
||||
|
||||
fun testController(): TestController {
|
||||
return router.backstack.single().controller as TestController
|
||||
}
|
||||
}
|
||||
|
||||
class TestController : Controller() {
|
||||
|
||||
val destroyedItems = mutableListOf<Int>()
|
||||
lateinit var pagerAdapter: RouterPagerAdapter
|
||||
lateinit var pager: ViewPager
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
savedViewState: Bundle?
|
||||
): View {
|
||||
pager = ViewPager(container.context).also {
|
||||
it.id = ViewCompat.generateViewId()
|
||||
}
|
||||
pager.offscreenPageLimit = 1
|
||||
pagerAdapter = object : RouterPagerAdapter(this) {
|
||||
|
||||
override fun configureRouter(router: Router, position: Int) {
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(PageController()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return 20
|
||||
}
|
||||
|
||||
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
|
||||
super.destroyItem(container, position, `object`)
|
||||
destroyedItems.add(position)
|
||||
}
|
||||
}
|
||||
pager.adapter = pagerAdapter
|
||||
return pager
|
||||
}
|
||||
}
|
||||
|
||||
class PageController : Controller() {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
savedViewState: Bundle?
|
||||
): View {
|
||||
return FrameLayout(container.context)
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.bluelinelabs.conductor.viewpager.util;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
|
||||
public class TestController extends Controller {
|
||||
|
||||
@Override @NonNull
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container, @Nullable Bundle savedViewState) {
|
||||
return new FrameLayout(inflater.getContext());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
@@ -21,14 +21,14 @@ android {
|
||||
|
||||
dependencies {
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.roboelectric
|
||||
testImplementation rootProject.ext.robolectric
|
||||
|
||||
implementation rootProject.ext.androidxAppCompat
|
||||
implementation rootProject.ext.androidxViewPager2
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-viewpager2'
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
ext.artifactId = 'conductor-viewpager2'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
+6
-4
@@ -10,7 +10,7 @@ import androidx.viewpager2.adapter.StatefulAdapter
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
/**
|
||||
* An ViewPager2 adapter that uses Routers as pages
|
||||
@@ -48,7 +48,8 @@ abstract class RouterStateAdapter(private val host: Controller) :
|
||||
}
|
||||
|
||||
private fun inferViewPager(recyclerView: RecyclerView): ViewPager2 {
|
||||
return recyclerView.parent as? ViewPager2 ?: error("Expected ViewPager2 instance. Got: ${recyclerView.parent}")
|
||||
return recyclerView.parent as? ViewPager2
|
||||
?: error("Expected ViewPager2 instance. Got: ${recyclerView.parent}")
|
||||
}
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
@@ -119,7 +120,8 @@ abstract class RouterStateAdapter(private val host: Controller) :
|
||||
|
||||
override fun saveState(): Parcelable {
|
||||
// Ensure all visible pages are saved, starting at the outermost pages and working our way in
|
||||
val visiblePositions = (0 until visibleRouters.size()).map { visibleRouters.keyAt(it) }.toMutableList()
|
||||
val visiblePositions = (0 until visibleRouters.size())
|
||||
.map { visibleRouters.keyAt(it) }.toMutableList()
|
||||
while (visiblePositions.isNotEmpty()) {
|
||||
val lastPosition = visiblePositions.removeAt(visiblePositions.lastIndex)
|
||||
savePage(getItemId(lastPosition), visibleRouters[lastPosition])
|
||||
@@ -152,7 +154,7 @@ abstract class RouterStateAdapter(private val host: Controller) :
|
||||
|
||||
private fun attachRouter(holder: RouterViewHolder, position: Int) {
|
||||
val itemId = getItemId(position)
|
||||
val router = host.getChildRouter(holder.container, "$itemId")
|
||||
val router = host.getChildRouter(holder.container, "$itemId", true, false)!!
|
||||
|
||||
// This should have already been handled by onViewRecycled, but it seems like this wasn't
|
||||
// always reliably called
|
||||
|
||||
@@ -14,8 +14,12 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation savedState
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.roboelectric
|
||||
testImplementation rootProject.ext.robolectric
|
||||
testImplementation kotestAssertions
|
||||
|
||||
implementation archComponentsLifecycle
|
||||
|
||||
api rootProject.ext.androidxAnnotations
|
||||
api kotlinStd
|
||||
@@ -23,7 +27,7 @@ dependencies {
|
||||
lintPublish project(':conductor-lint')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor'
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
ext.artifactId = 'conductor'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
class Backstack implements Iterable<RouterTransaction> {
|
||||
|
||||
private static final String KEY_ENTRIES = "Backstack.entries";
|
||||
|
||||
private final Deque<RouterTransaction> backstack = new ArrayDeque<>();
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
boolean isEmpty() {
|
||||
return backstack.isEmpty();
|
||||
}
|
||||
|
||||
int size() {
|
||||
return backstack.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
RouterTransaction root() {
|
||||
return backstack.size() > 0 ? backstack.getLast() : null;
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
public Iterator<RouterTransaction> iterator() {
|
||||
return backstack.iterator();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Iterator<RouterTransaction> reverseIterator() {
|
||||
return backstack.descendingIterator();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
List<RouterTransaction> popTo(@NonNull RouterTransaction transaction) {
|
||||
List<RouterTransaction> popped = new ArrayList<>();
|
||||
if (backstack.contains(transaction)) {
|
||||
while (backstack.peek() != transaction) {
|
||||
RouterTransaction poppedTransaction = pop();
|
||||
popped.add(poppedTransaction);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Tried to pop to a transaction that was not on the back stack");
|
||||
}
|
||||
return popped;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
RouterTransaction pop() {
|
||||
RouterTransaction popped = backstack.pop();
|
||||
popped.controller().destroy();
|
||||
return popped;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
RouterTransaction peek() {
|
||||
return backstack.peek();
|
||||
}
|
||||
|
||||
void push(@NonNull RouterTransaction transaction) {
|
||||
backstack.push(transaction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
List<RouterTransaction> popAll() {
|
||||
List<RouterTransaction> list = new ArrayList<>();
|
||||
while (!isEmpty()) {
|
||||
list.add(pop());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void setBackstack(@NonNull List<RouterTransaction> backstack) {
|
||||
this.backstack.clear();
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
this.backstack.push(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
boolean contains(@NonNull Controller controller) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (controller == transaction.controller()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void saveInstanceState(@NonNull Bundle outState) {
|
||||
ArrayList<Bundle> entryBundles = new ArrayList<>(backstack.size());
|
||||
for (RouterTransaction entry : backstack) {
|
||||
entryBundles.add(entry.saveInstanceState());
|
||||
}
|
||||
|
||||
outState.putParcelableArrayList(KEY_ENTRIES, entryBundles);
|
||||
}
|
||||
|
||||
void restoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
ArrayList<Bundle> entryBundles = savedInstanceState.getParcelableArrayList(KEY_ENTRIES);
|
||||
if (entryBundles != null) {
|
||||
Collections.reverse(entryBundles);
|
||||
for (Bundle transactionBundle : entryBundles) {
|
||||
backstack.push(new RouterTransaction(transactionBundle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import android.os.Bundle
|
||||
import java.util.*
|
||||
|
||||
internal class Backstack : Iterable<RouterTransaction> {
|
||||
|
||||
private val backstack: Deque<RouterTransaction> = ArrayDeque()
|
||||
|
||||
val isEmpty: Boolean get() = backstack.isEmpty()
|
||||
|
||||
val size: Int get() = backstack.size
|
||||
|
||||
fun root(): RouterTransaction? = backstack.lastOrNull()
|
||||
|
||||
override fun iterator(): MutableIterator<RouterTransaction> {
|
||||
return backstack.iterator()
|
||||
}
|
||||
|
||||
fun reverseIterator(): Iterator<RouterTransaction> = backstack.descendingIterator()
|
||||
|
||||
fun popTo(transaction: RouterTransaction): List<RouterTransaction> {
|
||||
if (transaction in backstack) {
|
||||
val popped: MutableList<RouterTransaction> = ArrayList()
|
||||
while (backstack.peek() != transaction) {
|
||||
val poppedTransaction = pop()
|
||||
popped.add(poppedTransaction)
|
||||
}
|
||||
return popped
|
||||
} else {
|
||||
throw RuntimeException("Tried to pop to a transaction that was not on the back stack")
|
||||
}
|
||||
}
|
||||
|
||||
fun pop(): RouterTransaction {
|
||||
return backstack.pop().also {
|
||||
it.controller.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
fun peek(): RouterTransaction? = backstack.peek()
|
||||
|
||||
fun push(transaction: RouterTransaction) {
|
||||
backstack.push(transaction)
|
||||
}
|
||||
|
||||
fun popAll(): List<RouterTransaction> {
|
||||
val list: MutableList<RouterTransaction> = ArrayList()
|
||||
while (!isEmpty) {
|
||||
list.add(pop())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
fun setBackstack(backstack: List<RouterTransaction>) {
|
||||
this.backstack.clear()
|
||||
backstack.forEach { transaction ->
|
||||
this.backstack.push(transaction)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun contains(controller: Controller): Boolean {
|
||||
return backstack.any {
|
||||
it.controller == controller
|
||||
}
|
||||
}
|
||||
|
||||
fun saveInstanceState(outState: Bundle) {
|
||||
val entryBundles = ArrayList<Bundle>(backstack.size)
|
||||
backstack.mapTo(entryBundles) {
|
||||
it.saveInstanceState()
|
||||
}
|
||||
outState.putParcelableArrayList(KEY_ENTRIES, entryBundles)
|
||||
}
|
||||
|
||||
fun restoreInstanceState(savedInstanceState: Bundle) {
|
||||
val entryBundles = savedInstanceState.getParcelableArrayList<Bundle?>(KEY_ENTRIES)
|
||||
if (entryBundles != null) {
|
||||
entryBundles.reverse()
|
||||
for (transactionBundle in entryBundles) {
|
||||
backstack.push(RouterTransaction(transactionBundle!!))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_ENTRIES = "Backstack.entries"
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -23,6 +22,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.conductor.internal.ClassUtils;
|
||||
import com.bluelinelabs.conductor.internal.OwnViewTreeLifecycleAndRegistry;
|
||||
import com.bluelinelabs.conductor.internal.RouterRequiringFunc;
|
||||
import com.bluelinelabs.conductor.internal.ViewAttachHandler;
|
||||
import com.bluelinelabs.conductor.internal.ViewAttachHandler.ViewAttachListener;
|
||||
@@ -142,6 +142,7 @@ public abstract class Controller {
|
||||
this.args = args != null ? args : new Bundle(getClass().getClassLoader());
|
||||
instanceId = UUID.randomUUID().toString();
|
||||
ensureRequiredConstructor();
|
||||
OwnViewTreeLifecycleAndRegistry.Companion.own(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,6 +214,23 @@ public abstract class Controller {
|
||||
*/
|
||||
@Nullable
|
||||
public final Router getChildRouter(@NonNull ViewGroup container, @Nullable String tag, boolean createIfNeeded) {
|
||||
return getChildRouter(container, tag, createIfNeeded, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child {@link Router} for the given container/tag combination. Note that multiple
|
||||
* routers should not exist in the same container unless a lot of care is taken to maintain order
|
||||
* between them. Avoid using the same container unless you have a great reason to do so (ex: ViewPagers).
|
||||
* The only time this method will return {@code null} is when the child router does not exist prior
|
||||
* to calling this method and the createIfNeeded parameter is set to false.
|
||||
*
|
||||
* @param container The ViewGroup that hosts the child Router
|
||||
* @param tag The router's tag or {@code null} if none is needed
|
||||
* @param createIfNeeded If true, a router will be created if one does not yet exist. Else {@code null} will be returned in this case.
|
||||
* @param boundToHostContainerId If true, a router will only ever rebind with a container with the same view id on state restoration. Note that this must be set to true if the tag is null.
|
||||
*/
|
||||
@Nullable
|
||||
public final Router getChildRouter(@NonNull ViewGroup container, @Nullable String tag, boolean createIfNeeded, boolean boundToHostContainerId) {
|
||||
@IdRes final int containerId = container.getId();
|
||||
if (containerId == View.NO_ID) {
|
||||
throw new IllegalStateException("You must set an id on your container.");
|
||||
@@ -220,7 +238,7 @@ public abstract class Controller {
|
||||
|
||||
ControllerHostedRouter childRouter = null;
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
if (router.getHostId() == containerId && TextUtils.equals(tag, router.getTag())) {
|
||||
if (router.matches(containerId, tag)) {
|
||||
childRouter = router;
|
||||
break;
|
||||
}
|
||||
@@ -228,7 +246,7 @@ public abstract class Controller {
|
||||
|
||||
if (childRouter == null) {
|
||||
if (createIfNeeded) {
|
||||
childRouter = new ControllerHostedRouter(container.getId(), tag);
|
||||
childRouter = new ControllerHostedRouter(container.getId(), tag, boundToHostContainerId);
|
||||
childRouter.setHostContainer(this, container);
|
||||
childRouters.add(childRouter);
|
||||
|
||||
@@ -854,6 +872,27 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
final void onContextUnavailable(@NonNull Context context) {
|
||||
if (isContextAvailable) {
|
||||
for (Router childRouter : childRouters) {
|
||||
childRouter.onContextUnavailable(context);
|
||||
}
|
||||
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preContextUnavailable(this, context);
|
||||
}
|
||||
|
||||
isContextAvailable = false;
|
||||
onContextUnavailable();
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postContextUnavailable(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void executeWithRouter(@NonNull RouterRequiringFunc listener) {
|
||||
if (router != null) {
|
||||
listener.execute();
|
||||
@@ -906,20 +945,7 @@ public abstract class Controller {
|
||||
destroy(true);
|
||||
}
|
||||
|
||||
if (isContextAvailable) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preContextUnavailable(this, activity);
|
||||
}
|
||||
|
||||
isContextAvailable = false;
|
||||
onContextUnavailable();
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postContextUnavailable(this);
|
||||
}
|
||||
}
|
||||
onContextUnavailable(activity);
|
||||
}
|
||||
|
||||
void attach(@NonNull View view) {
|
||||
@@ -1121,18 +1147,7 @@ public abstract class Controller {
|
||||
|
||||
private void performDestroy() {
|
||||
if (isContextAvailable) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preContextUnavailable(this, getActivity());
|
||||
}
|
||||
|
||||
isContextAvailable = false;
|
||||
onContextUnavailable();
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postContextUnavailable(this);
|
||||
}
|
||||
onContextUnavailable(getActivity());
|
||||
}
|
||||
|
||||
if (!destroyed) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.IntentSender.SendIntentException;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
@@ -22,18 +23,28 @@ class ControllerHostedRouter extends Router {
|
||||
|
||||
private final String KEY_HOST_ID = "ControllerHostedRouter.hostId";
|
||||
private final String KEY_TAG = "ControllerHostedRouter.tag";
|
||||
private final String KEY_BOUND_TO_CONTAINER = "ControllerHostedRouter.boundToContainer";
|
||||
|
||||
private Controller hostController;
|
||||
|
||||
@IdRes private int hostId;
|
||||
private String tag;
|
||||
private boolean isDetachFrozen;
|
||||
private boolean boundToContainer;
|
||||
|
||||
ControllerHostedRouter() { }
|
||||
|
||||
ControllerHostedRouter(int hostId, @Nullable String tag) {
|
||||
this(hostId, tag, false);
|
||||
}
|
||||
|
||||
ControllerHostedRouter(int hostId, @Nullable String tag, boolean boundToContainer) {
|
||||
if (!boundToContainer && tag == null) {
|
||||
throw new IllegalStateException("ControllerHostedRouter can't be created without a tag if not bounded to its container");
|
||||
}
|
||||
this.hostId = hostId;
|
||||
this.tag = tag;
|
||||
this.boundToContainer = boundToContainer;
|
||||
}
|
||||
|
||||
final void setHostController(@NonNull Controller controller) {
|
||||
@@ -213,6 +224,7 @@ class ControllerHostedRouter extends Router {
|
||||
super.saveInstanceState(outState);
|
||||
|
||||
outState.putInt(KEY_HOST_ID, hostId);
|
||||
outState.putBoolean(KEY_BOUND_TO_CONTAINER, boundToContainer);
|
||||
outState.putString(KEY_TAG, tag);
|
||||
}
|
||||
|
||||
@@ -221,6 +233,7 @@ class ControllerHostedRouter extends Router {
|
||||
super.restoreInstanceState(savedInstanceState);
|
||||
|
||||
hostId = savedInstanceState.getInt(KEY_HOST_ID);
|
||||
boundToContainer = savedInstanceState.getBoolean(KEY_BOUND_TO_CONTAINER);
|
||||
tag = savedInstanceState.getString(KEY_TAG);
|
||||
}
|
||||
|
||||
@@ -234,9 +247,18 @@ class ControllerHostedRouter extends Router {
|
||||
return hostId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getTag() {
|
||||
return tag;
|
||||
boolean matches(int hostId, @Nullable String tag) {
|
||||
if (!boundToContainer && container == null) {
|
||||
if (this.tag == null) {
|
||||
throw new IllegalStateException("Host ID can't be variable with a null tag");
|
||||
}
|
||||
if (this.tag.equals(tag)) {
|
||||
this.hostId = hostId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return this.hostId == hostId && TextUtils.equals(tag, this.tag);
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
@@ -280,7 +281,7 @@ public abstract class Router {
|
||||
public boolean popToRoot(@Nullable ControllerChangeHandler changeHandler) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
if (backstack.size() > 1) {
|
||||
if (backstack.getSize() > 1) {
|
||||
//noinspection ConstantConditions
|
||||
popToTransaction(backstack.root(), changeHandler);
|
||||
return true;
|
||||
@@ -375,7 +376,7 @@ public abstract class Router {
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public int getBackstackSize() {
|
||||
return backstack.size();
|
||||
return backstack.getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,7 +384,7 @@ public abstract class Router {
|
||||
*/
|
||||
@NonNull
|
||||
public List<RouterTransaction> getBackstack() {
|
||||
List<RouterTransaction> list = new ArrayList<>(backstack.size());
|
||||
List<RouterTransaction> list = new ArrayList<>(backstack.getSize());
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
while (backstackIterator.hasNext()) {
|
||||
list.add(backstackIterator.next());
|
||||
@@ -700,7 +701,7 @@ public abstract class Router {
|
||||
}
|
||||
|
||||
private void popToTransaction(@NonNull RouterTransaction transaction, @Nullable ControllerChangeHandler changeHandler) {
|
||||
if (backstack.size() > 0) {
|
||||
if (backstack.getSize() > 0) {
|
||||
RouterTransaction topTransaction = backstack.peek();
|
||||
|
||||
List<RouterTransaction> updatedBackstack = new ArrayList<>();
|
||||
@@ -745,9 +746,18 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
void onContextUnavailable(@NonNull Context context) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller().onContextUnavailable(context);
|
||||
}
|
||||
for (Controller controller : destroyingControllers) {
|
||||
controller.onContextUnavailable(context);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
final List<Controller> getControllers() {
|
||||
List<Controller> controllers = new ArrayList<>(backstack.size());
|
||||
List<Controller> controllers = new ArrayList<>(backstack.getSize());
|
||||
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
while (backstackIterator.hasNext()) {
|
||||
@@ -793,7 +803,7 @@ public abstract class Router {
|
||||
if (to != null) {
|
||||
to.ensureValidIndex(getTransactionIndexer());
|
||||
setRouterOnController(toController);
|
||||
} else if (backstack.size() == 0 && !popsLastView) {
|
||||
} else if (backstack.getSize() == 0 && !popsLastView) {
|
||||
// We're emptying out the backstack. Views get weird if you transition them out, so just no-op it. The host
|
||||
// Activity or controller should be handling this by finishing or at least hiding this view.
|
||||
changeHandler = new NoOpControllerChangeHandler();
|
||||
|
||||
@@ -24,7 +24,8 @@ private constructor(
|
||||
private var pushControllerChangeHandler: ControllerChangeHandler? = null,
|
||||
private var popControllerChangeHandler: ControllerChangeHandler? = null,
|
||||
private var attachedToRouter: Boolean = false,
|
||||
@RestrictTo(LIBRARY)
|
||||
@get:RestrictTo(LIBRARY)
|
||||
@set:RestrictTo(LIBRARY)
|
||||
var transactionIndex: Int = INVALID_INDEX
|
||||
) {
|
||||
|
||||
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
package com.bluelinelabs.conductor.internal
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LifecycleRegistry
|
||||
import androidx.lifecycle.ViewTreeLifecycleOwner
|
||||
import androidx.savedstate.SavedStateRegistryController
|
||||
import androidx.savedstate.SavedStateRegistryOwner
|
||||
import androidx.savedstate.ViewTreeSavedStateRegistryOwner
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.R
|
||||
|
||||
/**
|
||||
* This class sets the [ViewTreeLifecycleOwner] and [ViewTreeSavedStateRegistryOwner] which is
|
||||
* necessary for Jetpack Compose. By setting these, the view state restoration and compose lifecycle
|
||||
* play together with the lifecycle of the [Controller].
|
||||
*/
|
||||
internal class OwnViewTreeLifecycleAndRegistry private constructor(
|
||||
controller: Controller
|
||||
) : LifecycleOwner, SavedStateRegistryOwner {
|
||||
|
||||
private lateinit var lifecycleRegistry: LifecycleRegistry
|
||||
private lateinit var savedStateRegistryController: SavedStateRegistryController
|
||||
|
||||
private var hasSavedState = false
|
||||
private var savedRegistryState = Bundle.EMPTY
|
||||
|
||||
init {
|
||||
controller.addLifecycleListener(object : Controller.LifecycleListener() {
|
||||
override fun preCreateView(controller: Controller) {
|
||||
hasSavedState = false
|
||||
|
||||
lifecycleRegistry = LifecycleRegistry(this@OwnViewTreeLifecycleAndRegistry)
|
||||
savedStateRegistryController = SavedStateRegistryController.create(
|
||||
this@OwnViewTreeLifecycleAndRegistry
|
||||
)
|
||||
savedStateRegistryController.performRestore(savedRegistryState)
|
||||
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
|
||||
}
|
||||
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
/**
|
||||
* If the consumer of the library already has its own [ViewTreeLifecycleOwner] or
|
||||
* [ViewTreeSavedStateRegistryOwner] set, don't overwrite it but assume that they're doing
|
||||
* it on purpose.
|
||||
*/
|
||||
if (
|
||||
view.getTag(R.id.view_tree_lifecycle_owner) == null &&
|
||||
view.getTag(R.id.view_tree_saved_state_registry_owner) == null
|
||||
) {
|
||||
ViewTreeLifecycleOwner.set(view, this@OwnViewTreeLifecycleAndRegistry)
|
||||
ViewTreeSavedStateRegistryOwner.set(
|
||||
view,
|
||||
this@OwnViewTreeLifecycleAndRegistry
|
||||
)
|
||||
}
|
||||
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
|
||||
}
|
||||
|
||||
override fun postAttach(controller: Controller, view: View) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
}
|
||||
|
||||
override fun onChangeEnd(
|
||||
changeController: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
// Should only happen if pushing another controller over this one was aborted
|
||||
if (
|
||||
controller === changeController &&
|
||||
changeType.isEnter &&
|
||||
changeHandler.removesFromViewOnPush() &&
|
||||
changeController.view?.windowToken != null &&
|
||||
lifecycleRegistry.currentState == Lifecycle.State.STARTED
|
||||
) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
}
|
||||
}
|
||||
|
||||
// AbstractComposeView adds its own OnAttachStateChangeListener by default. Since it
|
||||
// does this on init, its detach callbacks get called before ours, which prevents us
|
||||
// from saving state in onDetach. The if statement in here should detect upcoming
|
||||
// detachment.
|
||||
override fun onChangeStart(
|
||||
changeController: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
if (
|
||||
controller === changeController &&
|
||||
!changeType.isEnter &&
|
||||
changeHandler.removesFromViewOnPush() &&
|
||||
changeController.view != null &&
|
||||
lifecycleRegistry.currentState == Lifecycle.State.RESUMED
|
||||
) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
|
||||
savedRegistryState = Bundle()
|
||||
savedStateRegistryController.performSave(savedRegistryState)
|
||||
|
||||
hasSavedState = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun preDetach(controller: Controller, view: View) {
|
||||
// Should only happen if pushing this controller was aborted
|
||||
if (lifecycleRegistry.currentState == Lifecycle.State.RESUMED) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
}
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(controller: Controller, outState: Bundle) {
|
||||
outState.putBundle(KEY_SAVED_STATE, savedRegistryState)
|
||||
}
|
||||
|
||||
override fun onSaveViewState(controller: Controller, outState: Bundle) {
|
||||
if (!hasSavedState) {
|
||||
savedRegistryState = Bundle()
|
||||
savedStateRegistryController.performSave(savedRegistryState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(controller: Controller, savedInstanceState: Bundle) {
|
||||
savedRegistryState = savedInstanceState.getBundle(KEY_SAVED_STATE)
|
||||
}
|
||||
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
if (controller.isBeingDestroyed && controller.router.backstackSize == 0) {
|
||||
val parent = view.parent as? View
|
||||
parent?.addOnAttachStateChangeListener(object :
|
||||
View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View?) = Unit
|
||||
override fun onViewDetachedFromWindow(v: View?) {
|
||||
parent.removeOnAttachStateChangeListener(this)
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun getLifecycle() = lifecycleRegistry
|
||||
|
||||
override fun getSavedStateRegistry() = savedStateRegistryController.savedStateRegistry
|
||||
|
||||
companion object {
|
||||
private const val KEY_SAVED_STATE = "Registry.savedState"
|
||||
|
||||
fun own(target: Controller) {
|
||||
OwnViewTreeLifecycleAndRegistry(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.SparseArray;
|
||||
|
||||
public class StringSparseArrayParceler implements Parcelable {
|
||||
|
||||
private final SparseArray<String> stringSparseArray;
|
||||
|
||||
public StringSparseArrayParceler(@NonNull SparseArray<String> stringSparseArray) {
|
||||
this.stringSparseArray = stringSparseArray;
|
||||
}
|
||||
|
||||
StringSparseArrayParceler(@NonNull Parcel in) {
|
||||
stringSparseArray = new SparseArray<>();
|
||||
|
||||
final int size = in.readInt();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
stringSparseArray.put(in.readInt(), in.readString());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SparseArray<String> getStringSparseArray() {
|
||||
return stringSparseArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
final int size = stringSparseArray.size();
|
||||
|
||||
out.writeInt(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = stringSparseArray.keyAt(i);
|
||||
|
||||
out.writeInt(key);
|
||||
out.writeString(stringSparseArray.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<StringSparseArrayParceler> CREATOR = new Parcelable.Creator<StringSparseArrayParceler>() {
|
||||
@Override
|
||||
public StringSparseArrayParceler createFromParcel(Parcel in) {
|
||||
return new StringSparseArrayParceler(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringSparseArrayParceler[] newArray(int size) {
|
||||
return new StringSparseArrayParceler[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.bluelinelabs.conductor.internal
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.util.SparseArray
|
||||
|
||||
internal class StringSparseArrayParceler(val stringSparseArray: SparseArray<String>) : Parcelable {
|
||||
|
||||
override fun describeContents(): Int = 0
|
||||
|
||||
override fun writeToParcel(out: Parcel, flags: Int) {
|
||||
val size = stringSparseArray.size()
|
||||
out.writeInt(size)
|
||||
for (i in 0 until size) {
|
||||
val key = stringSparseArray.keyAt(i)
|
||||
out.writeInt(key)
|
||||
out.writeString(stringSparseArray[key])
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@Suppress("unused")
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<StringSparseArrayParceler> =
|
||||
object : Parcelable.Creator<StringSparseArrayParceler> {
|
||||
override fun createFromParcel(parcel: Parcel): StringSparseArrayParceler {
|
||||
val stringSparseArray = SparseArray<String>()
|
||||
val size = parcel.readInt()
|
||||
for (i in 0 until size) {
|
||||
stringSparseArray.put(parcel.readInt(), parcel.readString())
|
||||
}
|
||||
return StringSparseArrayParceler(stringSparseArray)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<StringSparseArrayParceler?> = arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class BackstackTests {
|
||||
|
||||
private Backstack backstack;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
backstack = new Backstack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPush() {
|
||||
assertEquals(0, backstack.size());
|
||||
backstack.push(RouterTransaction.with(new TestController()));
|
||||
assertEquals(1, backstack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPop() {
|
||||
backstack.push(RouterTransaction.with(new TestController()));
|
||||
backstack.push(RouterTransaction.with(new TestController()));
|
||||
assertEquals(2, backstack.size());
|
||||
backstack.pop();
|
||||
assertEquals(1, backstack.size());
|
||||
backstack.pop();
|
||||
assertEquals(0, backstack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPeek() {
|
||||
RouterTransaction transaction1 = RouterTransaction.with(new TestController());
|
||||
RouterTransaction transaction2 = RouterTransaction.with(new TestController());
|
||||
|
||||
backstack.push(transaction1);
|
||||
assertEquals(transaction1, backstack.peek());
|
||||
|
||||
backstack.push(transaction2);
|
||||
assertEquals(transaction2, backstack.peek());
|
||||
|
||||
backstack.pop();
|
||||
assertEquals(transaction1, backstack.peek());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopTo() {
|
||||
RouterTransaction transaction1 = RouterTransaction.with(new TestController());
|
||||
RouterTransaction transaction2 = RouterTransaction.with(new TestController());
|
||||
RouterTransaction transaction3 = RouterTransaction.with(new TestController());
|
||||
|
||||
backstack.push(transaction1);
|
||||
backstack.push(transaction2);
|
||||
backstack.push(transaction3);
|
||||
|
||||
assertEquals(3, backstack.size());
|
||||
|
||||
backstack.popTo(transaction1);
|
||||
|
||||
assertEquals(1, backstack.size());
|
||||
assertEquals(transaction1, backstack.peek());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class BackstackTests {
|
||||
|
||||
private val backstack = Backstack()
|
||||
|
||||
@Test
|
||||
fun testPush() {
|
||||
assertEquals(0, backstack.size.toLong())
|
||||
backstack.push(TestController().asTransaction())
|
||||
assertEquals(1, backstack.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPop() {
|
||||
backstack.push(TestController().asTransaction())
|
||||
backstack.push(TestController().asTransaction())
|
||||
assertEquals(2, backstack.size.toLong())
|
||||
|
||||
backstack.pop()
|
||||
assertEquals(1, backstack.size.toLong())
|
||||
|
||||
backstack.pop()
|
||||
assertEquals(0, backstack.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPeek() {
|
||||
val transaction1 = TestController().asTransaction()
|
||||
val transaction2 = TestController().asTransaction()
|
||||
|
||||
backstack.push(transaction1)
|
||||
assertEquals(transaction1, backstack.peek())
|
||||
|
||||
backstack.push(transaction2)
|
||||
assertEquals(transaction2, backstack.peek())
|
||||
|
||||
backstack.pop()
|
||||
assertEquals(transaction1, backstack.peek())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopTo() {
|
||||
val transaction1 = TestController().asTransaction()
|
||||
val transaction2 = TestController().asTransaction()
|
||||
val transaction3 = TestController().asTransaction()
|
||||
|
||||
backstack.push(transaction1)
|
||||
backstack.push(transaction2)
|
||||
backstack.push(transaction3)
|
||||
assertEquals(3, backstack.size.toLong())
|
||||
|
||||
backstack.popTo(transaction1)
|
||||
assertEquals(1, backstack.size.toLong())
|
||||
assertEquals(transaction1, backstack.peek())
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package com.bluelinelabs.conductor;
|
||||
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
-270
@@ -1,270 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ControllerLifecycleActivityReferenceTests {
|
||||
|
||||
private Router router;
|
||||
|
||||
private ActivityProxy activityProxy;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState, boolean includeStartAndResume) {
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState);
|
||||
|
||||
if (includeStartAndResume) {
|
||||
activityProxy.start().resume();
|
||||
}
|
||||
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
router.setPopsLastView(true);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createActivityController(null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleControllerActivityOnPush() {
|
||||
Controller controller = new TestController();
|
||||
|
||||
assertNull(controller.getActivity());
|
||||
|
||||
ActivityReferencingLifecycleListener listener = new ActivityReferencingLifecycleListener();
|
||||
controller.addLifecycleListener(listener);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertEquals(Collections.singletonList(true), listener.changeEndReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postCreateViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postAttachReferences);
|
||||
assertEquals(Collections.emptyList(), listener.postDetachReferences);
|
||||
assertEquals(Collections.emptyList(), listener.postDestroyViewReferences);
|
||||
assertEquals(Collections.emptyList(), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildControllerActivityOnPush() {
|
||||
Controller parent = new TestController();
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
|
||||
assertNull(child.getActivity());
|
||||
|
||||
ActivityReferencingLifecycleListener listener = new ActivityReferencingLifecycleListener();
|
||||
child.addLifecycleListener(listener);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup) parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(child)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertEquals(Collections.singletonList(true), listener.changeEndReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postCreateViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postAttachReferences);
|
||||
assertEquals(Collections.emptyList(), listener.postDetachReferences);
|
||||
assertEquals(Collections.emptyList(), listener.postDestroyViewReferences);
|
||||
assertEquals(Collections.emptyList(), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleControllerActivityOnPop() {
|
||||
Controller controller = new TestController();
|
||||
|
||||
ActivityReferencingLifecycleListener listener = new ActivityReferencingLifecycleListener();
|
||||
controller.addLifecycleListener(listener);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertEquals(Arrays.asList(true, true), listener.changeEndReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postCreateViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postAttachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDetachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildControllerActivityOnPop() {
|
||||
Controller parent = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
|
||||
ActivityReferencingLifecycleListener listener = new ActivityReferencingLifecycleListener();
|
||||
child.addLifecycleListener(listener);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup) parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.pushController(RouterTransaction.with(child)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
childRouter.popCurrentController();
|
||||
|
||||
assertEquals(Arrays.asList(true, true), listener.changeEndReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postCreateViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postAttachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDetachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildControllerActivityOnParentPop() {
|
||||
Controller parent = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
|
||||
ActivityReferencingLifecycleListener listener = new ActivityReferencingLifecycleListener();
|
||||
child.addLifecycleListener(listener);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup) parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.pushController(RouterTransaction.with(child)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertEquals(Collections.singletonList(true), listener.changeEndReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postCreateViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postAttachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDetachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleControllerActivityOnDestroy() {
|
||||
Controller controller = new TestController();
|
||||
|
||||
ActivityReferencingLifecycleListener listener = new ActivityReferencingLifecycleListener();
|
||||
controller.addLifecycleListener(listener);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
activityProxy.pause().stop(false).destroy();
|
||||
|
||||
assertEquals(Collections.singletonList(true), listener.changeEndReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postCreateViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postAttachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDetachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildControllerActivityOnDestroy() {
|
||||
Controller parent = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
|
||||
ActivityReferencingLifecycleListener listener = new ActivityReferencingLifecycleListener();
|
||||
child.addLifecycleListener(listener);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup) parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.pushController(RouterTransaction.with(child)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
activityProxy.pause().stop(false).destroy();
|
||||
|
||||
assertEquals(Collections.singletonList(true), listener.changeEndReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postCreateViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postAttachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDetachReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyViewReferences);
|
||||
assertEquals(Collections.singletonList(true), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
static class ActivityReferencingLifecycleListener extends Controller.LifecycleListener {
|
||||
final List<Boolean> changeEndReferences = new ArrayList<>();
|
||||
final List<Boolean> postCreateViewReferences = new ArrayList<>();
|
||||
final List<Boolean> postAttachReferences = new ArrayList<>();
|
||||
final List<Boolean> postDetachReferences = new ArrayList<>();
|
||||
final List<Boolean> postDestroyViewReferences = new ArrayList<>();
|
||||
final List<Boolean> postDestroyReferences = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onChangeEnd(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
changeEndReferences.add(controller.getActivity() != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCreateView(@NonNull Controller controller, @NonNull View view) {
|
||||
postCreateViewReferences.add(controller.getActivity() != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
postAttachReferences.add(controller.getActivity() != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
postDetachReferences.add(controller.getActivity() != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroyView(@NonNull Controller controller) {
|
||||
postDestroyViewReferences.add(controller.getActivity() != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroy(@NonNull Controller controller) {
|
||||
postDestroyReferences.add(controller.getActivity() != null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import android.os.Looper.getMainLooper
|
||||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class ControllerLifecycleActivityReferenceTests {
|
||||
|
||||
private val activityController = Robolectric.buildActivity(TestActivity::class.java).setup()
|
||||
private val activity = activityController.get()
|
||||
|
||||
@Test
|
||||
fun testSingleControllerActivityOnPush() {
|
||||
val controller = TestController()
|
||||
Assert.assertNull(controller.activity)
|
||||
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
controller.addLifecycleListener(listener)
|
||||
|
||||
activity.router.pushController(
|
||||
controller.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
Assert.assertEquals(listOf(true), listener.changeEndReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postCreateViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postAttachReferences)
|
||||
Assert.assertEquals(emptyList<Any>(), listener.postDetachReferences)
|
||||
Assert.assertEquals(emptyList<Any>(), listener.postDestroyViewReferences)
|
||||
Assert.assertEquals(emptyList<Any>(), listener.postDestroyReferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildControllerActivityOnPush() {
|
||||
val parent = TestController()
|
||||
activity.router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
Assert.assertNull(child.activity)
|
||||
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
child.addLifecycleListener(listener)
|
||||
|
||||
val childRouter = parent.getChildRouter((parent.view!!.findViewById(TestController.VIEW_ID)))
|
||||
childRouter.pushController(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
Assert.assertEquals(listOf(true), listener.changeEndReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postCreateViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postAttachReferences)
|
||||
Assert.assertEquals(emptyList<Any>(), listener.postDetachReferences)
|
||||
Assert.assertEquals(emptyList<Any>(), listener.postDestroyViewReferences)
|
||||
Assert.assertEquals(emptyList<Any>(), listener.postDestroyReferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSingleControllerActivityOnPop() {
|
||||
val controller = TestController()
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
controller.addLifecycleListener(listener)
|
||||
|
||||
activity.router.pushController(
|
||||
controller.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
activity.router.popCurrentController()
|
||||
|
||||
Assert.assertEquals(listOf(true, true), listener.changeEndReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postCreateViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postAttachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDetachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyReferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildControllerActivityOnPop() {
|
||||
val parent = TestController()
|
||||
activity.router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
child.addLifecycleListener(listener)
|
||||
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.pushController(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
childRouter.popCurrentController()
|
||||
|
||||
shadowOf(getMainLooper()).idle()
|
||||
|
||||
Assert.assertEquals(listOf(true, true), listener.changeEndReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postCreateViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postAttachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDetachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyReferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildControllerActivityOnParentPop() {
|
||||
val parent = TestController()
|
||||
activity.router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
child.addLifecycleListener(listener)
|
||||
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.pushController(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
activity.router.popCurrentController()
|
||||
|
||||
Assert.assertEquals(listOf(true), listener.changeEndReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postCreateViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postAttachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDetachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyReferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSingleControllerActivityOnDestroy() {
|
||||
val controller = TestController()
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
controller.addLifecycleListener(listener)
|
||||
|
||||
activity.router.pushController(
|
||||
controller.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
activityController.pause().stop().destroy()
|
||||
|
||||
Assert.assertEquals(listOf(true), listener.changeEndReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postCreateViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postAttachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDetachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyReferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildControllerActivityOnDestroy() {
|
||||
val parent = TestController()
|
||||
activity.router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
child.addLifecycleListener(listener)
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.pushController(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
activityController.pause().stop().destroy()
|
||||
|
||||
Assert.assertEquals(listOf(true), listener.changeEndReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postCreateViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postAttachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDetachReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyViewReferences)
|
||||
Assert.assertEquals(listOf(true), listener.postDestroyReferences)
|
||||
}
|
||||
|
||||
internal class ActivityReferencingLifecycleListener : LifecycleListener() {
|
||||
val changeEndReferences = mutableListOf<Boolean>()
|
||||
val postCreateViewReferences = mutableListOf<Boolean>()
|
||||
val postAttachReferences = mutableListOf<Boolean>()
|
||||
val postDetachReferences = mutableListOf<Boolean>()
|
||||
val postDestroyViewReferences = mutableListOf<Boolean>()
|
||||
val postDestroyReferences = mutableListOf<Boolean>()
|
||||
|
||||
override fun onChangeEnd(
|
||||
controller: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
changeEndReferences.add(controller.activity != null)
|
||||
}
|
||||
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
postCreateViewReferences.add(controller.activity != null)
|
||||
}
|
||||
|
||||
override fun postAttach(controller: Controller, view: View) {
|
||||
postAttachReferences.add(controller.activity != null)
|
||||
}
|
||||
|
||||
override fun postDetach(controller: Controller, view: View) {
|
||||
postDetachReferences.add(controller.activity != null)
|
||||
}
|
||||
|
||||
override fun postDestroyView(controller: Controller) {
|
||||
postDestroyViewReferences.add(controller.activity != null)
|
||||
}
|
||||
|
||||
override fun postDestroy(controller: Controller) {
|
||||
postDestroyReferences.add(controller.activity != null)
|
||||
}
|
||||
}
|
||||
}
|
||||
-745
@@ -1,745 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
import com.bluelinelabs.conductor.Controller.RetainViewMode;
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.CallState;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler.ChangeHandlerListener;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
import com.bluelinelabs.conductor.util.ViewUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ControllerLifecycleCallbacksTests {
|
||||
|
||||
private Router router;
|
||||
|
||||
private ActivityProxy activityProxy;
|
||||
private CallState currentCallState;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState, boolean includeStartAndResume) {
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState);
|
||||
|
||||
if (includeStartAndResume) {
|
||||
activityProxy.start().resume();
|
||||
}
|
||||
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createActivityController(null, true);
|
||||
|
||||
currentCallState = new CallState(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalLifecycle() {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, controller))
|
||||
.popChangeHandler(getPopHandler(expectedCallState, controller)));
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertNull(controller.getView());
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleWithActivityStop() {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, controller)));
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.getActivity().isDestroying = true;
|
||||
activityProxy.pause();
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.stop(false);
|
||||
|
||||
expectedCallState.detachCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(controller.getView(), false);
|
||||
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleWithActivityDestroy() {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, controller)));
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.getActivity().isDestroying = true;
|
||||
activityProxy.pause();
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.stop(true);
|
||||
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.destroy();
|
||||
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleWithActivityConfigurationChange() {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, controller))
|
||||
.tag("root"));
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.getActivity().isChangingConfigurations = true;
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
activityProxy.saveInstanceState(bundle);
|
||||
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
expectedCallState.saveInstanceStateCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.pause();
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.stop(true);
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.destroy();
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
createActivityController(bundle, false);
|
||||
controller = (TestController)router.getControllerWithTag("root");
|
||||
|
||||
expectedCallState.contextAvailableCalls++;
|
||||
expectedCallState.restoreInstanceStateCalls++;
|
||||
expectedCallState.restoreViewStateCalls++;
|
||||
expectedCallState.changeStartCalls++;
|
||||
expectedCallState.createViewCalls++;
|
||||
|
||||
// Lifecycle listener isn't attached during restore, grab the current views from the controller for this stuff...
|
||||
currentCallState.restoreInstanceStateCalls = controller.currentCallState.restoreInstanceStateCalls;
|
||||
currentCallState.restoreViewStateCalls = controller.currentCallState.restoreViewStateCalls;
|
||||
currentCallState.changeStartCalls = controller.currentCallState.changeStartCalls;
|
||||
currentCallState.changeEndCalls = controller.currentCallState.changeEndCalls;
|
||||
currentCallState.createViewCalls = controller.currentCallState.createViewCalls;
|
||||
currentCallState.attachCalls = controller.currentCallState.attachCalls;
|
||||
currentCallState.contextAvailableCalls = controller.currentCallState.contextAvailableCalls;
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.start().resume();
|
||||
currentCallState.changeEndCalls = controller.currentCallState.changeEndCalls;
|
||||
currentCallState.attachCalls = controller.currentCallState.attachCalls;
|
||||
expectedCallState.changeEndCalls++;
|
||||
expectedCallState.attachCalls++;
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.resume();
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleWithActivityBackground() {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, controller)));
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.pause();
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
activityProxy.saveInstanceState(bundle);
|
||||
|
||||
expectedCallState.saveInstanceStateCalls++;
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.resume();
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleCallOrder() {
|
||||
final TestController testController = new TestController();
|
||||
final CallState callState = new CallState(false);
|
||||
|
||||
testController.addLifecycleListener(new LifecycleListener() {
|
||||
@Override
|
||||
public void preCreateView(@NonNull Controller controller) {
|
||||
callState.createViewCalls++;
|
||||
assertEquals(1, callState.createViewCalls);
|
||||
assertEquals(0, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(0, callState.attachCalls);
|
||||
assertEquals(0, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCreateView(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.createViewCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(0, callState.attachCalls);
|
||||
assertEquals(0, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.attachCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(1, callState.attachCalls);
|
||||
assertEquals(0, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.attachCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.detachCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(1, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.detachCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroyView(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.destroyViewCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(1, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroyView(@NonNull Controller controller) {
|
||||
callState.destroyViewCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
callState.destroyCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(1, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroy(@NonNull Controller controller) {
|
||||
callState.destroyCalls++;
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
assertEquals(2, callState.destroyCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
});
|
||||
|
||||
router.pushController(RouterTransaction.with(testController)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
router.popController(testController);
|
||||
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(2, callState.destroyCalls);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleWhenPopNonCurrentController() {
|
||||
String controller1Tag = "controller1";
|
||||
String controller2Tag = "controller2";
|
||||
String controller3Tag = "controller3";
|
||||
|
||||
TestController controller1 = new TestController();
|
||||
TestController controller2 = new TestController();
|
||||
TestController controller3 = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controller1)
|
||||
.tag(controller1Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.tag(controller2Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller3)
|
||||
.tag(controller3Tag));
|
||||
|
||||
router.popController(controller2);
|
||||
|
||||
assertEquals(1, controller2.currentCallState.attachCalls);
|
||||
assertEquals(1, controller2.currentCallState.createViewCalls);
|
||||
assertEquals(1, controller2.currentCallState.detachCalls);
|
||||
assertEquals(1, controller2.currentCallState.destroyViewCalls);
|
||||
assertEquals(1, controller2.currentCallState.destroyCalls);
|
||||
assertEquals(1, controller2.currentCallState.contextAvailableCalls);
|
||||
assertEquals(1, controller2.currentCallState.contextUnavailableCalls);
|
||||
assertEquals(1, controller2.currentCallState.saveViewStateCalls);
|
||||
assertEquals(0, controller2.currentCallState.restoreViewStateCalls);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildLifecycle() {
|
||||
Controller parent = new TestController();
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
attachLifecycleListener(child);
|
||||
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter
|
||||
.setRoot(RouterTransaction.with(child)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, child))
|
||||
.popChangeHandler(getPopHandler(expectedCallState, child)));
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
parent.removeChildRouter(childRouter);
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildLifecycle2() {
|
||||
Controller parent = new TestController();
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
attachLifecycleListener(child);
|
||||
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter
|
||||
.setRoot(RouterTransaction.with(child)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, child))
|
||||
.popChangeHandler(getPopHandler(expectedCallState, child)));
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildLifecycleOrderingAfterUnexpectedAttach() {
|
||||
Controller parent = new TestController();
|
||||
parent.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
child.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter
|
||||
.setRoot(RouterTransaction.with(child)
|
||||
.pushChangeHandler(new SimpleSwapChangeHandler())
|
||||
.popChangeHandler(new SimpleSwapChangeHandler()));
|
||||
|
||||
assertTrue(parent.isAttached());
|
||||
assertTrue(child.isAttached());
|
||||
|
||||
ViewUtils.reportAttached(parent.getView(), false, true);
|
||||
assertFalse(parent.isAttached());
|
||||
assertFalse(child.isAttached());
|
||||
|
||||
ViewUtils.reportAttached(child.getView(), true);
|
||||
assertFalse(parent.isAttached());
|
||||
assertFalse(child.isAttached());
|
||||
|
||||
ViewUtils.reportAttached(parent.getView(), true);
|
||||
assertTrue(parent.isAttached());
|
||||
assertTrue(child.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildLifecycleAfterPushAndPop() {
|
||||
Controller parent = new TestController();
|
||||
parent.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter
|
||||
.setRoot(RouterTransaction.with(child)
|
||||
.pushChangeHandler(new SimpleSwapChangeHandler())
|
||||
.popChangeHandler(new SimpleSwapChangeHandler()));
|
||||
|
||||
Controller nextController = new TestController();
|
||||
router.pushController(RouterTransaction.with(nextController));
|
||||
router.popCurrentController();
|
||||
|
||||
assertTrue(parent.isAttached());
|
||||
assertTrue(child.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildLifecycleAfterPushPopPush() {
|
||||
Controller parent = new TestController();
|
||||
parent.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter
|
||||
.setRoot(RouterTransaction.with(child)
|
||||
.pushChangeHandler(new SimpleSwapChangeHandler())
|
||||
.popChangeHandler(new SimpleSwapChangeHandler()));
|
||||
|
||||
Controller nextController = new TestController();
|
||||
router.pushController(RouterTransaction.with(nextController));
|
||||
|
||||
TestController child2 = new TestController();
|
||||
childRouter.pushController(RouterTransaction.with(child2));
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertTrue(parent.isAttached());
|
||||
assertFalse(child.isAttached());
|
||||
assertTrue(child2.isAttached());
|
||||
}
|
||||
|
||||
private MockChangeHandler getPushHandler(final CallState expectedCallState, final TestController controller) {
|
||||
return MockChangeHandler.listeningChangeHandler(new ChangeHandlerListener() {
|
||||
@Override
|
||||
public void willStartChange() {
|
||||
expectedCallState.contextAvailableCalls++;
|
||||
expectedCallState.changeStartCalls++;
|
||||
expectedCallState.createViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didAttachOrDetach() {
|
||||
expectedCallState.attachCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didEndChange() {
|
||||
expectedCallState.changeEndCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private MockChangeHandler getPopHandler(final CallState expectedCallState, final TestController controller) {
|
||||
return MockChangeHandler.listeningChangeHandler(new ChangeHandlerListener() {
|
||||
@Override
|
||||
public void willStartChange() {
|
||||
expectedCallState.changeStartCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didAttachOrDetach() {
|
||||
expectedCallState.destroyViewCalls++;
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didEndChange() {
|
||||
expectedCallState.changeEndCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void assertCalls(CallState callState, TestController controller) {
|
||||
assertEquals("Expected call counts and controller call counts do not match.", callState, controller.currentCallState);
|
||||
assertEquals("Expected call counts and lifecycle call counts do not match.", callState, currentCallState);
|
||||
}
|
||||
|
||||
private void attachLifecycleListener(Controller controller) {
|
||||
controller.addLifecycleListener(new LifecycleListener() {
|
||||
@Override
|
||||
public void onChangeStart(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
currentCallState.changeStartCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeEnd(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
currentCallState.changeEndCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postContextAvailable(@NonNull Controller controller, @NonNull Context context) {
|
||||
currentCallState.contextAvailableCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postContextUnavailable(@NonNull Controller controller) {
|
||||
currentCallState.contextUnavailableCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCreateView(@NonNull Controller controller, @NonNull View view) {
|
||||
currentCallState.createViewCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
currentCallState.attachCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroyView(@NonNull Controller controller) {
|
||||
currentCallState.destroyViewCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
currentCallState.detachCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroy(@NonNull Controller controller) {
|
||||
currentCallState.destroyCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Controller controller, @NonNull Bundle outState) {
|
||||
currentCallState.saveInstanceStateCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(@NonNull Controller controller, @NonNull Bundle savedInstanceState) {
|
||||
currentCallState.restoreInstanceStateCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveViewState(@NonNull Controller controller, @NonNull Bundle outState) {
|
||||
currentCallState.saveViewStateCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreViewState(@NonNull Controller controller, @NonNull Bundle savedViewState) {
|
||||
currentCallState.restoreViewStateCalls++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+702
@@ -0,0 +1,702 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Looper.getMainLooper
|
||||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener
|
||||
import com.bluelinelabs.conductor.Controller.RetainViewMode
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler
|
||||
import com.bluelinelabs.conductor.util.CallState
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler.ChangeHandlerListener
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import com.bluelinelabs.conductor.util.ViewUtils
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.android.controller.ActivityController
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class ControllerLifecycleCallbacksTests {
|
||||
|
||||
private lateinit var activityController: ActivityController<TestActivity>
|
||||
private lateinit var currentCallState: CallState
|
||||
|
||||
private fun createActivityController(savedInstanceState: Bundle?, includeStartAndResume: Boolean) {
|
||||
activityController = Robolectric.buildActivity(TestActivity::class.java)
|
||||
|
||||
activityController.create(savedInstanceState)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
activityController.restoreInstanceState(savedInstanceState)
|
||||
}
|
||||
|
||||
if (includeStartAndResume) {
|
||||
activityController
|
||||
.start()
|
||||
.postCreate(savedInstanceState)
|
||||
.resume()
|
||||
.visible()
|
||||
}
|
||||
|
||||
if (!activityController.get().router.hasRootController()) {
|
||||
activityController.get().router.setRoot(TestController().asTransaction())
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
createActivityController(null, true)
|
||||
currentCallState = CallState(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNormalLifecycle() {
|
||||
val controller = TestController()
|
||||
attachLifecycleListener(controller)
|
||||
val expectedCallState = CallState(false)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().router.pushController(
|
||||
controller.asTransaction(
|
||||
pushChangeHandler = getPushHandler(expectedCallState, controller),
|
||||
popChangeHandler = getPopHandler(expectedCallState, controller)
|
||||
)
|
||||
)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().router.popCurrentController()
|
||||
Assert.assertNull(controller.view)
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLifecycleWithActivityStop() {
|
||||
val controller = TestController()
|
||||
attachLifecycleListener(controller)
|
||||
val expectedCallState = CallState(false)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().router.pushController(
|
||||
controller.asTransaction(
|
||||
pushChangeHandler = getPushHandler(expectedCallState, controller)
|
||||
)
|
||||
)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().destroying = true
|
||||
activityController.pause()
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.stop()
|
||||
expectedCallState.detachCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
Assert.assertNotNull(controller.view)
|
||||
|
||||
ViewUtils.reportAttached(controller.view, false)
|
||||
expectedCallState.saveViewStateCalls++
|
||||
expectedCallState.destroyViewCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLifecycleWithActivityDestroy() {
|
||||
val controller = TestController()
|
||||
attachLifecycleListener(controller)
|
||||
val expectedCallState = CallState(false)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().router.pushController(
|
||||
controller.asTransaction(
|
||||
pushChangeHandler = getPushHandler(expectedCallState, controller)
|
||||
)
|
||||
)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().destroying = true
|
||||
activityController.pause()
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.stop()
|
||||
expectedCallState.detachCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.destroy()
|
||||
expectedCallState.destroyViewCalls++
|
||||
expectedCallState.contextUnavailableCalls++
|
||||
expectedCallState.destroyCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLifecycleWithActivityConfigurationChange() {
|
||||
var controller = TestController()
|
||||
attachLifecycleListener(controller)
|
||||
val expectedCallState = CallState(false)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().router.pushController(
|
||||
RouterTransaction.with(controller)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, controller))
|
||||
.tag("root")
|
||||
)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().changingConfigurations = true
|
||||
val bundle = Bundle()
|
||||
activityController.saveInstanceState(bundle)
|
||||
expectedCallState.saveViewStateCalls++
|
||||
expectedCallState.saveInstanceStateCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.pause()
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.stop()
|
||||
expectedCallState.detachCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.destroy()
|
||||
expectedCallState.destroyViewCalls++
|
||||
expectedCallState.contextUnavailableCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
createActivityController(bundle, false)
|
||||
controller = activityController.get().router.getControllerWithTag("root") as TestController
|
||||
expectedCallState.contextAvailableCalls++
|
||||
expectedCallState.restoreInstanceStateCalls++
|
||||
expectedCallState.restoreViewStateCalls++
|
||||
expectedCallState.changeStartCalls++
|
||||
expectedCallState.createViewCalls++
|
||||
|
||||
// Lifecycle listener isn't attached during restore, grab the current views from the controller for this stuff...
|
||||
currentCallState.restoreInstanceStateCalls = controller.currentCallState.restoreInstanceStateCalls
|
||||
currentCallState.restoreViewStateCalls = controller.currentCallState.restoreViewStateCalls
|
||||
currentCallState.changeStartCalls = controller.currentCallState.changeStartCalls
|
||||
currentCallState.changeEndCalls = controller.currentCallState.changeEndCalls
|
||||
currentCallState.createViewCalls = controller.currentCallState.createViewCalls
|
||||
currentCallState.attachCalls = controller.currentCallState.attachCalls
|
||||
currentCallState.contextAvailableCalls = controller.currentCallState.contextAvailableCalls
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController
|
||||
.start()
|
||||
.postCreate(bundle)
|
||||
.resume()
|
||||
.visible()
|
||||
|
||||
currentCallState.changeEndCalls = controller.currentCallState.changeEndCalls
|
||||
currentCallState.attachCalls = controller.currentCallState.attachCalls
|
||||
expectedCallState.changeEndCalls++
|
||||
expectedCallState.attachCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.resume()
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLifecycleWithActivityBackground() {
|
||||
val controller = TestController()
|
||||
attachLifecycleListener(controller)
|
||||
val expectedCallState = CallState(false)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.get().router.pushController(
|
||||
controller.asTransaction(
|
||||
pushChangeHandler = getPushHandler(expectedCallState, controller)
|
||||
)
|
||||
)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.pause()
|
||||
val bundle = Bundle()
|
||||
activityController.saveInstanceState(bundle)
|
||||
expectedCallState.saveInstanceStateCalls++
|
||||
expectedCallState.saveViewStateCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
activityController.resume()
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLifecycleCallOrder() {
|
||||
val testController = TestController()
|
||||
val callState = CallState(false)
|
||||
testController.addLifecycleListener(object : LifecycleListener() {
|
||||
override fun preCreateView(controller: Controller) {
|
||||
callState.createViewCalls++
|
||||
Assert.assertEquals(1, callState.createViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(0, callState.attachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(0, callState.detachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(0, callState.destroyViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
callState.createViewCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(0, callState.attachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(0, callState.detachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(0, callState.destroyViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun preAttach(controller: Controller, view: View) {
|
||||
callState.attachCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(1, callState.attachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(0, callState.detachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(0, callState.destroyViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun postAttach(controller: Controller, view: View) {
|
||||
callState.attachCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(0, callState.detachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(0, callState.destroyViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun preDetach(controller: Controller, view: View) {
|
||||
callState.detachCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(1, callState.detachCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(0, callState.destroyViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun postDetach(controller: Controller, view: View) {
|
||||
callState.detachCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(2, callState.detachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(0, callState.destroyViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
callState.destroyViewCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(2, callState.detachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(1, callState.destroyViewCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun postDestroyView(controller: Controller) {
|
||||
callState.destroyViewCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(2, callState.detachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(2, callState.destroyViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(0, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun preDestroy(controller: Controller) {
|
||||
callState.destroyCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(2, callState.detachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(2, callState.destroyViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(1, callState.destroyCalls)
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
|
||||
override fun postDestroy(controller: Controller) {
|
||||
callState.destroyCalls++
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls)
|
||||
Assert.assertEquals(2, callState.detachCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls)
|
||||
Assert.assertEquals(2, callState.destroyViewCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(2, callState.destroyCalls)
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyCalls)
|
||||
}
|
||||
})
|
||||
activityController.get().router.pushController(
|
||||
testController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
activityController.get().router.popController(testController)
|
||||
Assert.assertEquals(2, callState.createViewCalls)
|
||||
Assert.assertEquals(2, callState.attachCalls)
|
||||
Assert.assertEquals(2, callState.detachCalls)
|
||||
Assert.assertEquals(2, callState.destroyViewCalls)
|
||||
Assert.assertEquals(2, callState.destroyCalls)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLifecycleWhenPopNonCurrentController() {
|
||||
val controller1Tag = "controller1"
|
||||
val controller2Tag = "controller2"
|
||||
val controller3Tag = "controller3"
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
val controller3 = TestController()
|
||||
activityController.get().router.pushController(
|
||||
RouterTransaction.with(controller1).tag(controller1Tag)
|
||||
)
|
||||
activityController.get().router.pushController(
|
||||
RouterTransaction.with(controller2).tag(controller2Tag)
|
||||
)
|
||||
activityController.get().router.pushController(
|
||||
RouterTransaction.with(controller3).tag(controller3Tag)
|
||||
)
|
||||
activityController.get().router.popController(controller2)
|
||||
Assert.assertEquals(1, controller2.currentCallState.attachCalls)
|
||||
Assert.assertEquals(1, controller2.currentCallState.createViewCalls)
|
||||
Assert.assertEquals(1, controller2.currentCallState.detachCalls)
|
||||
Assert.assertEquals(1, controller2.currentCallState.destroyViewCalls)
|
||||
Assert.assertEquals(1, controller2.currentCallState.destroyCalls)
|
||||
Assert.assertEquals(1, controller2.currentCallState.contextAvailableCalls)
|
||||
Assert.assertEquals(1, controller2.currentCallState.contextUnavailableCalls)
|
||||
Assert.assertEquals(1, controller2.currentCallState.saveViewStateCalls)
|
||||
Assert.assertEquals(0, controller2.currentCallState.restoreViewStateCalls)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildLifecycle() {
|
||||
val parent = TestController()
|
||||
activityController.get().router.pushController(
|
||||
parent.asTransaction(pushChangeHandler = MockChangeHandler.defaultHandler())
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
attachLifecycleListener(child)
|
||||
val expectedCallState = CallState(false)
|
||||
assertCalls(expectedCallState, child)
|
||||
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setRoot(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = getPushHandler(expectedCallState, child),
|
||||
popChangeHandler = getPopHandler(expectedCallState, child)
|
||||
)
|
||||
)
|
||||
assertCalls(expectedCallState, child)
|
||||
|
||||
parent.removeChildRouter(childRouter)
|
||||
assertCalls(expectedCallState, child)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildLifecycle2() {
|
||||
val parent = TestController()
|
||||
activityController.get().router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
attachLifecycleListener(child)
|
||||
val expectedCallState = CallState(false)
|
||||
assertCalls(expectedCallState, child)
|
||||
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setRoot(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = getPushHandler(expectedCallState, child),
|
||||
popChangeHandler = getPopHandler(expectedCallState, child)
|
||||
)
|
||||
)
|
||||
assertCalls(expectedCallState, child)
|
||||
|
||||
activityController.get().router.popCurrentController()
|
||||
expectedCallState.detachCalls++
|
||||
expectedCallState.destroyViewCalls++
|
||||
expectedCallState.contextUnavailableCalls++
|
||||
expectedCallState.destroyCalls++
|
||||
assertCalls(expectedCallState, child)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildLifecycleOrderingAfterUnexpectedAttach() {
|
||||
val parent = TestController()
|
||||
parent.retainViewMode = RetainViewMode.RETAIN_DETACH
|
||||
activityController.get().router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
child.retainViewMode = RetainViewMode.RETAIN_DETACH
|
||||
val childRouter = parent.getChildRouter(parent.getView()!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setRoot(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = SimpleSwapChangeHandler(),
|
||||
popChangeHandler = SimpleSwapChangeHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertTrue(parent.isAttached)
|
||||
Assert.assertTrue(child.isAttached)
|
||||
|
||||
ViewUtils.reportAttached(parent.view, false, true)
|
||||
Assert.assertFalse(parent.isAttached)
|
||||
Assert.assertFalse(child.isAttached)
|
||||
|
||||
ViewUtils.reportAttached(child.view, true)
|
||||
Assert.assertFalse(parent.isAttached)
|
||||
Assert.assertFalse(child.isAttached)
|
||||
|
||||
ViewUtils.reportAttached(parent.view, true)
|
||||
Assert.assertTrue(parent.isAttached)
|
||||
Assert.assertTrue(child.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildLifecycleAfterPushAndPop() {
|
||||
val parent = TestController()
|
||||
parent.retainViewMode = RetainViewMode.RETAIN_DETACH
|
||||
activityController.get().router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setRoot(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = SimpleSwapChangeHandler(),
|
||||
popChangeHandler = SimpleSwapChangeHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val nextController = TestController()
|
||||
activityController.get().router.pushController(nextController.asTransaction())
|
||||
activityController.get().router.popCurrentController()
|
||||
|
||||
shadowOf(getMainLooper()).idle()
|
||||
|
||||
Assert.assertTrue(parent.isAttached)
|
||||
Assert.assertTrue(child.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildLifecycleAfterPushPopPush() {
|
||||
val parent = TestController()
|
||||
parent.retainViewMode = RetainViewMode.RETAIN_DETACH
|
||||
activityController.get().router.pushController(
|
||||
parent.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val child = TestController()
|
||||
val childRouter = parent.getChildRouter(parent.getView()!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setRoot(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = SimpleSwapChangeHandler(),
|
||||
popChangeHandler = SimpleSwapChangeHandler()
|
||||
)
|
||||
)
|
||||
|
||||
val nextController = TestController()
|
||||
activityController.get().router.pushController(nextController.asTransaction())
|
||||
|
||||
val child2 = TestController()
|
||||
childRouter.pushController(child2.asTransaction())
|
||||
activityController.get().router.popCurrentController()
|
||||
|
||||
shadowOf(getMainLooper()).idle()
|
||||
|
||||
Assert.assertTrue(parent.isAttached)
|
||||
Assert.assertFalse(child.isAttached)
|
||||
Assert.assertTrue(child2.isAttached)
|
||||
}
|
||||
|
||||
private fun getPushHandler(
|
||||
expectedCallState: CallState,
|
||||
controller: TestController
|
||||
): MockChangeHandler {
|
||||
return MockChangeHandler.listeningChangeHandler(object : ChangeHandlerListener() {
|
||||
override fun willStartChange() {
|
||||
expectedCallState.contextAvailableCalls++
|
||||
expectedCallState.changeStartCalls++
|
||||
expectedCallState.createViewCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
override fun didAttachOrDetach() {
|
||||
expectedCallState.attachCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
override fun didEndChange() {
|
||||
expectedCallState.changeEndCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getPopHandler(
|
||||
expectedCallState: CallState,
|
||||
controller: TestController
|
||||
): MockChangeHandler {
|
||||
return MockChangeHandler.listeningChangeHandler(object : ChangeHandlerListener() {
|
||||
override fun willStartChange() {
|
||||
expectedCallState.changeStartCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
override fun didAttachOrDetach() {
|
||||
expectedCallState.destroyViewCalls++
|
||||
expectedCallState.detachCalls++
|
||||
expectedCallState.contextUnavailableCalls++
|
||||
expectedCallState.destroyCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
override fun didEndChange() {
|
||||
expectedCallState.changeEndCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun assertCalls(callState: CallState, controller: TestController) {
|
||||
shadowOf(getMainLooper()).idle()
|
||||
|
||||
Assert.assertEquals(
|
||||
"Expected call counts and controller call counts do not match.",
|
||||
callState,
|
||||
controller.currentCallState
|
||||
)
|
||||
Assert.assertEquals(
|
||||
"Expected call counts and lifecycle call counts do not match.",
|
||||
callState,
|
||||
currentCallState
|
||||
)
|
||||
}
|
||||
|
||||
private fun attachLifecycleListener(controller: Controller?) {
|
||||
controller!!.addLifecycleListener(object : LifecycleListener() {
|
||||
override fun onChangeStart(
|
||||
controller: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
currentCallState.changeStartCalls++
|
||||
}
|
||||
|
||||
override fun onChangeEnd(
|
||||
controller: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
currentCallState.changeEndCalls++
|
||||
}
|
||||
|
||||
override fun postContextAvailable(controller: Controller, context: Context) {
|
||||
currentCallState.contextAvailableCalls++
|
||||
}
|
||||
|
||||
override fun postContextUnavailable(controller: Controller) {
|
||||
currentCallState.contextUnavailableCalls++
|
||||
}
|
||||
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
currentCallState.createViewCalls++
|
||||
}
|
||||
|
||||
override fun postAttach(controller: Controller, view: View) {
|
||||
currentCallState.attachCalls++
|
||||
}
|
||||
|
||||
override fun postDestroyView(controller: Controller) {
|
||||
currentCallState.destroyViewCalls++
|
||||
}
|
||||
|
||||
override fun postDetach(controller: Controller, view: View) {
|
||||
currentCallState.detachCalls++
|
||||
}
|
||||
|
||||
override fun postDestroy(controller: Controller) {
|
||||
currentCallState.destroyCalls++
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(controller: Controller, outState: Bundle) {
|
||||
currentCallState.saveInstanceStateCalls++
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(controller: Controller, savedInstanceState: Bundle) {
|
||||
currentCallState.restoreInstanceStateCalls++
|
||||
}
|
||||
|
||||
override fun onSaveViewState(controller: Controller, outState: Bundle) {
|
||||
currentCallState.saveViewStateCalls++
|
||||
}
|
||||
|
||||
override fun onRestoreViewState(controller: Controller, savedViewState: Bundle) {
|
||||
currentCallState.restoreViewStateCalls++
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,412 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller.RetainViewMode;
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.CallState;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
import com.bluelinelabs.conductor.util.ViewUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ControllerTests {
|
||||
|
||||
private ActivityProxy activityProxy;
|
||||
private Router router;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createActivityController(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testViewRetention() {
|
||||
Controller controller = new TestController();
|
||||
controller.setRouter(router);
|
||||
|
||||
// Test View getting released w/ RELEASE_DETACH
|
||||
controller.setRetainViewMode(RetainViewMode.RELEASE_DETACH);
|
||||
assertNull(controller.getView());
|
||||
View view = controller.inflate(router.container);
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertNull(controller.getView());
|
||||
|
||||
// Test View getting retained w/ RETAIN_DETACH
|
||||
controller.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
view = controller.inflate(router.container);
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
// Ensure re-setting RELEASE_DETACH releases
|
||||
controller.setRetainViewMode(RetainViewMode.RELEASE_DETACH);
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityResult() {
|
||||
TestController controller = new TestController();
|
||||
CallState expectedCallState = new CallState(true);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
// Ensure that calling onActivityResult w/o requesting a result doesn't do anything
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null);
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
// Ensure starting an activity for result gets us the result back
|
||||
controller.startActivityForResult(new Intent("action"), 1);
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null);
|
||||
expectedCallState.onActivityResultCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
// Ensure requesting a result w/o calling startActivityForResult works
|
||||
controller.registerForActivityResult(2);
|
||||
router.onActivityResult(2, Activity.RESULT_OK, null);
|
||||
expectedCallState.onActivityResultCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityResultForChild() {
|
||||
TestController parent = new TestController();
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
CallState parentExpectedCallState = new CallState(true);
|
||||
|
||||
// Ensure that calling onActivityResult w/o requesting a result doesn't do anything
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null);
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
|
||||
// Ensure starting an activity for result gets us the result back
|
||||
child.startActivityForResult(new Intent("action"), 1);
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null);
|
||||
childExpectedCallState.onActivityResultCalls++;
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
|
||||
// Ensure requesting a result w/o calling startActivityForResult works
|
||||
child.registerForActivityResult(2);
|
||||
router.onActivityResult(2, Activity.RESULT_OK, null);
|
||||
childExpectedCallState.onActivityResultCalls++;
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermissionResult() {
|
||||
final String[] requestedPermissions = new String[] {"test"};
|
||||
|
||||
TestController controller = new TestController();
|
||||
CallState expectedCallState = new CallState(true);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
// Ensure that calling handleRequestedPermission w/o requesting a result doesn't do anything
|
||||
router.onRequestPermissionsResult("anotherId", 1, requestedPermissions, new int[] {1});
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
// Ensure requesting the permission gets us the result back
|
||||
try {
|
||||
controller.requestPermissions(requestedPermissions, 1);
|
||||
} catch (NoSuchMethodError ignored) { }
|
||||
|
||||
router.onRequestPermissionsResult(controller.getInstanceId(), 1, requestedPermissions, new int[] {1});
|
||||
expectedCallState.onRequestPermissionsResultCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermissionResultForChild() {
|
||||
final String[] requestedPermissions = new String[] {"test"};
|
||||
|
||||
TestController parent = new TestController();
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
CallState parentExpectedCallState = new CallState(true);
|
||||
|
||||
// Ensure that calling handleRequestedPermission w/o requesting a result doesn't do anything
|
||||
router.onRequestPermissionsResult("anotherId", 1, requestedPermissions, new int[] {1});
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
|
||||
// Ensure requesting the permission gets us the result back
|
||||
try {
|
||||
child.requestPermissions(requestedPermissions, 1);
|
||||
} catch (NoSuchMethodError ignored) { }
|
||||
|
||||
router.onRequestPermissionsResult(child.getInstanceId(), 1, requestedPermissions, new int[] {1});
|
||||
childExpectedCallState.onRequestPermissionsResultCalls++;
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionsMenu() {
|
||||
TestController controller = new TestController();
|
||||
CallState expectedCallState = new CallState(true);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
// Ensure that calling onCreateOptionsMenu w/o declaring that we have one doesn't do anything
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
// Ensure calling onCreateOptionsMenu with a menu works
|
||||
controller.setHasOptionsMenu(true);
|
||||
|
||||
// Ensure it'll still get called back next time onCreateOptionsMenu is called
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
expectedCallState.createOptionsMenuCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
// Ensure we stop getting them when we hide it
|
||||
controller.setOptionsMenuHidden(true);
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
// Ensure we get the callback them when we un-hide it
|
||||
controller.setOptionsMenuHidden(false);
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
expectedCallState.createOptionsMenuCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
// Ensure we don't get the callback when we no longer have a menu
|
||||
controller.setHasOptionsMenu(false);
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionsMenuForChild() {
|
||||
TestController parent = new TestController();
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
CallState parentExpectedCallState = new CallState(true);
|
||||
|
||||
// Ensure that calling onCreateOptionsMenu w/o declaring that we have one doesn't do anything
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
|
||||
// Ensure calling onCreateOptionsMenu with a menu works
|
||||
child.setHasOptionsMenu(true);
|
||||
|
||||
// Ensure it'll still get called back next time onCreateOptionsMenu is called
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
childExpectedCallState.createOptionsMenuCalls++;
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
|
||||
// Ensure we stop getting them when we hide it
|
||||
child.setOptionsMenuHidden(true);
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
|
||||
// Ensure we get the callback them when we un-hide it
|
||||
child.setOptionsMenuHidden(false);
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
childExpectedCallState.createOptionsMenuCalls++;
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
|
||||
// Ensure we don't get the callback when we no longer have a menu
|
||||
child.setHasOptionsMenu(false);
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
assertCalls(childExpectedCallState, child);
|
||||
assertCalls(parentExpectedCallState, parent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveChildControllers() {
|
||||
TestController parent = new TestController();
|
||||
TestController child1 = new TestController();
|
||||
TestController child2 = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
|
||||
assertEquals(0, parent.getChildRouters().size());
|
||||
assertNull(child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.setRoot(RouterTransaction.with(child1));
|
||||
|
||||
assertEquals(1, parent.getChildRouters().size());
|
||||
assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
assertEquals(1, childRouter.getBackstackSize());
|
||||
assertEquals(child1, childRouter.getControllers().get(0));
|
||||
assertEquals(parent, child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
|
||||
childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(child2));
|
||||
|
||||
assertEquals(1, parent.getChildRouters().size());
|
||||
assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
assertEquals(2, childRouter.getBackstackSize());
|
||||
assertEquals(child1, childRouter.getControllers().get(0));
|
||||
assertEquals(child2, childRouter.getControllers().get(1));
|
||||
assertEquals(parent, child1.getParentController());
|
||||
assertEquals(parent, child2.getParentController());
|
||||
|
||||
childRouter.popController(child2);
|
||||
|
||||
assertEquals(1, parent.getChildRouters().size());
|
||||
assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
assertEquals(1, childRouter.getBackstackSize());
|
||||
assertEquals(child1, childRouter.getControllers().get(0));
|
||||
assertEquals(parent, child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
|
||||
childRouter.popController(child1);
|
||||
|
||||
assertEquals(1, parent.getChildRouters().size());
|
||||
assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
assertEquals(0, childRouter.getBackstackSize());
|
||||
assertNull(child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveChildRouters() {
|
||||
TestController parent = new TestController();
|
||||
|
||||
TestController child1 = new TestController();
|
||||
TestController child2 = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
|
||||
assertEquals(0, parent.getChildRouters().size());
|
||||
assertNull(child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
|
||||
Router childRouter1 = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.CHILD_VIEW_ID_1));
|
||||
Router childRouter2 = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.CHILD_VIEW_ID_2));
|
||||
|
||||
childRouter1.setRoot(RouterTransaction.with(child1));
|
||||
childRouter2.setRoot(RouterTransaction.with(child2));
|
||||
|
||||
assertEquals(2, parent.getChildRouters().size());
|
||||
assertEquals(childRouter1, parent.getChildRouters().get(0));
|
||||
assertEquals(childRouter2, parent.getChildRouters().get(1));
|
||||
assertEquals(1, childRouter1.getBackstackSize());
|
||||
assertEquals(1, childRouter2.getBackstackSize());
|
||||
assertEquals(child1, childRouter1.getControllers().get(0));
|
||||
assertEquals(child2, childRouter2.getControllers().get(0));
|
||||
assertEquals(parent, child1.getParentController());
|
||||
assertEquals(parent, child2.getParentController());
|
||||
|
||||
parent.removeChildRouter(childRouter2);
|
||||
|
||||
assertEquals(1, parent.getChildRouters().size());
|
||||
assertEquals(childRouter1, parent.getChildRouters().get(0));
|
||||
assertEquals(1, childRouter1.getBackstackSize());
|
||||
assertEquals(0, childRouter2.getBackstackSize());
|
||||
assertEquals(child1, childRouter1.getControllers().get(0));
|
||||
assertEquals(parent, child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
|
||||
parent.removeChildRouter(childRouter1);
|
||||
|
||||
assertEquals(0, parent.getChildRouters().size());
|
||||
assertEquals(0, childRouter1.getBackstackSize());
|
||||
assertEquals(0, childRouter2.getBackstackSize());
|
||||
assertNull(child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestoredChildRouterBackstack() {
|
||||
TestController parent = new TestController();
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
ViewUtils.reportAttached(parent.getView(), true);
|
||||
|
||||
RouterTransaction childTransaction1 = RouterTransaction.with(new TestController());
|
||||
RouterTransaction childTransaction2 = RouterTransaction.with(new TestController());
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.CHILD_VIEW_ID_1));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.setRoot(childTransaction1);
|
||||
childRouter.pushController(childTransaction2);
|
||||
|
||||
Bundle savedState = new Bundle();
|
||||
childRouter.saveInstanceState(savedState);
|
||||
parent.removeChildRouter(childRouter);
|
||||
|
||||
childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.CHILD_VIEW_ID_1));
|
||||
assertEquals(0, childRouter.getBackstackSize());
|
||||
|
||||
childRouter.restoreInstanceState(savedState);
|
||||
childRouter.rebindIfNeeded();
|
||||
|
||||
assertEquals(2, childRouter.getBackstackSize());
|
||||
|
||||
RouterTransaction restoredChildTransaction1 = childRouter.getBackstack().get(0);
|
||||
RouterTransaction restoredChildTransaction2 = childRouter.getBackstack().get(1);
|
||||
|
||||
assertEquals(childTransaction1.getTransactionIndex(), restoredChildTransaction1.getTransactionIndex());
|
||||
assertEquals(childTransaction1.controller().getInstanceId(), restoredChildTransaction1.controller().getInstanceId());
|
||||
assertEquals(childTransaction2.getTransactionIndex(), restoredChildTransaction2.getTransactionIndex());
|
||||
assertEquals(childTransaction2.controller().getInstanceId(), restoredChildTransaction2.controller().getInstanceId());
|
||||
|
||||
assertTrue(parent.handleBack());
|
||||
assertEquals(1, childRouter.getBackstackSize());
|
||||
assertEquals(restoredChildTransaction1, childRouter.getBackstack().get(0));
|
||||
|
||||
assertTrue(parent.handleBack());
|
||||
assertEquals(0, childRouter.getBackstackSize());
|
||||
}
|
||||
|
||||
private void assertCalls(CallState callState, TestController controller) {
|
||||
assertEquals("Expected call counts and controller call counts do not match.", callState, controller.currentCallState);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.SubMenu
|
||||
import com.bluelinelabs.conductor.Controller.RetainViewMode
|
||||
import com.bluelinelabs.conductor.util.AttachFakingFrameLayout
|
||||
import com.bluelinelabs.conductor.util.CallState
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import com.bluelinelabs.conductor.util.ViewUtils
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class ControllerTests {
|
||||
|
||||
private val router = Robolectric.buildActivity(TestActivity::class.java)
|
||||
.setup()
|
||||
.get()
|
||||
.router
|
||||
|
||||
@Test
|
||||
fun testViewRetention() {
|
||||
val controller = TestController()
|
||||
controller.setRouter(router)
|
||||
|
||||
// Test View getting released w/ RELEASE_DETACH
|
||||
controller.retainViewMode = RetainViewMode.RELEASE_DETACH
|
||||
Assert.assertNull(controller.getView())
|
||||
var view = controller.inflate(router.container)
|
||||
Assert.assertNotNull(controller.getView())
|
||||
ViewUtils.reportAttached(view, true)
|
||||
Assert.assertNotNull(controller.getView())
|
||||
ViewUtils.reportAttached(view, false)
|
||||
Assert.assertNull(controller.getView())
|
||||
|
||||
// Test View getting retained w/ RETAIN_DETACH
|
||||
controller.retainViewMode = RetainViewMode.RETAIN_DETACH
|
||||
view = controller.inflate(router.container)
|
||||
Assert.assertNotNull(controller.getView())
|
||||
ViewUtils.reportAttached(view, true)
|
||||
Assert.assertNotNull(controller.getView())
|
||||
ViewUtils.reportAttached(view, false)
|
||||
Assert.assertNotNull(controller.getView())
|
||||
|
||||
// Ensure re-setting RELEASE_DETACH releases
|
||||
controller.retainViewMode = RetainViewMode.RELEASE_DETACH
|
||||
Assert.assertNull(controller.getView())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testActivityResult() {
|
||||
val controller = TestController()
|
||||
val expectedCallState = CallState(true)
|
||||
router.pushController(controller.asTransaction())
|
||||
|
||||
// Ensure that calling onActivityResult w/o requesting a result doesn't do anything
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null)
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure starting an activity for result gets us the result back
|
||||
controller.startActivityForResult(Intent("action"), 1)
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null)
|
||||
expectedCallState.onActivityResultCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure requesting a result w/o calling startActivityForResult works
|
||||
controller.registerForActivityResult(2)
|
||||
router.onActivityResult(2, Activity.RESULT_OK, null)
|
||||
expectedCallState.onActivityResultCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testActivityResultForChild() {
|
||||
val parent = TestController()
|
||||
val child = TestController()
|
||||
router.pushController(parent.asTransaction())
|
||||
val childContainer = parent.view!!.findViewById<AttachFakingFrameLayout>(TestController.VIEW_ID)
|
||||
childContainer.setAttached(true)
|
||||
parent.getChildRouter(childContainer)
|
||||
.setRoot(child.asTransaction())
|
||||
val childExpectedCallState = CallState(true)
|
||||
val parentExpectedCallState = CallState(true)
|
||||
|
||||
// Ensure that calling onActivityResult w/o requesting a result doesn't do anything
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null)
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure starting an activity for result gets us the result back
|
||||
child.startActivityForResult(Intent("action"), 1)
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null)
|
||||
childExpectedCallState.onActivityResultCalls++
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure requesting a result w/o calling startActivityForResult works
|
||||
child.registerForActivityResult(2)
|
||||
router.onActivityResult(2, Activity.RESULT_OK, null)
|
||||
childExpectedCallState.onActivityResultCalls++
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPermissionResult() {
|
||||
val requestedPermissions = arrayOf("test")
|
||||
val controller = TestController()
|
||||
val expectedCallState = CallState(true)
|
||||
router.pushController(controller.asTransaction())
|
||||
|
||||
// Ensure that calling handleRequestedPermission w/o requesting a result doesn't do anything
|
||||
router.onRequestPermissionsResult("anotherId", 1, requestedPermissions, intArrayOf(1))
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure requesting the permission gets us the result back
|
||||
try {
|
||||
controller.requestPermissions(requestedPermissions, 1)
|
||||
} catch (ignored: NoSuchMethodError) { }
|
||||
|
||||
router.onRequestPermissionsResult(
|
||||
controller.instanceId,
|
||||
1,
|
||||
requestedPermissions,
|
||||
intArrayOf(1)
|
||||
)
|
||||
expectedCallState.onRequestPermissionsResultCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPermissionResultForChild() {
|
||||
val requestedPermissions = arrayOf("test")
|
||||
val parent = TestController()
|
||||
val child = TestController()
|
||||
router.pushController(parent.asTransaction())
|
||||
val childContainer = parent.view!!.findViewById<AttachFakingFrameLayout>(TestController.VIEW_ID)
|
||||
childContainer.setAttached(true)
|
||||
parent.getChildRouter(childContainer)
|
||||
.setRoot(child.asTransaction())
|
||||
val childExpectedCallState = CallState(true)
|
||||
val parentExpectedCallState = CallState(true)
|
||||
|
||||
// Ensure that calling handleRequestedPermission w/o requesting a result doesn't do anything
|
||||
router.onRequestPermissionsResult("anotherId", 1, requestedPermissions, intArrayOf(1))
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure requesting the permission gets us the result back
|
||||
try {
|
||||
child.requestPermissions(requestedPermissions, 1)
|
||||
} catch (ignored: NoSuchMethodError) { }
|
||||
|
||||
router.onRequestPermissionsResult(child.instanceId, 1, requestedPermissions, intArrayOf(1))
|
||||
childExpectedCallState.onRequestPermissionsResultCalls++
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOptionsMenu() {
|
||||
val controller = TestController()
|
||||
val expectedCallState = CallState(true)
|
||||
router.pushController(controller.asTransaction())
|
||||
|
||||
// Ensure that calling onCreateOptionsMenu w/o declaring that we have one doesn't do anything
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure calling onCreateOptionsMenu with a menu works
|
||||
controller.setHasOptionsMenu(true)
|
||||
expectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure it'll still get called back next time onCreateOptionsMenu is called
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
expectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure we stop getting them when we hide it
|
||||
controller.setOptionsMenuHidden(true)
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure we get the callback them when we un-hide it
|
||||
controller.setOptionsMenuHidden(false)
|
||||
expectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
expectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(expectedCallState, controller)
|
||||
|
||||
// Ensure we don't get the callback when we no longer have a menu
|
||||
controller.setHasOptionsMenu(false)
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
assertCalls(expectedCallState, controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOptionsMenuForChild() {
|
||||
val parent = TestController()
|
||||
val child = TestController()
|
||||
router.pushController(parent.asTransaction())
|
||||
val childContainer = parent.view!!.findViewById<AttachFakingFrameLayout>(TestController.VIEW_ID)
|
||||
childContainer.setAttached(true)
|
||||
parent.getChildRouter(childContainer)
|
||||
.setRoot(child.asTransaction())
|
||||
val childExpectedCallState = CallState(true)
|
||||
val parentExpectedCallState = CallState(true)
|
||||
|
||||
// Ensure that calling onCreateOptionsMenu w/o declaring that we have one doesn't do anything
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure calling onCreateOptionsMenu with a menu works
|
||||
child.setHasOptionsMenu(true)
|
||||
childExpectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure it'll still get called back next time onCreateOptionsMenu is called
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
childExpectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure we stop getting them when we hide it
|
||||
child.setOptionsMenuHidden(true)
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure we get the callback them when we un-hide it
|
||||
child.setOptionsMenuHidden(false)
|
||||
childExpectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
childExpectedCallState.createOptionsMenuCalls++
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
|
||||
// Ensure we don't get the callback when we no longer have a menu
|
||||
child.setHasOptionsMenu(false)
|
||||
router.onCreateOptionsMenu(menu(), menuInflater(router.activity!!))
|
||||
assertCalls(childExpectedCallState, child)
|
||||
assertCalls(parentExpectedCallState, parent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddRemoveChildControllers() {
|
||||
val parent = TestController()
|
||||
val child1 = TestController()
|
||||
val child2 = TestController()
|
||||
router.pushController(parent.asTransaction())
|
||||
Assert.assertEquals(0, parent.childRouters.size)
|
||||
Assert.assertNull(child1.parentController)
|
||||
Assert.assertNull(child2.parentController)
|
||||
|
||||
var childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setRoot(child1.asTransaction())
|
||||
Assert.assertEquals(1, parent.childRouters.size)
|
||||
Assert.assertEquals(childRouter, parent.childRouters[0])
|
||||
Assert.assertEquals(1, childRouter.backstackSize)
|
||||
Assert.assertEquals(child1, childRouter.controllers[0])
|
||||
Assert.assertEquals(parent, child1.parentController)
|
||||
Assert.assertNull(child2.parentController)
|
||||
|
||||
childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.pushController(child2.asTransaction())
|
||||
Assert.assertEquals(1, parent.childRouters.size)
|
||||
Assert.assertEquals(childRouter, parent.childRouters[0])
|
||||
Assert.assertEquals(2, childRouter.backstackSize)
|
||||
Assert.assertEquals(child1, childRouter.controllers[0])
|
||||
Assert.assertEquals(child2, childRouter.controllers[1])
|
||||
Assert.assertEquals(parent, child1.parentController)
|
||||
Assert.assertEquals(parent, child2.parentController)
|
||||
|
||||
childRouter.popController(child2)
|
||||
Assert.assertEquals(1, parent.childRouters.size)
|
||||
Assert.assertEquals(childRouter, parent.childRouters[0])
|
||||
Assert.assertEquals(1, childRouter.backstackSize)
|
||||
Assert.assertEquals(child1, childRouter.controllers[0])
|
||||
Assert.assertEquals(parent, child1.parentController)
|
||||
Assert.assertNull(child2.parentController)
|
||||
|
||||
childRouter.popController(child1)
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertEquals(1, parent.childRouters.size)
|
||||
Assert.assertEquals(childRouter, parent.childRouters[0])
|
||||
Assert.assertEquals(0, childRouter.backstackSize)
|
||||
Assert.assertNull(child1.parentController)
|
||||
Assert.assertNull(child2.parentController)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddRemoveChildRouters() {
|
||||
val parent = TestController()
|
||||
val child1 = TestController()
|
||||
val child2 = TestController()
|
||||
router.pushController(parent.asTransaction())
|
||||
Assert.assertEquals(0, parent.childRouters.size)
|
||||
Assert.assertNull(child1.parentController)
|
||||
Assert.assertNull(child2.parentController)
|
||||
|
||||
val childRouter1 = parent.getChildRouter(parent.view!!.findViewById(TestController.CHILD_VIEW_ID_1))
|
||||
val childRouter2 = parent.getChildRouter(parent.view!!.findViewById(TestController.CHILD_VIEW_ID_2))
|
||||
childRouter1.setRoot(child1.asTransaction())
|
||||
childRouter2.setRoot(child2.asTransaction())
|
||||
Assert.assertEquals(2, parent.childRouters.size)
|
||||
Assert.assertEquals(childRouter1, parent.childRouters[0])
|
||||
Assert.assertEquals(childRouter2, parent.childRouters[1])
|
||||
Assert.assertEquals(1, childRouter1.backstackSize)
|
||||
Assert.assertEquals(1, childRouter2.backstackSize)
|
||||
Assert.assertEquals(child1, childRouter1.controllers[0])
|
||||
Assert.assertEquals(child2, childRouter2.controllers[0])
|
||||
Assert.assertEquals(parent, child1.parentController)
|
||||
Assert.assertEquals(parent, child2.parentController)
|
||||
|
||||
parent.removeChildRouter(childRouter2)
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertEquals(1, parent.childRouters.size)
|
||||
Assert.assertEquals(childRouter1, parent.childRouters[0])
|
||||
Assert.assertEquals(1, childRouter1.backstackSize)
|
||||
Assert.assertEquals(0, childRouter2.backstackSize)
|
||||
Assert.assertEquals(child1, childRouter1.controllers[0])
|
||||
Assert.assertEquals(parent, child1.parentController)
|
||||
Assert.assertNull(child2.parentController)
|
||||
parent.removeChildRouter(childRouter1)
|
||||
Assert.assertEquals(0, parent.childRouters.size)
|
||||
Assert.assertEquals(0, childRouter1.backstackSize)
|
||||
Assert.assertEquals(0, childRouter2.backstackSize)
|
||||
Assert.assertNull(child1.parentController)
|
||||
Assert.assertNull(child2.parentController)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRestoredChildRouterBackstack() {
|
||||
val parent = TestController()
|
||||
router.pushController(parent.asTransaction())
|
||||
ViewUtils.reportAttached(parent.view, true)
|
||||
|
||||
val childTransaction1 = TestController().asTransaction()
|
||||
val childTransaction2 = TestController().asTransaction()
|
||||
var childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.CHILD_VIEW_ID_1))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setRoot(childTransaction1)
|
||||
childRouter.pushController(childTransaction2)
|
||||
val savedState = Bundle()
|
||||
childRouter.saveInstanceState(savedState)
|
||||
parent.removeChildRouter(childRouter)
|
||||
childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.CHILD_VIEW_ID_1))
|
||||
Assert.assertEquals(0, childRouter.backstackSize)
|
||||
|
||||
childRouter.restoreInstanceState(savedState)
|
||||
childRouter.rebindIfNeeded()
|
||||
Assert.assertEquals(2, childRouter.backstackSize)
|
||||
val restoredChildTransaction1 = childRouter.getBackstack()[0]
|
||||
val restoredChildTransaction2 = childRouter.getBackstack()[1]
|
||||
Assert.assertEquals(
|
||||
childTransaction1.transactionIndex,
|
||||
restoredChildTransaction1.transactionIndex
|
||||
)
|
||||
Assert.assertEquals(
|
||||
childTransaction1.controller.getInstanceId(),
|
||||
restoredChildTransaction1.controller.getInstanceId()
|
||||
)
|
||||
Assert.assertEquals(
|
||||
childTransaction2.transactionIndex,
|
||||
restoredChildTransaction2.transactionIndex
|
||||
)
|
||||
Assert.assertEquals(
|
||||
childTransaction2.controller.getInstanceId(),
|
||||
restoredChildTransaction2.controller.getInstanceId()
|
||||
)
|
||||
Assert.assertTrue(parent.handleBack())
|
||||
Assert.assertEquals(1, childRouter.backstackSize)
|
||||
Assert.assertEquals(restoredChildTransaction1, childRouter.getBackstack()[0])
|
||||
Assert.assertTrue(parent.handleBack())
|
||||
Assert.assertEquals(0, childRouter.backstackSize)
|
||||
}
|
||||
|
||||
private fun assertCalls(callState: CallState, controller: TestController) {
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
|
||||
Assert.assertEquals(
|
||||
"Expected call counts and controller call counts do not match.",
|
||||
callState,
|
||||
controller.currentCallState
|
||||
)
|
||||
}
|
||||
|
||||
private fun menu(): Menu {
|
||||
return object : Menu {
|
||||
override fun add(p0: CharSequence?): MenuItem {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun add(p0: Int): MenuItem {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun add(p0: Int, p1: Int, p2: Int, p3: CharSequence?): MenuItem {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun add(p0: Int, p1: Int, p2: Int, p3: Int): MenuItem {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun addSubMenu(p0: CharSequence?): SubMenu {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun addSubMenu(p0: Int): SubMenu {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun addSubMenu(p0: Int, p1: Int, p2: Int, p3: CharSequence?): SubMenu {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun addSubMenu(p0: Int, p1: Int, p2: Int, p3: Int): SubMenu {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun addIntentOptions(
|
||||
p0: Int,
|
||||
p1: Int,
|
||||
p2: Int,
|
||||
p3: ComponentName?,
|
||||
p4: Array<out Intent>?,
|
||||
p5: Intent?,
|
||||
p6: Int,
|
||||
p7: Array<out MenuItem>?
|
||||
): Int {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun removeItem(p0: Int) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun removeGroup(p0: Int) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun setGroupCheckable(p0: Int, p1: Boolean, p2: Boolean) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun setGroupVisible(p0: Int, p1: Boolean) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun setGroupEnabled(p0: Int, p1: Boolean) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun hasVisibleItems(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun findItem(p0: Int): MenuItem {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getItem(p0: Int): MenuItem {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun performShortcut(p0: Int, p1: KeyEvent?, p2: Int): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isShortcutKey(p0: Int, p1: KeyEvent?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun performIdentifierAction(p0: Int, p1: Int): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun setQwertyMode(p0: Boolean) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun menuInflater(context: Context): MenuInflater {
|
||||
return MenuInflater(context)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import android.os.Bundle;
|
||||
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -1,406 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.internal.LifecycleHandler;
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.AttachFakingFrameLayout;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ReattachCaseTests {
|
||||
|
||||
private ActivityProxy activityProxy;
|
||||
private Router router;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createActivityController(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeedsAttachingOnPauseAndOrientation() {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
sleepWakeDevice();
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildNeedsAttachOnPauseAndOrientation() {
|
||||
final Controller controllerA = new TestController();
|
||||
final Controller childController = new TestController();
|
||||
final Controller controllerB = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup) controllerA.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
sleepWakeDevice();
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
assertTrue(childController.getNeedsAttach());
|
||||
assertTrue(controllerB.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildHandleBackOnOrientation() {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
final TestController childController = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouter = controllerB.getChildRouter((ViewGroup)controllerB.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
}
|
||||
|
||||
// Attempt to test https://github.com/bluelinelabs/Conductor/issues/86#issuecomment-231381271
|
||||
@Test
|
||||
public void testReusedChildRouterHandleBackOnOrientation() {
|
||||
TestController controllerA = new TestController();
|
||||
TestController controllerB = new TestController();
|
||||
TestController childController = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouter = controllerB.getChildRouter((ViewGroup)controllerB.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
childController = new TestController();
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
childController = new TestController();
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
}
|
||||
|
||||
// Attempt to test https://github.com/bluelinelabs/Conductor/issues/367
|
||||
@Test
|
||||
public void testViewIsAttachedAfterStartedActivityIsRecreated() {
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
|
||||
router.setRoot(RouterTransaction.with(controller1));
|
||||
assertTrue(controller1.isAttached());
|
||||
|
||||
// Lock screen
|
||||
Bundle bundle = new Bundle();
|
||||
activityProxy.pause().saveInstanceState(bundle).stop(false);
|
||||
|
||||
// Push a 2nd controller, which will rotate the screen once it unlocked
|
||||
router.pushController(RouterTransaction.with(controller2));
|
||||
assertTrue(controller2.isAttached());
|
||||
assertTrue(controller2.getNeedsAttach());
|
||||
|
||||
// Unlock screen and rotate
|
||||
activityProxy.start();
|
||||
activityProxy.rotate();
|
||||
|
||||
assertTrue(controller2.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopMiddleControllerAttaches() {
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
Controller controller3 = new TestController();
|
||||
|
||||
router.setRoot(RouterTransaction.with(controller1));
|
||||
router.pushController(RouterTransaction.with(controller2));
|
||||
router.pushController(RouterTransaction.with(controller3));
|
||||
router.popController(controller2);
|
||||
|
||||
assertFalse(controller1.isAttached());
|
||||
assertFalse(controller2.isAttached());
|
||||
assertTrue(controller3.isAttached());
|
||||
|
||||
controller1 = new TestController();
|
||||
controller2 = new TestController();
|
||||
controller3 = new TestController();
|
||||
|
||||
router.setRoot(RouterTransaction.with(controller1));
|
||||
router.pushController(RouterTransaction.with(controller2));
|
||||
router.pushController(RouterTransaction.with(controller3).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler()));
|
||||
router.popController(controller2);
|
||||
|
||||
assertTrue(controller1.isAttached());
|
||||
assertFalse(controller2.isAttached());
|
||||
assertTrue(controller3.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPendingChanges() {
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
|
||||
ActivityProxy activityProxy = new ActivityProxy().create(null);
|
||||
AttachFakingFrameLayout container = new AttachFakingFrameLayout(activityProxy.getActivity());
|
||||
container.setNeedDelayPost(true); // to simulate calling posts after resume
|
||||
|
||||
activityProxy.setView(container);
|
||||
|
||||
Router router = Conductor.attachRouter(activityProxy.getActivity(), container, null);
|
||||
router.setRoot(RouterTransaction.with(controller1));
|
||||
router.pushController(RouterTransaction.with(controller2));
|
||||
|
||||
activityProxy.start().resume();
|
||||
container.setNeedDelayPost(false);
|
||||
|
||||
assertTrue(controller2.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPendingChangesAfterRotation() {
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
|
||||
// first activity
|
||||
ActivityProxy activityProxy = new ActivityProxy().create(null);
|
||||
AttachFakingFrameLayout container1 = new AttachFakingFrameLayout(activityProxy.getActivity());
|
||||
|
||||
container1.setNeedDelayPost(true); // delay forever as view will be removed
|
||||
activityProxy.setView(container1);
|
||||
|
||||
// first attachRouter: Conductor.attachRouter(activityProxy.getActivity(), container1, null)
|
||||
LifecycleHandler lifecycleHandler = LifecycleHandler.install(activityProxy.getActivity());
|
||||
Router router = lifecycleHandler.getRouter(container1, null);
|
||||
router.setRoot(RouterTransaction.with(controller1));
|
||||
|
||||
// setup controllers
|
||||
router.pushController(RouterTransaction.with(controller2));
|
||||
|
||||
// simulate setRequestedOrientation in activity onCreate
|
||||
activityProxy.start().resume();
|
||||
Bundle savedState = new Bundle();
|
||||
activityProxy.saveInstanceState(savedState).pause().stop(true);
|
||||
|
||||
// recreate activity and view
|
||||
activityProxy = new ActivityProxy().create(savedState);
|
||||
AttachFakingFrameLayout container2 = new AttachFakingFrameLayout(activityProxy.getActivity());
|
||||
activityProxy.setView(container2);
|
||||
|
||||
// second attach router with the same lifecycleHandler (do manually as Roboelectric recreates retained fragments)
|
||||
// Conductor.attachRouter(activityProxy.getActivity(), container2, savedState);
|
||||
router = lifecycleHandler.getRouter(container2, savedState);
|
||||
router.rebindIfNeeded();
|
||||
|
||||
activityProxy.start().resume();
|
||||
|
||||
assertTrue(controller2.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostAvailableDuringRotation() {
|
||||
final Controller controllerA = new TestController();
|
||||
final Controller childControllerA = new TestController();
|
||||
final Controller controllerB = new TestController();
|
||||
final Controller childControllerB = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouterA = controllerA.getChildRouter((ViewGroup) controllerA.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouterA.pushController(RouterTransaction.with(childControllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertNotNull(controllerA.getActivity());
|
||||
assertNotNull(childControllerA.getActivity());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouterB = controllerB.getChildRouter((ViewGroup) controllerB.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouterB.pushController(RouterTransaction.with(childControllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertNotNull(controllerA.getActivity());
|
||||
assertNotNull(childControllerA.getActivity());
|
||||
assertNotNull(controllerB.getActivity());
|
||||
assertNotNull(childControllerB.getActivity());
|
||||
|
||||
activityProxy.rotate();
|
||||
|
||||
assertNotNull(controllerA.getActivity());
|
||||
assertNotNull(childControllerA.getActivity());
|
||||
assertNotNull(controllerB.getActivity());
|
||||
assertNotNull(childControllerB.getActivity());
|
||||
|
||||
router.rebindIfNeeded();
|
||||
|
||||
assertNotNull(controllerA.getActivity());
|
||||
assertNotNull(childControllerA.getActivity());
|
||||
assertNotNull(controllerB.getActivity());
|
||||
assertNotNull(childControllerB.getActivity());
|
||||
}
|
||||
|
||||
private void sleepWakeDevice() {
|
||||
activityProxy.saveInstanceState(new Bundle()).pause();
|
||||
activityProxy.resume();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import com.bluelinelabs.conductor.Conductor.attachRouter
|
||||
import com.bluelinelabs.conductor.internal.LifecycleHandler
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy
|
||||
import com.bluelinelabs.conductor.util.AttachFakingFrameLayout
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class ReattachCaseTests {
|
||||
|
||||
private val activityController = Robolectric.buildActivity(TestActivity::class.java).setup()
|
||||
private val router = activityController.get().router
|
||||
|
||||
@Test
|
||||
fun testNeedsAttachingOnPauseAndOrientation() {
|
||||
val controllerA = TestController()
|
||||
val controllerB = TestController()
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
|
||||
sleepWakeDevice()
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
|
||||
router.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
|
||||
activityController.configurationChange()
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildNeedsAttachOnPauseAndOrientation() {
|
||||
val controllerA = TestController()
|
||||
val childController = TestController()
|
||||
val controllerB = TestController()
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
val childRouter = controllerA.getChildRouter(
|
||||
controllerA.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouter.pushController(
|
||||
childController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
|
||||
sleepWakeDevice()
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
|
||||
router.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
|
||||
activityController.configurationChange()
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
Assert.assertTrue(childController.needsAttach)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildHandleBackOnOrientation() {
|
||||
val controllerA = TestController()
|
||||
val controllerB = TestController()
|
||||
val childController = TestController()
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
|
||||
router.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
val childRouter = controllerB.getChildRouter(
|
||||
controllerB.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.pushController(
|
||||
childController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
|
||||
activityController.configurationChange()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
|
||||
router.handleBack()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
|
||||
router.handleBack()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
}
|
||||
|
||||
// Attempt to test https://github.com/bluelinelabs/Conductor/issues/86#issuecomment-231381271
|
||||
@Test
|
||||
fun testReusedChildRouterHandleBackOnOrientation() {
|
||||
val controllerA = TestController()
|
||||
val controllerB = TestController()
|
||||
var childController = TestController()
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
|
||||
router.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
val childRouter = controllerB.getChildRouter(
|
||||
controllerB.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.pushController(
|
||||
childController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
|
||||
router.handleBack()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
|
||||
childController = TestController()
|
||||
childRouter.pushController(
|
||||
childController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
|
||||
activityController.configurationChange()
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
|
||||
router.handleBack()
|
||||
childController = TestController()
|
||||
childRouter.pushController(
|
||||
childController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertTrue(childController.isAttached)
|
||||
|
||||
router.handleBack()
|
||||
Assert.assertFalse(controllerA.isAttached)
|
||||
Assert.assertTrue(controllerB.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
|
||||
router.handleBack()
|
||||
Assert.assertTrue(controllerA.isAttached)
|
||||
Assert.assertFalse(controllerB.isAttached)
|
||||
Assert.assertFalse(childController.isAttached)
|
||||
}
|
||||
|
||||
// Attempt to test https://github.com/bluelinelabs/Conductor/issues/367
|
||||
@Test
|
||||
fun testViewIsAttachedAfterStartedActivityIsRecreated() {
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
router.setRoot(controller1.asTransaction())
|
||||
Assert.assertTrue(controller1.isAttached)
|
||||
|
||||
// Lock screen
|
||||
val bundle = Bundle()
|
||||
activityController.pause().saveInstanceState(bundle).stop()
|
||||
|
||||
// Push a 2nd controller, which will rotate the screen once it unlocked
|
||||
router.pushController(controller2.asTransaction())
|
||||
Assert.assertTrue(controller2.isAttached)
|
||||
Assert.assertTrue(controller2.needsAttach)
|
||||
|
||||
// Unlock screen and rotate
|
||||
activityController.start()
|
||||
activityController.configurationChange()
|
||||
Assert.assertTrue(controller2.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopMiddleControllerAttaches() {
|
||||
var controller1 = TestController()
|
||||
var controller2 = TestController()
|
||||
var controller3 = TestController()
|
||||
router.setRoot(controller1.asTransaction())
|
||||
router.pushController(controller2.asTransaction())
|
||||
router.pushController(controller3.asTransaction())
|
||||
router.popController(controller2)
|
||||
Assert.assertFalse(controller1.isAttached)
|
||||
Assert.assertFalse(controller2.isAttached)
|
||||
Assert.assertTrue(controller3.isAttached)
|
||||
|
||||
controller1 = TestController()
|
||||
controller2 = TestController()
|
||||
controller3 = TestController()
|
||||
router.setRoot(controller1.asTransaction())
|
||||
router.pushController(controller2.asTransaction())
|
||||
router.pushController(
|
||||
controller3.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.noRemoveViewOnPushHandler()
|
||||
)
|
||||
)
|
||||
router.popController(controller2)
|
||||
Assert.assertTrue(controller1.isAttached())
|
||||
Assert.assertFalse(controller2.isAttached())
|
||||
Assert.assertTrue(controller3.isAttached())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPendingChanges() {
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
val activityProxy = ActivityProxy().create(null)
|
||||
val container = AttachFakingFrameLayout(activityProxy.activity)
|
||||
container.setNeedDelayPost(true) // to simulate calling posts after resume
|
||||
activityProxy.view = container
|
||||
val router = attachRouter(activityProxy.activity, container, null)
|
||||
router.setRoot(controller1.asTransaction())
|
||||
router.pushController(controller2.asTransaction())
|
||||
activityProxy.start().resume()
|
||||
container.setNeedDelayPost(false)
|
||||
Assert.assertTrue(controller2.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPendingChangesAfterRotation() {
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
|
||||
// first activity
|
||||
var activityProxy = ActivityProxy().create(null)
|
||||
val container1 = AttachFakingFrameLayout(activityProxy.activity)
|
||||
container1.setNeedDelayPost(true) // delay forever as view will be removed
|
||||
activityProxy.view = container1
|
||||
|
||||
// first attachRouter: Conductor.attachRouter(activityProxy.getActivity(), container1, null)
|
||||
val lifecycleHandler = LifecycleHandler.install(activityProxy.activity)
|
||||
var router = lifecycleHandler.getRouter(container1, null)
|
||||
router.setRoot(controller1.asTransaction())
|
||||
|
||||
// setup controllers
|
||||
router.pushController(controller2.asTransaction())
|
||||
|
||||
// simulate setRequestedOrientation in activity onCreate
|
||||
activityProxy.start().resume()
|
||||
val savedState = Bundle()
|
||||
activityProxy.saveInstanceState(savedState).pause().stop(true)
|
||||
|
||||
// recreate activity and view
|
||||
activityProxy = ActivityProxy().create(savedState)
|
||||
val container2 = AttachFakingFrameLayout(activityProxy.activity)
|
||||
activityProxy.view = container2
|
||||
|
||||
// second attach router with the same lifecycleHandler (do manually as robolectric recreates retained fragments)
|
||||
// Conductor.attachRouter(activityProxy.getActivity(), container2, savedState);
|
||||
router = lifecycleHandler.getRouter(container2, savedState)
|
||||
router.rebindIfNeeded()
|
||||
activityProxy.start().resume()
|
||||
Assert.assertTrue(controller2.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHostAvailableDuringRotation() {
|
||||
val controllerA = TestController()
|
||||
val childControllerA = TestController()
|
||||
val controllerB = TestController()
|
||||
val childControllerB = TestController()
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
val childRouterA = controllerA.getChildRouter(
|
||||
controllerA.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouterA.pushController(
|
||||
childControllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertNotNull(controllerA.activity)
|
||||
Assert.assertNotNull(childControllerA.activity)
|
||||
|
||||
router.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
val childRouterB = controllerB.getChildRouter(
|
||||
controllerB.view!!.findViewById(
|
||||
TestController.VIEW_ID
|
||||
)
|
||||
)
|
||||
childRouterB.pushController(
|
||||
childControllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertNotNull(controllerA.activity)
|
||||
Assert.assertNotNull(childControllerA.activity)
|
||||
Assert.assertNotNull(controllerB.activity)
|
||||
Assert.assertNotNull(childControllerB.activity)
|
||||
|
||||
activityController.configurationChange()
|
||||
Assert.assertNotNull(controllerA.activity)
|
||||
Assert.assertNotNull(childControllerA.activity)
|
||||
Assert.assertNotNull(controllerB.activity)
|
||||
Assert.assertNotNull(childControllerB.activity)
|
||||
}
|
||||
|
||||
private fun sleepWakeDevice() {
|
||||
activityController.saveInstanceState(Bundle()).pause()
|
||||
activityController.resume()
|
||||
}
|
||||
}
|
||||
@@ -1,354 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class RouterChangeHandlerTests {
|
||||
|
||||
private Router router;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ActivityProxy activityProxy = new ActivityProxy().create(null).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRootHandler() {
|
||||
MockChangeHandler handler = MockChangeHandler.taggedHandler("root", true);
|
||||
TestController rootController = new TestController();
|
||||
router.setRoot(RouterTransaction.with(rootController).pushChangeHandler(handler));
|
||||
|
||||
assertTrue(rootController.changeHandlerHistory.isValidHistory);
|
||||
assertNull(rootController.changeHandlerHistory.latestFromView());
|
||||
assertNotNull(rootController.changeHandlerHistory.latestToView());
|
||||
assertEquals(rootController.getView(), rootController.changeHandlerHistory.latestToView());
|
||||
assertTrue(rootController.changeHandlerHistory.latestIsPush());
|
||||
assertEquals(handler.tag, rootController.changeHandlerHistory.latestChangeHandler().tag);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushPopHandlers() {
|
||||
TestController rootController = new TestController();
|
||||
router.setRoot(RouterTransaction.with(rootController).pushChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
View rootView = rootController.getView();
|
||||
|
||||
MockChangeHandler pushHandler = MockChangeHandler.taggedHandler("push", true);
|
||||
MockChangeHandler popHandler = MockChangeHandler.taggedHandler("pop", true);
|
||||
TestController pushController = new TestController();
|
||||
router.pushController(RouterTransaction.with(pushController).pushChangeHandler(pushHandler).popChangeHandler(popHandler));
|
||||
|
||||
assertTrue(rootController.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(pushController.changeHandlerHistory.isValidHistory);
|
||||
|
||||
assertNotNull(pushController.changeHandlerHistory.latestFromView());
|
||||
assertNotNull(pushController.changeHandlerHistory.latestToView());
|
||||
assertEquals(rootView, pushController.changeHandlerHistory.latestFromView());
|
||||
assertEquals(pushController.getView(), pushController.changeHandlerHistory.latestToView());
|
||||
assertTrue(pushController.changeHandlerHistory.latestIsPush());
|
||||
assertEquals(pushHandler.tag, pushController.changeHandlerHistory.latestChangeHandler().tag);
|
||||
|
||||
View pushView = pushController.getView();
|
||||
router.popController(pushController);
|
||||
|
||||
assertNotNull(pushController.changeHandlerHistory.latestFromView());
|
||||
assertNotNull(pushController.changeHandlerHistory.latestToView());
|
||||
assertEquals(pushView, pushController.changeHandlerHistory.fromViewAt(1));
|
||||
assertEquals(rootController.getView(), pushController.changeHandlerHistory.latestToView());
|
||||
assertFalse(pushController.changeHandlerHistory.latestIsPush());
|
||||
assertEquals(popHandler.tag, pushController.changeHandlerHistory.latestChangeHandler().tag);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResetRootHandlers() {
|
||||
TestController initialController1 = new TestController();
|
||||
MockChangeHandler initialPushHandler1 = MockChangeHandler.taggedHandler("initialPush1", true);
|
||||
MockChangeHandler initialPopHandler1 = MockChangeHandler.taggedHandler("initialPop1", true);
|
||||
router.setRoot(RouterTransaction.with(initialController1).pushChangeHandler(initialPushHandler1).popChangeHandler(initialPopHandler1));
|
||||
TestController initialController2 = new TestController();
|
||||
MockChangeHandler initialPushHandler2 = MockChangeHandler.taggedHandler("initialPush2", false);
|
||||
MockChangeHandler initialPopHandler2 = MockChangeHandler.taggedHandler("initialPop2", false);
|
||||
router.pushController(RouterTransaction.with(initialController2).pushChangeHandler(initialPushHandler2).popChangeHandler(initialPopHandler2));
|
||||
|
||||
View initialView1 = initialController1.getView();
|
||||
View initialView2 = initialController2.getView();
|
||||
|
||||
TestController newRootController = new TestController();
|
||||
MockChangeHandler newRootHandler = MockChangeHandler.taggedHandler("newRootHandler", true);
|
||||
|
||||
router.setRoot(RouterTransaction.with(newRootController).pushChangeHandler(newRootHandler));
|
||||
|
||||
assertTrue(initialController1.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(initialController2.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(newRootController.changeHandlerHistory.isValidHistory);
|
||||
|
||||
assertEquals(3, initialController1.changeHandlerHistory.size());
|
||||
assertEquals(2, initialController2.changeHandlerHistory.size());
|
||||
assertEquals(1, newRootController.changeHandlerHistory.size());
|
||||
|
||||
assertNotNull(initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(newRootController.getView(), initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView());
|
||||
assertEquals(newRootHandler.tag, initialController1.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController1.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNull(initialController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(newRootHandler.tag, initialController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController2.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNotNull(newRootController.changeHandlerHistory.latestToView());
|
||||
assertEquals(newRootController.getView(), newRootController.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView1, newRootController.changeHandlerHistory.latestFromView());
|
||||
assertEquals(newRootHandler.tag, newRootController.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(newRootController.changeHandlerHistory.latestIsPush());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBackstackHandlers() {
|
||||
TestController initialController1 = new TestController();
|
||||
MockChangeHandler initialPushHandler1 = MockChangeHandler.taggedHandler("initialPush1", true);
|
||||
MockChangeHandler initialPopHandler1 = MockChangeHandler.taggedHandler("initialPop1", true);
|
||||
router.setRoot(RouterTransaction.with(initialController1).pushChangeHandler(initialPushHandler1).popChangeHandler(initialPopHandler1));
|
||||
TestController initialController2 = new TestController();
|
||||
MockChangeHandler initialPushHandler2 = MockChangeHandler.taggedHandler("initialPush2", false);
|
||||
MockChangeHandler initialPopHandler2 = MockChangeHandler.taggedHandler("initialPop2", false);
|
||||
router.pushController(RouterTransaction.with(initialController2).pushChangeHandler(initialPushHandler2).popChangeHandler(initialPopHandler2));
|
||||
|
||||
View initialView1 = initialController1.getView();
|
||||
View initialView2 = initialController2.getView();
|
||||
|
||||
TestController newController1 = new TestController();
|
||||
TestController newController2 = new TestController();
|
||||
MockChangeHandler setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true);
|
||||
|
||||
List<RouterTransaction> newBackstack = Arrays.asList(
|
||||
RouterTransaction.with(newController1),
|
||||
RouterTransaction.with(newController2)
|
||||
);
|
||||
|
||||
router.setBackstack(newBackstack, setBackstackHandler);
|
||||
|
||||
assertTrue(initialController1.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(initialController2.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(newController1.changeHandlerHistory.isValidHistory);
|
||||
|
||||
assertEquals(3, initialController1.changeHandlerHistory.size());
|
||||
assertEquals(2, initialController2.changeHandlerHistory.size());
|
||||
assertEquals(0, newController1.changeHandlerHistory.size());
|
||||
assertEquals(1, newController2.changeHandlerHistory.size());
|
||||
|
||||
assertNotNull(initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController2.getView(), initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController1.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController1.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNull(initialController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController2.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNotNull(newController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController2.getView(), newController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView1, newController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, newController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(newController2.changeHandlerHistory.latestIsPush());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBackstackWithTwoVisibleHandlers() {
|
||||
TestController initialController1 = new TestController();
|
||||
MockChangeHandler initialPushHandler1 = MockChangeHandler.taggedHandler("initialPush1", true);
|
||||
MockChangeHandler initialPopHandler1 = MockChangeHandler.taggedHandler("initialPop1", true);
|
||||
router.setRoot(RouterTransaction.with(initialController1).pushChangeHandler(initialPushHandler1).popChangeHandler(initialPopHandler1));
|
||||
TestController initialController2 = new TestController();
|
||||
MockChangeHandler initialPushHandler2 = MockChangeHandler.taggedHandler("initialPush2", false);
|
||||
MockChangeHandler initialPopHandler2 = MockChangeHandler.taggedHandler("initialPop2", false);
|
||||
router.pushController(RouterTransaction.with(initialController2).pushChangeHandler(initialPushHandler2).popChangeHandler(initialPopHandler2));
|
||||
|
||||
View initialView1 = initialController1.getView();
|
||||
View initialView2 = initialController2.getView();
|
||||
|
||||
TestController newController1 = new TestController();
|
||||
TestController newController2 = new TestController();
|
||||
MockChangeHandler setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true);
|
||||
MockChangeHandler pushController2Handler = MockChangeHandler.noRemoveViewOnPushHandler("pushController2");
|
||||
List<RouterTransaction> newBackstack = Arrays.asList(
|
||||
RouterTransaction.with(newController1),
|
||||
RouterTransaction.with(newController2).pushChangeHandler(pushController2Handler)
|
||||
);
|
||||
|
||||
router.setBackstack(newBackstack, setBackstackHandler);
|
||||
|
||||
assertTrue(initialController1.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(initialController2.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(newController1.changeHandlerHistory.isValidHistory);
|
||||
|
||||
assertEquals(3, initialController1.changeHandlerHistory.size());
|
||||
assertEquals(2, initialController2.changeHandlerHistory.size());
|
||||
assertEquals(2, newController1.changeHandlerHistory.size());
|
||||
assertEquals(1, newController2.changeHandlerHistory.size());
|
||||
|
||||
assertNotNull(initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController1.getView(), initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController1.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController1.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNull(initialController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController2.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNotNull(newController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController1.getView(), newController1.changeHandlerHistory.toViewAt(0));
|
||||
assertEquals(newController2.getView(), newController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView1, newController1.changeHandlerHistory.fromViewAt(0));
|
||||
assertEquals(newController1.getView(), newController1.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, newController1.changeHandlerHistory.changeHandlerAt(0).tag);
|
||||
assertEquals(pushController2Handler.tag, newController1.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(newController1.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNotNull(newController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController2.getView(), newController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController1.getView(), newController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(pushController2Handler.tag, newController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(newController2.changeHandlerHistory.latestIsPush());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBackstackForPushHandlers() {
|
||||
TestController initialController = new TestController();
|
||||
MockChangeHandler initialPushHandler = MockChangeHandler.taggedHandler("initialPush1", true);
|
||||
MockChangeHandler initialPopHandler = MockChangeHandler.taggedHandler("initialPop1", true);
|
||||
RouterTransaction initialTransaction = RouterTransaction.with(initialController).pushChangeHandler(initialPushHandler).popChangeHandler(initialPopHandler);
|
||||
router.setRoot(initialTransaction);
|
||||
View initialView = initialController.getView();
|
||||
|
||||
TestController newController = new TestController();
|
||||
MockChangeHandler setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true);
|
||||
|
||||
List<RouterTransaction> newBackstack = Arrays.asList(
|
||||
initialTransaction,
|
||||
RouterTransaction.with(newController)
|
||||
);
|
||||
|
||||
router.setBackstack(newBackstack, setBackstackHandler);
|
||||
|
||||
assertTrue(initialController.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(newController.changeHandlerHistory.isValidHistory);
|
||||
|
||||
assertEquals(2, initialController.changeHandlerHistory.size());
|
||||
assertEquals(1, newController.changeHandlerHistory.size());
|
||||
|
||||
assertNotNull(initialController.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController.getView(), initialController.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView, initialController.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController.changeHandlerHistory.latestIsPush());
|
||||
assertTrue(newController.changeHandlerHistory.latestIsPush());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBackstackForInvertHandlersWithRemovesView() {
|
||||
TestController initialController1 = new TestController();
|
||||
MockChangeHandler initialPushHandler1 = MockChangeHandler.taggedHandler("initialPush1", true);
|
||||
MockChangeHandler initialPopHandler1 = MockChangeHandler.taggedHandler("initialPop1", true);
|
||||
RouterTransaction initialTransaction1 = RouterTransaction.with(initialController1).pushChangeHandler(initialPushHandler1).popChangeHandler(initialPopHandler1);
|
||||
router.setRoot(initialTransaction1);
|
||||
TestController initialController2 = new TestController();
|
||||
MockChangeHandler initialPushHandler2 = MockChangeHandler.taggedHandler("initialPush2", true);
|
||||
MockChangeHandler initialPopHandler2 = MockChangeHandler.taggedHandler("initialPop2", true);
|
||||
RouterTransaction initialTransaction2 = RouterTransaction.with(initialController2).pushChangeHandler(initialPushHandler2).popChangeHandler(initialPopHandler2);
|
||||
router.pushController(initialTransaction2);
|
||||
|
||||
View initialView2 = initialController2.getView();
|
||||
|
||||
MockChangeHandler setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true);
|
||||
List<RouterTransaction> newBackstack = Arrays.asList(
|
||||
initialTransaction2,
|
||||
initialTransaction1
|
||||
);
|
||||
|
||||
router.setBackstack(newBackstack, setBackstackHandler);
|
||||
|
||||
assertTrue(initialController1.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(initialController2.changeHandlerHistory.isValidHistory);
|
||||
|
||||
assertEquals(3, initialController1.changeHandlerHistory.size());
|
||||
assertEquals(2, initialController2.changeHandlerHistory.size());
|
||||
|
||||
assertNotNull(initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView2, initialController1.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController1.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertFalse(initialController1.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNotNull(initialController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertFalse(initialController2.changeHandlerHistory.latestIsPush());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBackstackForInvertHandlersWithoutRemovesView() {
|
||||
TestController initialController1 = new TestController();
|
||||
MockChangeHandler initialPushHandler1 = MockChangeHandler.taggedHandler("initialPush1", true);
|
||||
MockChangeHandler initialPopHandler1 = MockChangeHandler.taggedHandler("initialPop1", true);
|
||||
RouterTransaction initialTransaction1 = RouterTransaction.with(initialController1).pushChangeHandler(initialPushHandler1).popChangeHandler(initialPopHandler1);
|
||||
router.setRoot(initialTransaction1);
|
||||
TestController initialController2 = new TestController();
|
||||
MockChangeHandler initialPushHandler2 = MockChangeHandler.taggedHandler("initialPush2", false);
|
||||
MockChangeHandler initialPopHandler2 = MockChangeHandler.taggedHandler("initialPop2", false);
|
||||
RouterTransaction initialTransaction2 = RouterTransaction.with(initialController2).pushChangeHandler(initialPushHandler2).popChangeHandler(initialPopHandler2);
|
||||
router.pushController(initialTransaction2);
|
||||
|
||||
View initialView1 = initialController1.getView();
|
||||
View initialView2 = initialController2.getView();
|
||||
|
||||
MockChangeHandler setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true);
|
||||
List<RouterTransaction> newBackstack = Arrays.asList(
|
||||
initialTransaction2,
|
||||
initialTransaction1
|
||||
);
|
||||
|
||||
router.setBackstack(newBackstack, setBackstackHandler);
|
||||
|
||||
assertTrue(initialController1.changeHandlerHistory.isValidHistory);
|
||||
assertTrue(initialController2.changeHandlerHistory.isValidHistory);
|
||||
|
||||
assertEquals(2, initialController1.changeHandlerHistory.size());
|
||||
assertEquals(2, initialController2.changeHandlerHistory.size());
|
||||
|
||||
assertNotNull(initialController1.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView());
|
||||
assertEquals(initialPushHandler2.tag, initialController1.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(initialController1.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNull(initialController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, initialController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertFalse(initialController2.changeHandlerHistory.latestIsPush());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class RouterChangeHandlerTests {
|
||||
|
||||
private val router = Robolectric.buildActivity(TestActivity::class.java)
|
||||
.setup()
|
||||
.get()
|
||||
.router
|
||||
|
||||
@Test
|
||||
fun testSetRootHandler() {
|
||||
val handler = MockChangeHandler.taggedHandler("root", true)
|
||||
val rootController = TestController()
|
||||
router.setRoot(
|
||||
rootController.asTransaction(pushChangeHandler = handler)
|
||||
)
|
||||
|
||||
Assert.assertTrue(rootController.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertNull(rootController.changeHandlerHistory.latestFromView())
|
||||
Assert.assertNotNull(rootController.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
rootController.view,
|
||||
rootController.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertTrue(rootController.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertEquals(handler.tag, rootController.changeHandlerHistory.latestChangeHandler().tag)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPushPopHandlers() {
|
||||
val rootController = TestController()
|
||||
router.setRoot(
|
||||
rootController.asTransaction(pushChangeHandler = MockChangeHandler.defaultHandler())
|
||||
)
|
||||
|
||||
val rootView = rootController.view
|
||||
val pushHandler = MockChangeHandler.taggedHandler("push", true)
|
||||
val popHandler = MockChangeHandler.taggedHandler("pop", true)
|
||||
val pushController = TestController()
|
||||
router.pushController(
|
||||
pushController.asTransaction(
|
||||
pushChangeHandler = pushHandler,
|
||||
popChangeHandler = popHandler
|
||||
)
|
||||
)
|
||||
|
||||
Assert.assertTrue(rootController.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(pushController.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertNotNull(pushController.changeHandlerHistory.latestFromView())
|
||||
Assert.assertNotNull(pushController.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(rootView, pushController.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
pushController.view,
|
||||
pushController.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertTrue(pushController.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertEquals(
|
||||
pushHandler.tag,
|
||||
pushController.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
|
||||
val pushView = pushController.view
|
||||
router.popController(pushController)
|
||||
Assert.assertNotNull(pushController.changeHandlerHistory.latestFromView())
|
||||
Assert.assertNotNull(pushController.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(pushView, pushController.changeHandlerHistory.fromViewAt(1))
|
||||
Assert.assertEquals(
|
||||
rootController.view,
|
||||
pushController.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertFalse(pushController.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertEquals(
|
||||
popHandler.tag,
|
||||
pushController.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResetRootHandlers() {
|
||||
val initialController1 = TestController()
|
||||
router.setRoot(
|
||||
initialController1.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush1", true),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop1", true)
|
||||
)
|
||||
)
|
||||
|
||||
val initialController2 = TestController()
|
||||
router.pushController(
|
||||
initialController2.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush2", false),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop2", false)
|
||||
)
|
||||
)
|
||||
|
||||
val initialView1 = initialController1.view
|
||||
val initialView2 = initialController2.view
|
||||
val newRootController = TestController()
|
||||
val newRootHandlerTag = "newRootHandler"
|
||||
router.setRoot(
|
||||
newRootController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler(newRootHandlerTag, true)
|
||||
)
|
||||
)
|
||||
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(newRootController.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertEquals(3, initialController1.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(2, initialController2.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(1, newRootController.changeHandlerHistory.size().toLong())
|
||||
Assert.assertNotNull(initialController1.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
newRootController.view,
|
||||
initialController1.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
newRootHandlerTag,
|
||||
initialController1.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNull(initialController2.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
newRootHandlerTag,
|
||||
initialController2.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNotNull(newRootController.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
newRootController.view,
|
||||
newRootController.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(initialView1, newRootController.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
newRootHandlerTag,
|
||||
newRootController.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(newRootController.changeHandlerHistory.latestIsPush())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBackstackHandlers() {
|
||||
val initialController1 = TestController()
|
||||
router.setRoot(
|
||||
initialController1.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush1", true),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop1", true)
|
||||
)
|
||||
)
|
||||
|
||||
val initialController2 = TestController()
|
||||
router.pushController(
|
||||
initialController2.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush2", false),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop2", false)
|
||||
)
|
||||
)
|
||||
|
||||
val initialView1 = initialController1.view
|
||||
val initialView2 = initialController2.view
|
||||
val newController1 = TestController()
|
||||
val newController2 = TestController()
|
||||
val setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true)
|
||||
val newBackstack = listOf(newController1.asTransaction(), newController2.asTransaction())
|
||||
router.setBackstack(newBackstack, setBackstackHandler)
|
||||
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(newController1.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertEquals(3, initialController1.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(2, initialController2.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(0, newController1.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(1, newController2.changeHandlerHistory.size().toLong())
|
||||
Assert.assertNotNull(initialController1.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
newController2.view,
|
||||
initialController1.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController1.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNull(initialController2.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController2.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNotNull(newController2.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
newController2.view,
|
||||
newController2.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(initialView1, newController2.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
newController2.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(newController2.changeHandlerHistory.latestIsPush())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBackstackWithTwoVisibleHandlers() {
|
||||
val initialController1 = TestController()
|
||||
router.setRoot(
|
||||
initialController1.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush1", true),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop1", true)
|
||||
)
|
||||
)
|
||||
|
||||
val initialController2 = TestController()
|
||||
router.pushController(
|
||||
initialController2.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush2", false),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop2", false)
|
||||
)
|
||||
)
|
||||
|
||||
val initialView1 = initialController1.view
|
||||
val initialView2 = initialController2.view
|
||||
val newController1 = TestController()
|
||||
val newController2 = TestController()
|
||||
val setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true)
|
||||
val pushController2Handler = MockChangeHandler.noRemoveViewOnPushHandler("pushController2")
|
||||
val newBackstack = listOf(
|
||||
newController1.asTransaction(),
|
||||
newController2.asTransaction(pushChangeHandler = pushController2Handler)
|
||||
)
|
||||
router.setBackstack(newBackstack, setBackstackHandler)
|
||||
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(newController1.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertEquals(3, initialController1.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(2, initialController2.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(2, newController1.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(1, newController2.changeHandlerHistory.size().toLong())
|
||||
Assert.assertNotNull(initialController1.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
newController1.view,
|
||||
initialController1.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController1.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNull(initialController2.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController2.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNotNull(newController1.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(newController1.view, newController1.changeHandlerHistory.toViewAt(0))
|
||||
Assert.assertEquals(
|
||||
newController2.view,
|
||||
newController1.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(initialView1, newController1.changeHandlerHistory.fromViewAt(0))
|
||||
Assert.assertEquals(
|
||||
newController1.view,
|
||||
newController1.changeHandlerHistory.latestFromView()
|
||||
)
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
newController1.changeHandlerHistory.changeHandlerAt(0).tag
|
||||
)
|
||||
Assert.assertEquals(
|
||||
pushController2Handler.tag,
|
||||
newController1.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(newController1.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNotNull(newController2.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
newController2.view,
|
||||
newController2.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(
|
||||
newController1.view,
|
||||
newController2.changeHandlerHistory.latestFromView()
|
||||
)
|
||||
Assert.assertEquals(
|
||||
pushController2Handler.tag,
|
||||
newController2.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(newController2.changeHandlerHistory.latestIsPush())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBackstackForPushHandlers() {
|
||||
val initialController = TestController()
|
||||
val initialTransaction = initialController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush1", true),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop1", true)
|
||||
)
|
||||
router.setRoot(initialTransaction)
|
||||
|
||||
val initialView = initialController.view
|
||||
val newController = TestController()
|
||||
val setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true)
|
||||
val newBackstack = listOf(initialTransaction, newController.asTransaction())
|
||||
router.setBackstack(newBackstack, setBackstackHandler)
|
||||
|
||||
Assert.assertTrue(initialController.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(newController.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertEquals(2, initialController.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(1, newController.changeHandlerHistory.size().toLong())
|
||||
Assert.assertNotNull(initialController.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(
|
||||
newController.view,
|
||||
initialController.changeHandlerHistory.latestToView()
|
||||
)
|
||||
Assert.assertEquals(initialView, initialController.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertTrue(newController.changeHandlerHistory.latestIsPush())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBackstackForInvertHandlersWithRemovesView() {
|
||||
val initialController1 = TestController()
|
||||
val initialTransaction1 = initialController1.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush1", true),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop1", true)
|
||||
)
|
||||
router.setRoot(initialTransaction1)
|
||||
|
||||
val initialController2 = TestController()
|
||||
val initialTransaction2 = initialController2.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush2", true),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop2", true)
|
||||
)
|
||||
router.pushController(initialTransaction2)
|
||||
|
||||
val initialView2 = initialController2.view
|
||||
val setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true)
|
||||
val newBackstack = listOf(initialTransaction2, initialTransaction1)
|
||||
router.setBackstack(newBackstack, setBackstackHandler)
|
||||
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertEquals(3, initialController1.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(2, initialController2.changeHandlerHistory.size().toLong())
|
||||
Assert.assertNotNull(initialController1.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(initialView2, initialController1.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController1.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertFalse(initialController1.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNotNull(initialController2.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController2.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertFalse(initialController2.changeHandlerHistory.latestIsPush())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBackstackForInvertHandlersWithoutRemovesView() {
|
||||
val initialController1 = TestController()
|
||||
val initialTransaction1 = initialController1.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler("initialPush1", true),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop1", true)
|
||||
)
|
||||
router.setRoot(initialTransaction1)
|
||||
|
||||
val initialController2 = TestController()
|
||||
val initialPushHandler2Tag = "initialPush2"
|
||||
val initialTransaction2 = initialController2.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.taggedHandler(initialPushHandler2Tag, false),
|
||||
popChangeHandler = MockChangeHandler.taggedHandler("initialPop2", false)
|
||||
)
|
||||
router.pushController(initialTransaction2)
|
||||
|
||||
val initialView1 = initialController1.view
|
||||
val initialView2 = initialController2.view
|
||||
val setBackstackHandler = MockChangeHandler.taggedHandler("setBackstackHandler", true)
|
||||
val newBackstack = listOf(initialTransaction2, initialTransaction1)
|
||||
router.setBackstack(newBackstack, setBackstackHandler)
|
||||
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertTrue(initialController2.changeHandlerHistory.isValidHistory)
|
||||
Assert.assertEquals(2, initialController1.changeHandlerHistory.size().toLong())
|
||||
Assert.assertEquals(2, initialController2.changeHandlerHistory.size().toLong())
|
||||
Assert.assertNotNull(initialController1.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(initialView1, initialController1.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
initialPushHandler2Tag,
|
||||
initialController1.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertTrue(initialController1.changeHandlerHistory.latestIsPush())
|
||||
Assert.assertNull(initialController2.changeHandlerHistory.latestToView())
|
||||
Assert.assertEquals(initialView2, initialController2.changeHandlerHistory.latestFromView())
|
||||
Assert.assertEquals(
|
||||
setBackstackHandler.tag,
|
||||
initialController2.changeHandlerHistory.latestChangeHandler().tag
|
||||
)
|
||||
Assert.assertFalse(initialController2.changeHandlerHistory.latestIsPush())
|
||||
}
|
||||
}
|
||||
@@ -1,496 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class RouterTests {
|
||||
|
||||
private Router router;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ActivityProxy activityProxy = new ActivityProxy().create(null).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRoot() {
|
||||
String rootTag = "root";
|
||||
|
||||
Controller rootController = new TestController();
|
||||
|
||||
assertFalse(router.hasRootController());
|
||||
|
||||
router.setRoot(RouterTransaction.with(rootController).tag(rootTag));
|
||||
|
||||
assertTrue(router.hasRootController());
|
||||
|
||||
assertEquals(rootController, router.getControllerWithTag(rootTag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNewRoot() {
|
||||
String oldRootTag = "oldRoot";
|
||||
String newRootTag = "newRoot";
|
||||
|
||||
Controller oldRootController = new TestController();
|
||||
Controller newRootController = new TestController();
|
||||
|
||||
router.setRoot(RouterTransaction.with(oldRootController).tag(oldRootTag));
|
||||
router.setRoot(RouterTransaction.with(newRootController).tag(newRootTag));
|
||||
|
||||
assertNull(router.getControllerWithTag(oldRootTag));
|
||||
assertEquals(newRootController, router.getControllerWithTag(newRootTag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByInstanceId() {
|
||||
Controller controller = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
assertEquals(controller, router.getControllerWithInstanceId(controller.getInstanceId()));
|
||||
assertNull(router.getControllerWithInstanceId("fake id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByTag() {
|
||||
String controller1Tag = "controller1";
|
||||
String controller2Tag = "controller2";
|
||||
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controller1)
|
||||
.tag(controller1Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.tag(controller2Tag));
|
||||
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertEquals(controller2, router.getControllerWithTag(controller2Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushPopControllers() {
|
||||
String controller1Tag = "controller1";
|
||||
String controller2Tag = "controller2";
|
||||
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controller1)
|
||||
.tag(controller1Tag));
|
||||
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.tag(controller2Tag));
|
||||
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertNull(router.getControllerWithTag(controller2Tag));
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertEquals(0, router.getBackstackSize());
|
||||
|
||||
assertNull(router.getControllerWithTag(controller1Tag));
|
||||
assertNull(router.getControllerWithTag(controller2Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopControllerConcurrentModificationException() {
|
||||
int step = 1;
|
||||
for (int i = 0; i < 10; i++, step++) {
|
||||
router.pushController(RouterTransaction.with(new TestController()).tag("1"));
|
||||
router.pushController(RouterTransaction.with(new TestController()).tag("2"));
|
||||
router.pushController(RouterTransaction.with(new TestController()).tag("3"));
|
||||
|
||||
String tag;
|
||||
if (step == 1) {
|
||||
tag = "1";
|
||||
} else if (step == 2) {
|
||||
tag = "2";
|
||||
} else {
|
||||
tag = "3";
|
||||
step = 0;
|
||||
}
|
||||
Controller controller = router.getControllerWithTag(tag);
|
||||
if (controller != null) {
|
||||
router.popController(controller);
|
||||
}
|
||||
router.popToRoot();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopToTag() {
|
||||
String controller1Tag = "controller1";
|
||||
String controller2Tag = "controller2";
|
||||
String controller3Tag = "controller3";
|
||||
String controller4Tag = "controller4";
|
||||
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
Controller controller3 = new TestController();
|
||||
Controller controller4 = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controller1)
|
||||
.tag(controller1Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.tag(controller2Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller3)
|
||||
.tag(controller3Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller4)
|
||||
.tag(controller4Tag));
|
||||
|
||||
router.popToTag(controller2Tag);
|
||||
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertEquals(controller2, router.getControllerWithTag(controller2Tag));
|
||||
assertNull(router.getControllerWithTag(controller3Tag));
|
||||
assertNull(router.getControllerWithTag(controller4Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopNonCurrent() {
|
||||
String controller1Tag = "controller1";
|
||||
String controller2Tag = "controller2";
|
||||
String controller3Tag = "controller3";
|
||||
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
Controller controller3 = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controller1)
|
||||
.tag(controller1Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.tag(controller2Tag));
|
||||
|
||||
router.pushController(RouterTransaction.with(controller3)
|
||||
.tag(controller3Tag));
|
||||
|
||||
router.popController(controller2);
|
||||
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertNull(router.getControllerWithTag(controller2Tag));
|
||||
assertEquals(controller3, router.getControllerWithTag(controller3Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBackstack() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(rootTransaction, middleTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(middleTransaction, fetchedBackstack.get(1));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewSetBackstack() {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(rootTransaction, middleTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(middleTransaction, fetchedBackstack.get(1));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(2));
|
||||
|
||||
assertEquals(router, rootTransaction.controller().getRouter());
|
||||
assertEquals(router, middleTransaction.controller().getRouter());
|
||||
assertEquals(router, topTransaction.controller().getRouter());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewSetBackstackWithNoRemoveViewOnPush() {
|
||||
RouterTransaction oldRootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction oldTopTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
router.setRoot(oldRootTransaction);
|
||||
router.pushController(oldTopTransaction);
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
assertTrue(oldRootTransaction.controller().isAttached());
|
||||
assertTrue(oldTopTransaction.controller().isAttached());
|
||||
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(rootTransaction, middleTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(middleTransaction, fetchedBackstack.get(1));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(2));
|
||||
|
||||
assertFalse(oldRootTransaction.controller().isAttached());
|
||||
assertFalse(oldTopTransaction.controller().isAttached());
|
||||
assertTrue(rootTransaction.controller().isAttached());
|
||||
assertTrue(middleTransaction.controller().isAttached());
|
||||
assertTrue(topTransaction.controller().isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopToRoot() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction transaction1 = RouterTransaction.with(new TestController());
|
||||
RouterTransaction transaction2 = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(rootTransaction, transaction1, transaction2);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
router.popToRoot();
|
||||
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
assertEquals(rootTransaction, router.getBackstack().get(0));
|
||||
|
||||
assertTrue(rootTransaction.controller().isAttached());
|
||||
assertFalse(transaction1.controller().isAttached());
|
||||
assertFalse(transaction2.controller().isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopToRootWithNoRemoveViewOnPush() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(new HorizontalChangeHandler(false));
|
||||
RouterTransaction transaction1 = RouterTransaction.with(new TestController()).pushChangeHandler(new HorizontalChangeHandler(false));
|
||||
RouterTransaction transaction2 = RouterTransaction.with(new TestController()).pushChangeHandler(new HorizontalChangeHandler(false));
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(rootTransaction, transaction1, transaction2);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
router.popToRoot();
|
||||
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
assertEquals(rootTransaction, router.getBackstack().get(0));
|
||||
|
||||
assertTrue(rootTransaction.controller().isAttached());
|
||||
assertFalse(transaction1.controller().isAttached());
|
||||
assertFalse(transaction2.controller().isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceTopController() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(rootTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
|
||||
RouterTransaction newTopTransaction = RouterTransaction.with(new TestController());
|
||||
router.replaceTopController(newTopTransaction);
|
||||
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
fetchedBackstack = router.getBackstack();
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(newTopTransaction, fetchedBackstack.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceTopControllerWithNoRemoveViewOnPush() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(rootTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
assertTrue(rootTransaction.controller().isAttached());
|
||||
assertTrue(topTransaction.controller().isAttached());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
|
||||
RouterTransaction newTopTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
router.replaceTopController(newTopTransaction);
|
||||
newTopTransaction.pushChangeHandler().completeImmediately();
|
||||
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
fetchedBackstack = router.getBackstack();
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(newTopTransaction, fetchedBackstack.get(1));
|
||||
|
||||
assertTrue(rootTransaction.controller().isAttached());
|
||||
assertFalse(topTransaction.controller().isAttached());
|
||||
assertTrue(newTopTransaction.controller().isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRearrangeTransactionBackstack() {
|
||||
RouterTransaction transaction1 = RouterTransaction.with(new TestController());
|
||||
RouterTransaction transaction2 = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(transaction1, transaction2);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(1, transaction1.getTransactionIndex());
|
||||
assertEquals(2, transaction2.getTransactionIndex());
|
||||
|
||||
backstack = Arrays.asList(transaction2, transaction1);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(1, transaction2.getTransactionIndex());
|
||||
assertEquals(2, transaction1.getTransactionIndex());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
assertEquals(transaction2, router.getBackstack().get(0));
|
||||
|
||||
router.handleBack();
|
||||
assertEquals(0, router.getBackstackSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildRouterRearrangeTransactionBackstack() {
|
||||
Controller parent = new TestController();
|
||||
router.setRoot(RouterTransaction.with(parent));
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.CHILD_VIEW_ID_1));
|
||||
|
||||
RouterTransaction transaction1 = RouterTransaction.with(new TestController());
|
||||
RouterTransaction transaction2 = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = Arrays.asList(transaction1, transaction2);
|
||||
childRouter.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(2, transaction1.getTransactionIndex());
|
||||
assertEquals(3, transaction2.getTransactionIndex());
|
||||
|
||||
backstack = Arrays.asList(transaction2, transaction1);
|
||||
childRouter.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(2, transaction2.getTransactionIndex());
|
||||
assertEquals(3, transaction1.getTransactionIndex());
|
||||
|
||||
childRouter.handleBack();
|
||||
|
||||
assertEquals(1, childRouter.getBackstackSize());
|
||||
assertEquals(transaction2, childRouter.getBackstack().get(0));
|
||||
|
||||
childRouter.handleBack();
|
||||
assertEquals(0, childRouter.getBackstackSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovesAllViewsOnDestroy() {
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
|
||||
router.setRoot(RouterTransaction.with(controller1));
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.pushChangeHandler(new FadeChangeHandler(false)));
|
||||
|
||||
assertEquals(2, router.container.getChildCount());
|
||||
|
||||
router.destroy(true);
|
||||
|
||||
assertEquals(0, router.container.getChildCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBeingDestroyed() {
|
||||
final LifecycleListener lifecycleListener = new LifecycleListener() {
|
||||
@Override
|
||||
public void preDestroyView(@NonNull Controller controller, @NonNull View view) {
|
||||
assertTrue(controller.isBeingDestroyed());
|
||||
}
|
||||
};
|
||||
|
||||
Controller controller1 = new TestController();
|
||||
Controller controller2 = new TestController();
|
||||
controller2.addLifecycleListener(lifecycleListener);
|
||||
|
||||
router.setRoot(RouterTransaction.with(controller1));
|
||||
router.pushController(RouterTransaction.with(controller2));
|
||||
assertFalse(controller1.isBeingDestroyed());
|
||||
assertFalse(controller2.isBeingDestroyed());
|
||||
|
||||
router.popCurrentController();
|
||||
assertFalse(controller1.isBeingDestroyed());
|
||||
assertTrue(controller2.isBeingDestroyed());
|
||||
|
||||
Controller controller3 = new TestController();
|
||||
controller3.addLifecycleListener(lifecycleListener);
|
||||
router.pushController(RouterTransaction.with(controller3));
|
||||
assertFalse(controller1.isBeingDestroyed());
|
||||
assertFalse(controller3.isBeingDestroyed());
|
||||
|
||||
router.popToRoot();
|
||||
assertFalse(controller1.isBeingDestroyed());
|
||||
assertTrue(controller3.isBeingDestroyed());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class RouterTests {
|
||||
|
||||
private val router = Robolectric.buildActivity(TestActivity::class.java)
|
||||
.setup()
|
||||
.get()
|
||||
.router
|
||||
|
||||
@Test
|
||||
fun testSetRoot() {
|
||||
val rootTag = "root"
|
||||
val rootController = TestController()
|
||||
Assert.assertFalse(router.hasRootController())
|
||||
|
||||
router.setRoot(RouterTransaction.with(rootController).tag(rootTag))
|
||||
Assert.assertTrue(router.hasRootController())
|
||||
Assert.assertEquals(rootController, router.getControllerWithTag(rootTag))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetNewRoot() {
|
||||
val oldRootTag = "oldRoot"
|
||||
val newRootTag = "newRoot"
|
||||
val oldRootController = TestController()
|
||||
val newRootController = TestController()
|
||||
router.setRoot(RouterTransaction.with(oldRootController).tag(oldRootTag))
|
||||
router.setRoot(RouterTransaction.with(newRootController).tag(newRootTag))
|
||||
Assert.assertNull(router.getControllerWithTag(oldRootTag))
|
||||
Assert.assertEquals(newRootController, router.getControllerWithTag(newRootTag))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetByInstanceId() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction())
|
||||
Assert.assertEquals(
|
||||
controller,
|
||||
router.getControllerWithInstanceId(controller.getInstanceId())
|
||||
)
|
||||
Assert.assertNull(router.getControllerWithInstanceId("fake id"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetByTag() {
|
||||
val controller1Tag = "controller1"
|
||||
val controller2Tag = "controller2"
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller1).tag(controller1Tag)
|
||||
)
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller2).tag(controller2Tag)
|
||||
)
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag))
|
||||
Assert.assertEquals(controller2, router.getControllerWithTag(controller2Tag))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPushPopControllers() {
|
||||
val controller1Tag = "controller1"
|
||||
val controller2Tag = "controller2"
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller1).tag(controller1Tag)
|
||||
)
|
||||
Assert.assertEquals(1, router.backstackSize.toLong())
|
||||
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller2).tag(controller2Tag)
|
||||
)
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
|
||||
router.popCurrentController()
|
||||
Assert.assertEquals(1, router.backstackSize.toLong())
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag))
|
||||
Assert.assertNull(router.getControllerWithTag(controller2Tag))
|
||||
|
||||
router.popCurrentController()
|
||||
Assert.assertEquals(0, router.backstackSize.toLong())
|
||||
Assert.assertNull(router.getControllerWithTag(controller1Tag))
|
||||
Assert.assertNull(router.getControllerWithTag(controller2Tag))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopControllerConcurrentModificationException() {
|
||||
var step = 1
|
||||
var i = 0
|
||||
while (i < 10) {
|
||||
router.pushController(RouterTransaction.with(TestController()).tag("1"))
|
||||
router.pushController(RouterTransaction.with(TestController()).tag("2"))
|
||||
router.pushController(RouterTransaction.with(TestController()).tag("3"))
|
||||
val tag = when (step) {
|
||||
1 -> "1"
|
||||
2 -> "2"
|
||||
else -> {
|
||||
step = 0
|
||||
"3"
|
||||
}
|
||||
}
|
||||
val controller = router.getControllerWithTag(tag)
|
||||
if (controller != null) {
|
||||
router.popController(controller)
|
||||
}
|
||||
router.popToRoot()
|
||||
i++
|
||||
step++
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopToTag() {
|
||||
val controller1Tag = "controller1"
|
||||
val controller2Tag = "controller2"
|
||||
val controller3Tag = "controller3"
|
||||
val controller4Tag = "controller4"
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
val controller3 = TestController()
|
||||
val controller4 = TestController()
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller1).tag(controller1Tag)
|
||||
)
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller2).tag(controller2Tag)
|
||||
)
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller3).tag(controller3Tag)
|
||||
)
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller4).tag(controller4Tag)
|
||||
)
|
||||
router.popToTag(controller2Tag)
|
||||
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag))
|
||||
Assert.assertEquals(controller2, router.getControllerWithTag(controller2Tag))
|
||||
Assert.assertNull(router.getControllerWithTag(controller3Tag))
|
||||
Assert.assertNull(router.getControllerWithTag(controller4Tag))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopNonCurrent() {
|
||||
val controller1Tag = "controller1"
|
||||
val controller2Tag = "controller2"
|
||||
val controller3Tag = "controller3"
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
val controller3 = TestController()
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller1).tag(controller1Tag)
|
||||
)
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller2).tag(controller2Tag)
|
||||
)
|
||||
router.pushController(
|
||||
RouterTransaction.with(controller3).tag(controller3Tag)
|
||||
)
|
||||
router.popController(controller2)
|
||||
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag))
|
||||
Assert.assertNull(router.getControllerWithTag(controller2Tag))
|
||||
Assert.assertEquals(controller3, router.getControllerWithTag(controller3Tag))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBackstack() {
|
||||
val rootTransaction = TestController().asTransaction()
|
||||
val middleTransaction = TestController().asTransaction()
|
||||
val topTransaction = TestController().asTransaction()
|
||||
val backstack = listOf(rootTransaction, middleTransaction, topTransaction)
|
||||
router.setBackstack(backstack, null)
|
||||
Assert.assertEquals(3, router.backstackSize.toLong())
|
||||
|
||||
val fetchedBackstack = router.getBackstack()
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack[0])
|
||||
Assert.assertEquals(middleTransaction, fetchedBackstack[1])
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack[2])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNewSetBackstack() {
|
||||
router.setRoot(TestController().asTransaction())
|
||||
Assert.assertEquals(1, router.backstackSize.toLong())
|
||||
|
||||
val rootTransaction = TestController().asTransaction()
|
||||
val middleTransaction = TestController().asTransaction()
|
||||
val topTransaction = TestController().asTransaction()
|
||||
val backstack = listOf(rootTransaction, middleTransaction, topTransaction)
|
||||
router.setBackstack(backstack, null)
|
||||
|
||||
Assert.assertEquals(3, router.backstackSize.toLong())
|
||||
val fetchedBackstack = router.getBackstack()
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack[0])
|
||||
Assert.assertEquals(middleTransaction, fetchedBackstack[1])
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack[2])
|
||||
Assert.assertEquals(router, rootTransaction.controller.getRouter())
|
||||
Assert.assertEquals(router, middleTransaction.controller.getRouter())
|
||||
Assert.assertEquals(router, topTransaction.controller.getRouter())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNewSetBackstackWithNoRemoveViewOnPush() {
|
||||
val oldRootTransaction = TestController().asTransaction()
|
||||
val oldTopTransaction = TestController().asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.noRemoveViewOnPushHandler()
|
||||
)
|
||||
router.setRoot(oldRootTransaction)
|
||||
router.pushController(oldTopTransaction)
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
Assert.assertTrue(oldRootTransaction.controller.isAttached)
|
||||
Assert.assertTrue(oldTopTransaction.controller.isAttached)
|
||||
|
||||
val rootTransaction = TestController().asTransaction()
|
||||
val middleTransaction = TestController().asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.noRemoveViewOnPushHandler()
|
||||
)
|
||||
val topTransaction = TestController().asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.noRemoveViewOnPushHandler()
|
||||
)
|
||||
val backstack = listOf(rootTransaction, middleTransaction, topTransaction)
|
||||
router.setBackstack(backstack, null)
|
||||
|
||||
Assert.assertEquals(3, router.backstackSize.toLong())
|
||||
val fetchedBackstack = router.getBackstack()
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack[0])
|
||||
Assert.assertEquals(middleTransaction, fetchedBackstack[1])
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack[2])
|
||||
Assert.assertFalse(oldRootTransaction.controller.isAttached)
|
||||
Assert.assertFalse(oldTopTransaction.controller.isAttached)
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached)
|
||||
Assert.assertTrue(middleTransaction.controller.isAttached)
|
||||
Assert.assertTrue(topTransaction.controller.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopToRoot() {
|
||||
val rootTransaction = TestController().asTransaction()
|
||||
val transaction1 = TestController().asTransaction()
|
||||
val transaction2 = TestController().asTransaction()
|
||||
val backstack = listOf(rootTransaction, transaction1, transaction2)
|
||||
router.setBackstack(backstack, null)
|
||||
Assert.assertEquals(3, router.backstackSize.toLong())
|
||||
|
||||
router.popToRoot()
|
||||
Assert.assertEquals(1, router.backstackSize.toLong())
|
||||
Assert.assertEquals(rootTransaction, router.getBackstack()[0])
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached)
|
||||
Assert.assertFalse(transaction1.controller.isAttached)
|
||||
Assert.assertFalse(transaction2.controller.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopToRootWithNoRemoveViewOnPush() {
|
||||
val rootTransaction = TestController().asTransaction(
|
||||
pushChangeHandler = HorizontalChangeHandler(false)
|
||||
)
|
||||
val transaction1 = TestController().asTransaction(
|
||||
pushChangeHandler = HorizontalChangeHandler(false)
|
||||
)
|
||||
val transaction2 = TestController().asTransaction(
|
||||
pushChangeHandler = HorizontalChangeHandler(false)
|
||||
)
|
||||
val backstack = listOf(rootTransaction, transaction1, transaction2)
|
||||
router.setBackstack(backstack, null)
|
||||
Assert.assertEquals(3, router.backstackSize.toLong())
|
||||
|
||||
router.popToRoot()
|
||||
Assert.assertEquals(1, router.backstackSize.toLong())
|
||||
Assert.assertEquals(rootTransaction, router.getBackstack()[0])
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached)
|
||||
Assert.assertFalse(transaction1.controller.isAttached)
|
||||
Assert.assertFalse(transaction2.controller.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReplaceTopController() {
|
||||
val rootTransaction = TestController().asTransaction()
|
||||
val topTransaction = TestController().asTransaction()
|
||||
val backstack = listOf(rootTransaction, topTransaction)
|
||||
router.setBackstack(backstack, null)
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
|
||||
var fetchedBackstack = router.getBackstack()
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack[0])
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack[1])
|
||||
|
||||
val newTopTransaction = TestController().asTransaction()
|
||||
router.replaceTopController(newTopTransaction)
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
fetchedBackstack = router.getBackstack()
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack[0])
|
||||
Assert.assertEquals(newTopTransaction, fetchedBackstack[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReplaceTopControllerWithNoRemoveViewOnPush() {
|
||||
val rootTransaction = TestController().asTransaction()
|
||||
val topTransaction = TestController().asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.noRemoveViewOnPushHandler()
|
||||
)
|
||||
val backstack = listOf(rootTransaction, topTransaction)
|
||||
router.setBackstack(backstack, null)
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached)
|
||||
Assert.assertTrue(topTransaction.controller.isAttached)
|
||||
|
||||
var fetchedBackstack = router.getBackstack()
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack[0])
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack[1])
|
||||
|
||||
val newTopTransaction = TestController().asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.noRemoveViewOnPushHandler()
|
||||
)
|
||||
router.replaceTopController(newTopTransaction)
|
||||
newTopTransaction.pushChangeHandler()!!.completeImmediately()
|
||||
Assert.assertEquals(2, router.backstackSize.toLong())
|
||||
fetchedBackstack = router.getBackstack()
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack[0])
|
||||
Assert.assertEquals(newTopTransaction, fetchedBackstack[1])
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached)
|
||||
Assert.assertFalse(topTransaction.controller.isAttached)
|
||||
Assert.assertTrue(newTopTransaction.controller.isAttached)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRearrangeTransactionBackstack() {
|
||||
val transaction1 = TestController().asTransaction()
|
||||
val transaction2 = TestController().asTransaction()
|
||||
var backstack = listOf(transaction1, transaction2)
|
||||
router.setBackstack(backstack, null)
|
||||
Assert.assertEquals(1, transaction1.transactionIndex.toLong())
|
||||
Assert.assertEquals(2, transaction2.transactionIndex.toLong())
|
||||
|
||||
backstack = listOf(transaction2, transaction1)
|
||||
router.setBackstack(backstack, null)
|
||||
Assert.assertEquals(1, transaction2.transactionIndex.toLong())
|
||||
Assert.assertEquals(2, transaction1.transactionIndex.toLong())
|
||||
|
||||
router.handleBack()
|
||||
Assert.assertEquals(1, router.backstackSize.toLong())
|
||||
Assert.assertEquals(transaction2, router.getBackstack()[0])
|
||||
|
||||
router.handleBack()
|
||||
Assert.assertEquals(0, router.backstackSize.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildRouterRearrangeTransactionBackstack() {
|
||||
val parent = TestController()
|
||||
router.setRoot(parent.asTransaction())
|
||||
val childRouter = parent.getChildRouter(
|
||||
parent.view!!.findViewById(TestController.CHILD_VIEW_ID_1)
|
||||
)
|
||||
val transaction1 = TestController().asTransaction()
|
||||
val transaction2 = TestController().asTransaction()
|
||||
var backstack = listOf(transaction1, transaction2)
|
||||
childRouter.setBackstack(backstack, null)
|
||||
Assert.assertEquals(2, transaction1.transactionIndex.toLong())
|
||||
Assert.assertEquals(3, transaction2.transactionIndex.toLong())
|
||||
|
||||
backstack = listOf(transaction2, transaction1)
|
||||
childRouter.setBackstack(backstack, null)
|
||||
Assert.assertEquals(2, transaction2.transactionIndex.toLong())
|
||||
Assert.assertEquals(3, transaction1.transactionIndex.toLong())
|
||||
|
||||
childRouter.handleBack()
|
||||
Assert.assertEquals(1, childRouter.backstackSize.toLong())
|
||||
Assert.assertEquals(transaction2, childRouter.getBackstack()[0])
|
||||
|
||||
childRouter.handleBack()
|
||||
Assert.assertEquals(0, childRouter.backstackSize.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemovesAllViewsOnDestroy() {
|
||||
router.setRoot(TestController().asTransaction())
|
||||
router.pushController(
|
||||
TestController().asTransaction(
|
||||
pushChangeHandler = FadeChangeHandler(false)
|
||||
)
|
||||
)
|
||||
Assert.assertEquals(2, router.container.childCount.toLong())
|
||||
|
||||
router.destroy(true)
|
||||
Assert.assertEquals(0, router.container.childCount.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsBeingDestroyed() {
|
||||
val lifecycleListener: LifecycleListener = object : LifecycleListener() {
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
Assert.assertTrue(controller.isBeingDestroyed())
|
||||
}
|
||||
}
|
||||
val controller1 = TestController()
|
||||
val controller2 = TestController()
|
||||
controller2.addLifecycleListener(lifecycleListener)
|
||||
router.setRoot(controller1.asTransaction())
|
||||
router.pushController(controller2.asTransaction())
|
||||
Assert.assertFalse(controller1.isBeingDestroyed())
|
||||
Assert.assertFalse(controller2.isBeingDestroyed())
|
||||
|
||||
router.popCurrentController()
|
||||
Assert.assertFalse(controller1.isBeingDestroyed())
|
||||
Assert.assertTrue(controller2.isBeingDestroyed())
|
||||
|
||||
val controller3 = TestController()
|
||||
controller3.addLifecycleListener(lifecycleListener)
|
||||
router.pushController(controller3.asTransaction())
|
||||
Assert.assertFalse(controller1.isBeingDestroyed())
|
||||
Assert.assertFalse(controller3.isBeingDestroyed())
|
||||
|
||||
router.popToRoot()
|
||||
Assert.assertFalse(controller1.isBeingDestroyed())
|
||||
Assert.assertTrue(controller3.isBeingDestroyed())
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class TargetControllerTests {
|
||||
|
||||
private Router router;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
ActivityProxy activityProxy = new ActivityProxy().create(savedInstanceState).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createActivityController(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSiblingTarget() {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertNull(controllerB.getTargetController());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
controllerB.setTargetController(controllerA);
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertEquals(controllerA, controllerB.getTargetController());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParentChildTarget() {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertNull(controllerB.getTargetController());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
controllerB.setTargetController(controllerA);
|
||||
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertEquals(controllerA, controllerB.getTargetController());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildParentTarget() {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertNull(controllerB.getTargetController());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
controllerA.setTargetController(controllerB);
|
||||
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
assertNull(controllerB.getTargetController());
|
||||
assertEquals(controllerB, controllerA.getTargetController());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class TargetControllerTests {
|
||||
|
||||
private val router = Robolectric.buildActivity(TestActivity::class.java)
|
||||
.setup()
|
||||
.get()
|
||||
.router
|
||||
|
||||
@Test
|
||||
fun testSiblingTarget() {
|
||||
val controllerA = TestController()
|
||||
val controllerB = TestController()
|
||||
Assert.assertNull(controllerA.targetController)
|
||||
Assert.assertNull(controllerB.targetController)
|
||||
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
controllerB.targetController = controllerA
|
||||
router.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertNull(controllerA.targetController)
|
||||
Assert.assertEquals(controllerA, controllerB.targetController)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParentChildTarget() {
|
||||
val controllerA = TestController()
|
||||
val controllerB = TestController()
|
||||
Assert.assertNull(controllerA.targetController)
|
||||
Assert.assertNull(controllerB.targetController)
|
||||
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
controllerB.targetController = controllerA
|
||||
val childRouter = controllerA.getChildRouter(
|
||||
controllerA.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouter.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertNull(controllerA.targetController)
|
||||
Assert.assertEquals(controllerA, controllerB.targetController)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildParentTarget() {
|
||||
val controllerA = TestController()
|
||||
val controllerB = TestController()
|
||||
Assert.assertNull(controllerA.targetController)
|
||||
Assert.assertNull(controllerB.targetController)
|
||||
|
||||
router.pushController(
|
||||
controllerA.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
controllerA.targetController = controllerB
|
||||
val childRouter = controllerA.getChildRouter(
|
||||
controllerA.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouter.pushController(
|
||||
controllerB.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
popChangeHandler = MockChangeHandler.defaultHandler()
|
||||
)
|
||||
)
|
||||
Assert.assertNull(controllerB.targetController)
|
||||
Assert.assertEquals(controllerB, controllerA.targetController)
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -1,4 +1,4 @@
|
||||
package com.bluelinelabs.conductor.util;
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -14,9 +14,10 @@ import androidx.annotation.IdRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.util.AttachFakingFrameLayout;
|
||||
import com.bluelinelabs.conductor.util.CallState;
|
||||
import com.bluelinelabs.conductor.util.ChangeHandlerHistory;
|
||||
import com.bluelinelabs.conductor.util.MockChangeHandler;
|
||||
|
||||
public class TestController extends Controller {
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ViewLeakTests {
|
||||
|
||||
private ActivityProxy activityProxy;
|
||||
private Router router;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createActivityController(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPop() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopWhenPushNeverAdded() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller).pushChangeHandler(new NeverAddChangeHandler()));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopWhenPushNeverCompleted() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller).pushChangeHandler(new NeverCompleteChangeHandler()));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityStop() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
activityProxy.stop(true);
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityStopWhenPushNeverCompleted() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller).pushChangeHandler(new NeverCompleteChangeHandler()));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
activityProxy.stop(true);
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityDestroyWhenPushNeverAdded() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller).pushChangeHandler(new NeverAddChangeHandler()));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
activityProxy.stop(true).destroy();
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testViewRemovedIfLayeredNotRemovesFromViewOnPush() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
router.pushController(RouterTransaction.with(new TestController()).pushChangeHandler(new SimpleSwapChangeHandler(false)));
|
||||
|
||||
View view = controller.view;
|
||||
assertNotNull(view.getParent());
|
||||
|
||||
router.pushController(RouterTransaction.with(new TestController()));
|
||||
|
||||
assertNotNull(view.getParent());
|
||||
|
||||
router.popToRoot();
|
||||
|
||||
assertNull(view.getParent());
|
||||
}
|
||||
|
||||
public static class NeverAddChangeHandler extends ControllerChangeHandler {
|
||||
@Override
|
||||
public void performChange(@NonNull final ViewGroup container, @Nullable View from, @Nullable final View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
if (from != null) {
|
||||
container.removeView(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class NeverCompleteChangeHandler extends ControllerChangeHandler {
|
||||
@Override
|
||||
public void performChange(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
if (from != null) {
|
||||
container.removeView(from);
|
||||
}
|
||||
container.addView(to);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.bluelinelabs.conductor
|
||||
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class ViewLeakTests {
|
||||
|
||||
private val activityController = Robolectric.buildActivity(TestActivity::class.java).setup()
|
||||
private val router = activityController.get().router
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(TestController().asTransaction())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPop() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction())
|
||||
Assert.assertNotNull(controller.getView())
|
||||
|
||||
router.popCurrentController()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNull(controller.getView())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopWhenPushNeverAdded() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction(pushChangeHandler = NeverAddChangeHandler()))
|
||||
Assert.assertNotNull(controller.getView())
|
||||
|
||||
router.popCurrentController()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNull(controller.getView())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPopWhenPushNeverCompleted() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction(pushChangeHandler = NeverCompleteChangeHandler()))
|
||||
Assert.assertNotNull(controller.getView())
|
||||
|
||||
router.popCurrentController()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNull(controller.getView())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testActivityDestroy() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction())
|
||||
Assert.assertNotNull(controller.getView())
|
||||
|
||||
activityController.stop().destroy()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNull(controller.getView())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testActivityDestroyWhenPushNeverCompleted() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction(pushChangeHandler = NeverCompleteChangeHandler()))
|
||||
Assert.assertNotNull(controller.getView())
|
||||
|
||||
activityController.stop().destroy()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNull(controller.getView())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testActivityDestroyWhenPushNeverAdded() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction(pushChangeHandler = NeverAddChangeHandler()))
|
||||
Assert.assertNotNull(controller.getView())
|
||||
|
||||
activityController.stop().destroy()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNull(controller.getView())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testViewRemovedIfLayeredNotRemovesFromViewOnPush() {
|
||||
val controller = TestController()
|
||||
router.pushController(controller.asTransaction())
|
||||
router.pushController(TestController().asTransaction(pushChangeHandler = SimpleSwapChangeHandler(false)))
|
||||
val view = controller.view
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNotNull(view.parent)
|
||||
|
||||
router.pushController(TestController().asTransaction())
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNotNull(view.parent)
|
||||
|
||||
router.popToRoot()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNull(view.parent)
|
||||
}
|
||||
|
||||
class NeverAddChangeHandler : ControllerChangeHandler() {
|
||||
override fun performChange(
|
||||
container: ViewGroup,
|
||||
from: View?,
|
||||
to: View?,
|
||||
isPush: Boolean,
|
||||
changeListener: ControllerChangeCompletedListener
|
||||
) {
|
||||
if (from != null) {
|
||||
container.removeView(from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NeverCompleteChangeHandler : ControllerChangeHandler() {
|
||||
override fun performChange(
|
||||
container: ViewGroup,
|
||||
from: View?,
|
||||
to: View?,
|
||||
isPush: Boolean,
|
||||
changeListener: ControllerChangeCompletedListener
|
||||
) {
|
||||
if (from != null) {
|
||||
container.removeView(from)
|
||||
}
|
||||
container.addView(to)
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.bluelinelabs.conductor.internal
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.util.SparseArray
|
||||
import io.kotest.matchers.ints.shouldBeExactly
|
||||
import io.kotest.matchers.shouldBe
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class StringSparseArrayParcelerTest {
|
||||
|
||||
@Test
|
||||
fun emptyArray() {
|
||||
SparseArray<String>().parcelAndUnParcel().size() shouldBeExactly 0
|
||||
}
|
||||
|
||||
@Test
|
||||
fun arrayWithContents() {
|
||||
val array = SparseArray<String>()
|
||||
array.put(1, "one")
|
||||
array.put(7, "seven")
|
||||
|
||||
val unParceled = array.parcelAndUnParcel()
|
||||
|
||||
unParceled.size() shouldBeExactly 2
|
||||
unParceled[1] shouldBe "one"
|
||||
unParceled[7] shouldBe "seven"
|
||||
}
|
||||
|
||||
private fun SparseArray<String>.parcelAndUnParcel(): SparseArray<String> {
|
||||
val parceler = StringSparseArrayParceler(this)
|
||||
|
||||
val parcel = Parcel.obtain()
|
||||
parceler.writeToParcel(parcel, 0)
|
||||
|
||||
parcel.setDataPosition(0)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val creator = StringSparseArrayParceler::class.java.getField("CREATOR").get(null)
|
||||
as Parcelable.Creator<StringSparseArrayParceler>
|
||||
val unParceled = creator.createFromParcel(parcel)
|
||||
return unParceled.stringSparseArray.also {
|
||||
check(it !== this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
public class TestActivity extends Activity {
|
||||
|
||||
public boolean isChangingConfigurations = false;
|
||||
public boolean isDestroying = false;
|
||||
|
||||
@Override
|
||||
public boolean isChangingConfigurations() {
|
||||
return isChangingConfigurations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return isDestroying || super.isDestroyed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.bluelinelabs.conductor.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import com.bluelinelabs.conductor.Conductor
|
||||
import com.bluelinelabs.conductor.Router
|
||||
|
||||
class TestActivity : Activity() {
|
||||
|
||||
lateinit var router: Router
|
||||
|
||||
var changingConfigurations = false
|
||||
var destroying = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
router = Conductor.attachRouter(
|
||||
this,
|
||||
findViewById(android.R.id.content),
|
||||
savedInstanceState
|
||||
)
|
||||
}
|
||||
|
||||
override fun isChangingConfigurations(): Boolean {
|
||||
return changingConfigurations
|
||||
}
|
||||
|
||||
override fun isDestroyed(): Boolean {
|
||||
return destroying || super.isDestroyed()
|
||||
}
|
||||
}
|
||||
+15
-4
@@ -24,6 +24,7 @@ android {
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
compose = true
|
||||
}
|
||||
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
@@ -36,6 +37,10 @@ android {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion composeVersion
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -53,12 +58,18 @@ dependencies {
|
||||
implementation project(':conductor')
|
||||
implementation project(':conductor-modules:viewpager')
|
||||
implementation project(':conductor-modules:viewpager2')
|
||||
implementation project(':conductor-modules:rxlifecycle2')
|
||||
implementation project(':conductor-modules:autodispose')
|
||||
implementation project(':conductor-modules:arch-components-lifecycle')
|
||||
implementation project(':conductor-modules:androidx-transition')
|
||||
|
||||
debugImplementation rootProject.ext.leakCanary
|
||||
releaseImplementation rootProject.ext.leakCanaryNoOp
|
||||
testImplementation rootProject.ext.leakCanaryNoOp
|
||||
implementation "androidx.compose.ui:ui:$composeVersion"
|
||||
implementation "androidx.compose.ui:ui-tooling:$composeVersion"
|
||||
implementation "androidx.compose.foundation:foundation:$composeVersion"
|
||||
implementation "androidx.compose.material:material:$composeVersion"
|
||||
implementation "androidx.compose.material:material-icons-core:$composeVersion"
|
||||
implementation "androidx.compose.material:material-icons-extended:$composeVersion"
|
||||
implementation "androidx.activity:activity-compose:1.3.0-beta02"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07"
|
||||
|
||||
implementation rootProject.ext.leakCanary
|
||||
}
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.bluelinelabs.conductor.demo"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
package="com.bluelinelabs.conductor.demo">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:name="com.bluelinelabs.conductor.demo.DemoApplication"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:fullBackupContent="true"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
|
||||
<activity
|
||||
android:name="com.bluelinelabs.conductor.demo.MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.bluelinelabs.conductor.demo
|
||||
|
||||
import android.app.Application
|
||||
import com.squareup.leakcanary.LeakCanary
|
||||
import com.squareup.leakcanary.RefWatcher
|
||||
|
||||
class DemoApplication : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
refWatcher = LeakCanary.install(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
lateinit var refWatcher: RefWatcher
|
||||
}
|
||||
}
|
||||
+2
-19
@@ -11,22 +11,20 @@ import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.archlifecycle.LifecycleController
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication
|
||||
import com.bluelinelabs.conductor.demo.R
|
||||
import com.bluelinelabs.conductor.demo.ToolbarProvider
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.watchForLeaks
|
||||
import com.bluelinelabs.conductor.demo.databinding.ControllerLifecycleBinding
|
||||
|
||||
class ArchLifecycleController : LifecycleController() {
|
||||
|
||||
private var hasExited = false
|
||||
|
||||
init {
|
||||
Log.i(TAG, "Conductor: Constructor called")
|
||||
watchForLeaks()
|
||||
|
||||
lifecycle.addObserver(object : LifecycleObserver {
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
|
||||
@@ -104,21 +102,6 @@ class ArchLifecycleController : LifecycleController() {
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.i(TAG, "Conductor: onDestroy() called")
|
||||
super.onDestroy()
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChangeEnded(
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
super.onChangeEnded(changeHandler, changeType)
|
||||
hasExited = !changeType.isEnter
|
||||
if (isDestroyed) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+2
-18
@@ -6,14 +6,12 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.RouterTransaction.Companion.with
|
||||
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication
|
||||
import com.bluelinelabs.conductor.demo.R
|
||||
import com.bluelinelabs.conductor.demo.ToolbarProvider
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.watchForLeaks
|
||||
import com.bluelinelabs.conductor.demo.databinding.ControllerLifecycleBinding
|
||||
import com.uber.autodispose.autoDisposable
|
||||
import io.reactivex.Observable
|
||||
@@ -23,10 +21,10 @@ import java.util.concurrent.TimeUnit
|
||||
// instead of Activities or Fragments.
|
||||
class AutodisposeController : Controller() {
|
||||
|
||||
private var hasExited = false
|
||||
private val scopeProvider = ControllerScopeProvider.from(this)
|
||||
|
||||
init {
|
||||
watchForLeaks()
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose { Log.i(TAG, "Disposing from constructor") }
|
||||
.autoDisposable(scopeProvider)
|
||||
@@ -98,20 +96,6 @@ class AutodisposeController : Controller() {
|
||||
public override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Log.i(TAG, "onDestroy() called")
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChangeEnded(
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
super.onChangeEnded(changeHandler, changeType)
|
||||
hasExited = !changeType.isEnter
|
||||
if (isDestroyed) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+1
-1
@@ -2,10 +2,10 @@ package com.bluelinelabs.conductor.demo.controllers
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.DrawableRes
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.asTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.demo.ToolbarProvider
|
||||
|
||||
class ComposeController : Controller() {
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
savedViewState: Bundle?
|
||||
): View {
|
||||
return ComposeView(container.context).apply {
|
||||
setContent {
|
||||
LongNumberList {
|
||||
router.pushController(
|
||||
ComposeController().asTransaction(
|
||||
pushChangeHandler = HorizontalChangeHandler(),
|
||||
popChangeHandler = HorizontalChangeHandler()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
|
||||
(activity as? ToolbarProvider)?.toolbar?.apply {
|
||||
title = "Jetpack Compose Demo"
|
||||
menu.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LongNumberList(onClick: () -> Unit) {
|
||||
MaterialTheme {
|
||||
LazyColumn {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
items((0..100).toList()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(48.dp)
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart),
|
||||
text = "Line $it"
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-8
@@ -17,7 +17,9 @@ import com.bluelinelabs.conductor.demo.databinding.RowHomeBinding
|
||||
import com.bluelinelabs.conductor.demo.util.viewBinding
|
||||
|
||||
class ExternalModulesController : BaseController(R.layout.controller_additional_modules) {
|
||||
private val binding: ControllerAdditionalModulesBinding by viewBinding(ControllerAdditionalModulesBinding::bind)
|
||||
private val binding: ControllerAdditionalModulesBinding by viewBinding(
|
||||
ControllerAdditionalModulesBinding::bind
|
||||
)
|
||||
|
||||
override val title = "External Module Demos"
|
||||
|
||||
@@ -40,11 +42,6 @@ class ExternalModulesController : BaseController(R.layout.controller_additional_
|
||||
.pushChangeHandler(FadeChangeHandler())
|
||||
.popChangeHandler(FadeChangeHandler())
|
||||
)
|
||||
ModuleModel.RX_LIFECYCLE_2 -> router.pushController(
|
||||
with(RxLifecycle2Controller())
|
||||
.pushChangeHandler(FadeChangeHandler())
|
||||
.popChangeHandler(FadeChangeHandler())
|
||||
)
|
||||
ModuleModel.ARCH_LIFECYCLE -> router.pushController(
|
||||
with(ArchLifecycleController())
|
||||
.pushChangeHandler(FadeChangeHandler())
|
||||
@@ -56,7 +53,6 @@ class ExternalModulesController : BaseController(R.layout.controller_additional_
|
||||
|
||||
private enum class ModuleModel(val title: String, @ColorRes val color: Int) {
|
||||
AUTODISPOSE("Autodispose", R.color.purple_300),
|
||||
RX_LIFECYCLE_2("Rx Lifecycle 2", R.color.blue_grey_300),
|
||||
ARCH_LIFECYCLE("Arch Components Lifecycle", R.color.orange_300);
|
||||
}
|
||||
|
||||
@@ -83,7 +79,10 @@ private class AdditionalModulesAdapter(
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(item: ModuleModel) {
|
||||
binding.title.text = item.title
|
||||
binding.dot.drawable.setColorFilter(ContextCompat.getColor(itemView.context, item.color), PorterDuff.Mode.SRC_ATOP)
|
||||
binding.dot.drawable.setColorFilter(
|
||||
ContextCompat.getColor(itemView.context, item.color),
|
||||
PorterDuff.Mode.SRC_ATOP
|
||||
)
|
||||
itemView.setOnClickListener { modelClickListener(item) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.core.text.buildSpannedString
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.asTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.demo.R
|
||||
@@ -117,12 +118,24 @@ class HomeController : BaseController(R.layout.controller_home) {
|
||||
)
|
||||
}
|
||||
DemoModel.SHARED_ELEMENT_TRANSITIONS -> {
|
||||
val titleSharedElementName = resources!!.getString(R.string.transition_tag_title_indexed, position)
|
||||
val dotSharedElementName = resources!!.getString(R.string.transition_tag_dot_indexed, position)
|
||||
val titleSharedElementName =
|
||||
resources!!.getString(R.string.transition_tag_title_indexed, position)
|
||||
val dotSharedElementName =
|
||||
resources!!.getString(R.string.transition_tag_dot_indexed, position)
|
||||
router.pushController(
|
||||
RouterTransaction.with(CityGridController(model.title, model.color, position))
|
||||
.pushChangeHandler(ArcFadeMoveChangeHandler(titleSharedElementName, dotSharedElementName))
|
||||
.popChangeHandler(ArcFadeMoveChangeHandler(titleSharedElementName, dotSharedElementName))
|
||||
.pushChangeHandler(
|
||||
ArcFadeMoveChangeHandler(
|
||||
titleSharedElementName,
|
||||
dotSharedElementName
|
||||
)
|
||||
)
|
||||
.popChangeHandler(
|
||||
ArcFadeMoveChangeHandler(
|
||||
titleSharedElementName,
|
||||
dotSharedElementName
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
DemoModel.DRAG_DISMISS -> {
|
||||
@@ -153,13 +166,19 @@ class HomeController : BaseController(R.layout.controller_home) {
|
||||
.popChangeHandler(FadeChangeHandler())
|
||||
)
|
||||
}
|
||||
DemoModel.COMPOSE -> {
|
||||
router.pushController(
|
||||
ComposeController().asTransaction(FadeChangeHandler(), FadeChangeHandler())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAboutDialog(fromFab: Boolean) {
|
||||
val details = SpannableString("A small, yet full-featured framework that allows building View-based Android applications").apply {
|
||||
setSpan(AbsoluteSizeSpan(16, true), 0, length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
|
||||
}
|
||||
val details =
|
||||
SpannableString("A small, yet full-featured framework that allows building View-based Android applications").apply {
|
||||
setSpan(AbsoluteSizeSpan(16, true), 0, length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
|
||||
}
|
||||
|
||||
val link = SpannableString(CONDUCTOR_URL).apply {
|
||||
setSpan(object : URLSpan(CONDUCTOR_URL) {
|
||||
@@ -175,7 +194,8 @@ class HomeController : BaseController(R.layout.controller_home) {
|
||||
append(link)
|
||||
}
|
||||
|
||||
val pushHandler = if (fromFab) FabToDialogTransitionChangeHandler() else FadeChangeHandler(false)
|
||||
val pushHandler =
|
||||
if (fromFab) FabToDialogTransitionChangeHandler() else FadeChangeHandler(false)
|
||||
val popHandler = if (fromFab) FabToDialogTransitionChangeHandler() else FadeChangeHandler()
|
||||
router.pushController(
|
||||
RouterTransaction.with(DialogController("Conductor", description))
|
||||
@@ -191,6 +211,7 @@ class HomeController : BaseController(R.layout.controller_home) {
|
||||
}
|
||||
|
||||
private enum class DemoModel(val title: String, @ColorRes val color: Int) {
|
||||
COMPOSE("Jetpack Compose", R.color.amber_500),
|
||||
NAVIGATION("Navigation Demos", R.color.red_300),
|
||||
TRANSITIONS("Transition Demos", R.color.blue_grey_300),
|
||||
SHARED_ELEMENT_TRANSITIONS("Shared Element Demos", R.color.purple_300),
|
||||
|
||||
-119
@@ -1,119 +0,0 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.RouterTransaction.Companion.with
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication
|
||||
import com.bluelinelabs.conductor.demo.R
|
||||
import com.bluelinelabs.conductor.demo.ToolbarProvider
|
||||
import com.bluelinelabs.conductor.demo.databinding.ControllerLifecycleBinding
|
||||
import com.bluelinelabs.conductor.rxlifecycle2.ControllerEvent
|
||||
import com.bluelinelabs.conductor.rxlifecycle2.RxController
|
||||
import io.reactivex.Observable
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
// Shamelessly borrowed from the official RxLifecycle demo by Trello and adapted for Conductor Controllers
|
||||
// instead of Activities or Fragments.
|
||||
class RxLifecycle2Controller : RxController() {
|
||||
|
||||
private var hasExited = false
|
||||
|
||||
init {
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose { Log.i(TAG, "Disposing from constructor") }
|
||||
.compose(bindUntilEvent(ControllerEvent.DESTROY))
|
||||
.subscribe { num: Long ->
|
||||
Log.i(TAG, "Started in constructor, running until onDestroy(): $num")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
savedViewState: Bundle?
|
||||
): View {
|
||||
Log.i(TAG, "onCreateView() called")
|
||||
val binding = ControllerLifecycleBinding.inflate(inflater, container, false)
|
||||
binding.title.text = binding.root.resources.getString(R.string.rxlifecycle_title, TAG)
|
||||
|
||||
binding.nextReleaseView.setOnClickListener {
|
||||
retainViewMode = RetainViewMode.RELEASE_DETACH
|
||||
router.pushController(
|
||||
with(TextController("Logcat should now report that the observables from onAttach() and onViewBound() have been disposed of, while the constructor observable is still running."))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
|
||||
binding.nextRetainView.setOnClickListener {
|
||||
retainViewMode = RetainViewMode.RETAIN_DETACH
|
||||
router.pushController(
|
||||
with(TextController("Logcat should now report that the observables from onAttach() has been disposed of, while the constructor and onViewBound() observables are still running."))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose { Log.i(TAG, "Disposing from onCreateView()") }
|
||||
.compose(bindUntilEvent(ControllerEvent.DESTROY_VIEW))
|
||||
.subscribe { num: Long ->
|
||||
Log.i(TAG, "Started in onCreateView(), running until onDestroyView(): $num")
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
Log.i(TAG, "onAttach() called")
|
||||
|
||||
(activity as ToolbarProvider).toolbar.title = "RxLifecycle2 Demo"
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose { Log.i(TAG, "Disposing from onAttach()") }
|
||||
.compose(bindUntilEvent(ControllerEvent.DETACH))
|
||||
.subscribe { num: Long ->
|
||||
Log.i(TAG, "Started in onAttach(), running until onDetach(): $num")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
super.onDestroyView(view)
|
||||
Log.i(TAG, "onDestroyView() called")
|
||||
}
|
||||
|
||||
override fun onDetach(view: View) {
|
||||
super.onDetach(view)
|
||||
Log.i(TAG, "onDetach() called")
|
||||
}
|
||||
|
||||
public override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Log.i(TAG, "onDestroy() called")
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChangeEnded(
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
super.onChangeEnded(changeHandler, changeType)
|
||||
hasExited = !changeType.isEnter
|
||||
if (isDestroyed) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "RxLifecycleController"
|
||||
}
|
||||
|
||||
}
|
||||
+5
-1
@@ -14,7 +14,11 @@ import com.bluelinelabs.conductor.demo.ToolbarProvider
|
||||
abstract class BaseController(
|
||||
@LayoutRes private val layoutRes: Int,
|
||||
args: Bundle? = null
|
||||
) : RefWatchingController(args) {
|
||||
) : Controller(args) {
|
||||
|
||||
init {
|
||||
watchForLeaks()
|
||||
}
|
||||
|
||||
// Note: This is just a quick demo of how an ActionBar *can* be accessed, not necessarily how it *should*
|
||||
// be accessed. In a production app, this would use Dagger instead.
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers.base
|
||||
|
||||
import android.os.Bundle
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication
|
||||
|
||||
abstract class RefWatchingController(args: Bundle?) : Controller(args) {
|
||||
|
||||
private var hasExited = false
|
||||
|
||||
public override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChangeEnded(
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
super.onChangeEnded(changeHandler, changeType)
|
||||
|
||||
hasExited = !changeType.isEnter
|
||||
if (isDestroyed) {
|
||||
DemoApplication.refWatcher.watch(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers.base
|
||||
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import leakcanary.AppWatcher
|
||||
|
||||
private class RefWatchingControllerLifecycleListener : Controller.LifecycleListener() {
|
||||
|
||||
private var hasExited = false
|
||||
|
||||
override fun postDestroy(controller: Controller) {
|
||||
if (hasExited) {
|
||||
controller.expectWeaklyReachable()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChangeEnd(
|
||||
controller: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
hasExited = !changeType.isEnter
|
||||
if (controller.isDestroyed) {
|
||||
controller.expectWeaklyReachable()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Controller.expectWeaklyReachable() {
|
||||
AppWatcher.objectWatcher.expectWeaklyReachable(
|
||||
this,
|
||||
"A destroyed controller should have only weak references."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun Controller.watchForLeaks() {
|
||||
addLifecycleListener(RefWatchingControllerLifecycleListener())
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
<color name="cyan_300">#4dd0e1</color>
|
||||
<color name="grey_300">#e0e0e0</color>
|
||||
<color name="grey_400">#78909C</color>
|
||||
<color name="amber_500">#ffc107</color>
|
||||
|
||||
<color name="dark_icon">#99000000</color>
|
||||
<color name="dialog_background">#fafafa</color>
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
<!-- Drag Dismiss Demo -->
|
||||
<string name="drag_to_dismiss">Elastic scrolling view - scroll past bounds to dismiss.</string>
|
||||
|
||||
<!-- RxLifecycle Demo -->
|
||||
<string name="rxlifecycle_title">Watch tag %1$s on logcat for a demo.</string>
|
||||
<string name="next_controller_retain">Push Controller, retaining this View</string>
|
||||
<string name="next_controller_release">Push Controller, releasing this View</string>
|
||||
|
||||
+12
-17
@@ -4,29 +4,26 @@ ext {
|
||||
targetSdkVersion = 28
|
||||
|
||||
picassoVersion = '2.5.2'
|
||||
leakCanaryVersion = '1.5.4'
|
||||
rxJavaVersion = '1.3.8'
|
||||
rxJava2Version = '2.1.14'
|
||||
rxLifecycleVersion = '1.0'
|
||||
rxLifecycle2Version = '2.2.1'
|
||||
autodisposeVersion = '1.0.0'
|
||||
archComponentsVersion = '2.0.0'
|
||||
archComponentsVersion = '2.3.1'
|
||||
junitVersion = '4.12'
|
||||
mvnPublishVersion = '0.13.0'
|
||||
dokkaVersion = '1.4.10.2'
|
||||
mvnPublishVersion = '0.13.0'
|
||||
dokkaVersion = '1.4.32'
|
||||
composeVersion = "1.0.0-beta09"
|
||||
|
||||
agpVersion = "4.1.0"
|
||||
agpVersion = '7.0.3'
|
||||
lintVersion = agpVersion.replaceFirst(~/\d*/) { version ->
|
||||
// the major version of lint is always 23 version higher than the major version of agp
|
||||
version.toInteger() + 23
|
||||
}
|
||||
|
||||
kotlinVersion = '1.3.72'
|
||||
kotlinVersion = '1.5.10'
|
||||
kotlinStd = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
||||
|
||||
material = "com.google.android.material:material:1.1.0"
|
||||
androidxAnnotations = "androidx.annotation:annotation:1.1.0"
|
||||
androidxAppCompat = "androidx.appcompat:appcompat:1.0.0"
|
||||
androidxAppCompat = "androidx.appcompat:appcompat:1.3.0"
|
||||
androidxTransition = "androidx.transition:transition:1.3.1"
|
||||
androidxCollection = "androidx.collection:collection:1.1.0"
|
||||
androidxViewPager2 = "androidx.viewpager2:viewpager2:1.0.0"
|
||||
@@ -34,15 +31,10 @@ ext {
|
||||
|
||||
picasso = "com.squareup.picasso:picasso:$picassoVersion"
|
||||
|
||||
leakCanary = "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
|
||||
leakCanaryNoOp = "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
|
||||
leakCanary = "com.squareup.leakcanary:leakcanary-android:2.7"
|
||||
|
||||
rxJava = "io.reactivex:rxjava:$rxJavaVersion"
|
||||
rxJava2 = "io.reactivex.rxjava2:rxjava:$rxJava2Version"
|
||||
|
||||
rxLifecycle2 = "com.trello.rxlifecycle2:rxlifecycle:$rxLifecycle2Version"
|
||||
rxLifecycleAndroid2 = "com.trello.rxlifecycle2:rxlifecycle-android:$rxLifecycle2Version"
|
||||
|
||||
autodispose = "com.uber.autodispose:autodispose:$autodisposeVersion"
|
||||
autodisposeLifecycle = "com.uber.autodispose:autodispose-lifecycle:$autodisposeVersion"
|
||||
autodisposeKtx = "com.uber.autodispose:autodispose-ktx:$autodisposeVersion"
|
||||
@@ -50,8 +42,11 @@ ext {
|
||||
archComponentsLifecycle = "androidx.lifecycle:lifecycle-runtime:$archComponentsVersion"
|
||||
archComponentsLiveDataCore = "androidx.lifecycle:lifecycle-livedata-core:$archComponentsVersion"
|
||||
|
||||
savedState = "androidx.savedstate:savedstate-ktx:1.1.0"
|
||||
|
||||
junit = "junit:junit:$junitVersion"
|
||||
roboelectric = "org.robolectric:robolectric:4.3.1"
|
||||
robolectric = "org.robolectric:robolectric:4.5.1"
|
||||
kotestAssertions = "io.kotest:kotest-assertions-core:4.6.0"
|
||||
|
||||
lintapi = "com.android.tools.lint:lint-api:$lintVersion"
|
||||
lintchecks = "com.android.tools.lint:lint-checks:$lintVersion"
|
||||
|
||||
+3
-20
@@ -1,25 +1,9 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
VERSION_CODE=3
|
||||
VERSION_NAME=3.1.2-SNAPSHOT
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
VERSION_NAME=3.0.1-SNAPSHOT
|
||||
VERSION_CODE=3
|
||||
GROUP=com.bluelinelabs
|
||||
|
||||
POM_DESCRIPTION=A small, yet full-featured framework that allows building View-based Android applications
|
||||
POM_URL=https://github.com/bluelinelabs/Conductor
|
||||
POM_SCM_URL=https://github.com/bluelinelabs/Conductor
|
||||
@@ -30,4 +14,3 @@ POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
POM_LICENCE_DIST=repo
|
||||
POM_DEVELOPER_ID=erickuck
|
||||
POM_DEVELOPER_NAME=Eric Kuck
|
||||
android.useAndroidX=true
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -72,7 +72,7 @@ case "`uname`" in
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
|
||||
@@ -2,7 +2,6 @@ include ':conductor'
|
||||
include ':conductor-lint'
|
||||
include ':conductor-modules:viewpager'
|
||||
include ':conductor-modules:viewpager2'
|
||||
include ':conductor-modules:rxlifecycle2'
|
||||
include ':conductor-modules:autodispose'
|
||||
include ':conductor-modules:arch-components-lifecycle'
|
||||
include ':conductor-modules:androidx-transition'
|
||||
|
||||
Reference in New Issue
Block a user