Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 769d552e88 | |||
| afa4b69d7a | |||
| a9bdf0dd06 | |||
| 6ffa94ed3a | |||
| 690001ed2a | |||
| 90e015b6b3 | |||
| 44bcd0f977 | |||
| 60d0fabcf4 | |||
| 10a1c8af3e | |||
| 6834df73e6 | |||
| 04d40a5b90 | |||
| be40900e1e | |||
| f16f7b6d2c | |||
| f74f8391b6 | |||
| 2ce8c0a45d | |||
| 77ad6b4512 | |||
| efbdf913bd | |||
| dfb01389f7 | |||
| e390261b53 | |||
| 27f5275172 | |||
| d15f2b68ab | |||
| 44ed19858b | |||
| e7c195d910 | |||
| 23a4dbbb60 | |||
| 0ac81767dd | |||
| 54cdc51557 | |||
| 09ce640d9c | |||
| 01df673a34 | |||
| 553bae0be5 | |||
| 48dc4abcbe | |||
| 4a814afb5f | |||
| 9cd225e704 | |||
| c8640af1ac | |||
| 43c825f7c2 | |||
| 7334ed5300 | |||
| 7ea4872ff8 | |||
| 9655170bd2 | |||
| acce9b1702 | |||
| 95baa8baa3 | |||
| 2388fa2d06 | |||
| 285eb59da0 | |||
| ae42ee1674 | |||
| 638b2ad311 | |||
| 96e068d348 | |||
| db359d906b | |||
| 11185458b3 | |||
| 977db6b5bf | |||
| 803c20e093 | |||
| 9948cb4652 | |||
| 07a579b939 | |||
| 104d96e6e2 | |||
| e0f40a9fce | |||
| bc8e0c5b2c | |||
| 2b6e41f895 | |||
| b633523d0e | |||
| c5eb7fc89e | |||
| cf6837a41a | |||
| e297242264 | |||
| 550e7e0aa1 |
+4
-2
@@ -3,9 +3,11 @@ language: android
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- build-tools-23.0.2
|
||||
- android-23
|
||||
- build-tools-24.0.3
|
||||
- android-25
|
||||
- extra-android-m2repository
|
||||
licenses:
|
||||
- '.+'
|
||||
|
||||
script:
|
||||
- ./gradlew test
|
||||
|
||||
@@ -20,22 +20,26 @@ Conductor is architecture-agnostic and does not try to force any design decision
|
||||
## Installation
|
||||
|
||||
```gradle
|
||||
compile 'com.bluelinelabs:conductor:2.0.3'
|
||||
compile 'com.bluelinelabs:conductor:2.1.0'
|
||||
|
||||
// If you want the components that go along with
|
||||
// Android's support libraries (currently just a PagerAdapter):
|
||||
compile 'com.bluelinelabs:conductor-support:2.0.3'
|
||||
compile 'com.bluelinelabs:conductor-support:2.1.0'
|
||||
|
||||
// If you want RxJava/RxAndroid lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.0.3'
|
||||
// If you want RxJava lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.1.0'
|
||||
|
||||
// If you want RxJava2 lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle2:2.1.0'
|
||||
```
|
||||
|
||||
SNAPSHOT:
|
||||
|
||||
```gradle
|
||||
compile 'com.bluelinelabs:conductor:2.0.4-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-support:2.0.4-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.0.4-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor:2.1.1-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-support:2.1.1-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.1.1-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle2:2.1.1-SNAPSHOT'
|
||||
```
|
||||
|
||||
You also have to add the url to the snapshot repository:
|
||||
|
||||
+2
-6
@@ -3,19 +3,15 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.0'
|
||||
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.10'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
targetCompatibility = JavaVersion.VERSION_1_7
|
||||
sourceCompatibility = JavaVersion.VERSION_1_7
|
||||
|
||||
configurations {
|
||||
lintChecks
|
||||
}
|
||||
@@ -8,6 +11,9 @@ dependencies {
|
||||
compile rootProject.ext.lintapi
|
||||
compile rootProject.ext.lintchecks
|
||||
|
||||
testCompile rootProject.ext.lint
|
||||
testCompile rootProject.ext.lintTests
|
||||
|
||||
lintChecks files(jar)
|
||||
}
|
||||
|
||||
|
||||
+22
-53
@@ -1,7 +1,6 @@
|
||||
package com.bluelinelabs.conductor.lint;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
||||
import com.android.tools.lint.client.api.JavaEvaluator;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
@@ -9,21 +8,13 @@ import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.JavaContext;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.ClassDeclaration;
|
||||
import lombok.ast.ConstructorDeclaration;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.NormalTypeBody;
|
||||
import lombok.ast.StrictListAccessor;
|
||||
import lombok.ast.TypeMember;
|
||||
import lombok.ast.VariableDefinition;
|
||||
|
||||
public final class ControllerChangeHandlerIssueDetector extends Detector implements Detector.JavaScanner, Detector.ClassScanner {
|
||||
public final class ControllerChangeHandlerIssueDetector extends Detector implements Detector.JavaPsiScanner {
|
||||
|
||||
public static final Issue ISSUE =
|
||||
Issue.create("ValidControllerChangeHandler", "ControllerChangeHandler not instantiatable",
|
||||
@@ -34,67 +25,45 @@ public final class ControllerChangeHandlerIssueDetector extends Detector impleme
|
||||
|
||||
public ControllerChangeHandlerIssueDetector() { }
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Speed getSpeed() {
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> applicableSuperClasses() {
|
||||
return Collections.singletonList("com.bluelinelabs.conductor.ControllerChangeHandler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClass(@NonNull JavaContext context, ClassDeclaration node,
|
||||
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
|
||||
|
||||
if (node == null) {
|
||||
public void checkClass(JavaContext context, PsiClass declaration) {
|
||||
final JavaEvaluator evaluator = context.getEvaluator();
|
||||
if (evaluator.isAbstract(declaration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int flags = node.astModifiers().getEffectiveModifierFlags();
|
||||
if ((flags & Modifier.ABSTRACT) != 0) {
|
||||
if (!evaluator.isPublic(declaration)) {
|
||||
String message = String.format("This ControllerChangeHandler class should be public (%1$s)", declaration.getQualifiedName());
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((flags & Modifier.PUBLIC) == 0) {
|
||||
String message = String.format("This ControllerChangeHandler class should be public (%1$s)", cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
if (declaration.getContainingClass() != null && !evaluator.isStatic(declaration)) {
|
||||
String message = String.format("This ControllerChangeHandler inner class should be static (%1$s)", declaration.getQualifiedName());
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
|
||||
String message = String.format("This ControllerChangeHandler inner class should be static (%1$s)", cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasConstructor = false;
|
||||
boolean hasDefaultConstructor = false;
|
||||
NormalTypeBody body = node.astBody();
|
||||
if (body != null) {
|
||||
for (TypeMember member : body.astMembers()) {
|
||||
if (member instanceof ConstructorDeclaration) {
|
||||
hasConstructor = true;
|
||||
ConstructorDeclaration constructor = (ConstructorDeclaration)member;
|
||||
|
||||
if (constructor.astModifiers().isPublic()) {
|
||||
StrictListAccessor<VariableDefinition, ConstructorDeclaration> params = constructor.astParameters();
|
||||
if (params.isEmpty()) {
|
||||
hasDefaultConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PsiMethod[] constructors = declaration.getConstructors();
|
||||
for (PsiMethod constructor : constructors) {
|
||||
if (evaluator.isPublic(constructor)) {
|
||||
if (constructor.getParameterList().getParametersCount() == 0) {
|
||||
hasDefaultConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasConstructor && !hasDefaultConstructor) {
|
||||
if (constructors.length > 0 && !hasDefaultConstructor) {
|
||||
String message = String.format(
|
||||
"This ControllerChangeHandler needs to have a public default constructor (`%1$s`)",
|
||||
cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
"This ControllerChangeHandler needs to have a public default constructor (`%1$s`)", declaration.getQualifiedName());
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-55
@@ -1,8 +1,7 @@
|
||||
package com.bluelinelabs.conductor.lint;
|
||||
|
||||
import com.android.SdkConstants;
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
||||
import com.android.tools.lint.client.api.JavaEvaluator;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
@@ -10,21 +9,14 @@ import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.JavaContext;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.ClassDeclaration;
|
||||
import lombok.ast.ConstructorDeclaration;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.NormalTypeBody;
|
||||
import lombok.ast.StrictListAccessor;
|
||||
import lombok.ast.TypeMember;
|
||||
import lombok.ast.VariableDefinition;
|
||||
|
||||
public final class ControllerIssueDetector extends Detector implements Detector.JavaScanner, Detector.ClassScanner {
|
||||
public final class ControllerIssueDetector extends Detector implements Detector.JavaPsiScanner {
|
||||
|
||||
public static final Issue ISSUE =
|
||||
Issue.create("ValidController", "Controller not instantiatable",
|
||||
@@ -35,74 +27,56 @@ public final class ControllerIssueDetector extends Detector implements Detector.
|
||||
|
||||
public ControllerIssueDetector() { }
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Speed getSpeed() {
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> applicableSuperClasses() {
|
||||
return Collections.singletonList("com.bluelinelabs.conductor.Controller");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClass(@NonNull JavaContext context, ClassDeclaration node,
|
||||
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
|
||||
|
||||
if (node == null) {
|
||||
public void checkClass(JavaContext context, PsiClass declaration) {
|
||||
final JavaEvaluator evaluator = context.getEvaluator();
|
||||
if (evaluator.isAbstract(declaration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int flags = node.astModifiers().getEffectiveModifierFlags();
|
||||
if ((flags & Modifier.ABSTRACT) != 0) {
|
||||
if (!evaluator.isPublic(declaration)) {
|
||||
String message = String.format("This Controller class should be public (%1$s)", declaration.getQualifiedName());
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((flags & Modifier.PUBLIC) == 0) {
|
||||
String message = String.format("This Controller class should be public (%1$s)", cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
if (declaration.getContainingClass() != null && !evaluator.isStatic(declaration)) {
|
||||
String message = String.format("This Controller inner class should be static (%1$s)", declaration.getQualifiedName());
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
|
||||
String message = String.format("This Controller inner class should be static (%1$s)", cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasConstructor = false;
|
||||
boolean hasDefaultConstructor = false;
|
||||
boolean hasBundleConstructor = false;
|
||||
NormalTypeBody body = node.astBody();
|
||||
if (body != null) {
|
||||
for (TypeMember member : body.astMembers()) {
|
||||
if (member instanceof ConstructorDeclaration) {
|
||||
hasConstructor = true;
|
||||
ConstructorDeclaration constructor = (ConstructorDeclaration)member;
|
||||
PsiMethod[] constructors = declaration.getConstructors();
|
||||
for (PsiMethod constructor : constructors) {
|
||||
if (evaluator.isPublic(constructor)) {
|
||||
PsiParameter[] parameters = constructor.getParameterList().getParameters();
|
||||
|
||||
if (constructor.astModifiers().isPublic()) {
|
||||
StrictListAccessor<VariableDefinition, ConstructorDeclaration> params = constructor.astParameters();
|
||||
if (params.isEmpty()) {
|
||||
hasDefaultConstructor = true;
|
||||
break;
|
||||
} else if (params.size() == 1 &&
|
||||
(params.first().astTypeReference().getTypeName().equals(SdkConstants.CLASS_BUNDLE)) ||
|
||||
params.first().astTypeReference().getTypeName().equals("Bundle")) {
|
||||
hasBundleConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameters.length == 0) {
|
||||
hasDefaultConstructor = true;
|
||||
break;
|
||||
} else if (parameters.length == 1 &&
|
||||
parameters[0].getType().equalsToText(SdkConstants.CLASS_BUNDLE) ||
|
||||
parameters[0].getType().equalsToText("Bundle")) {
|
||||
hasBundleConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasConstructor && !hasDefaultConstructor && !hasBundleConstructor) {
|
||||
if (constructors.length > 0 && !hasDefaultConstructor && !hasBundleConstructor) {
|
||||
String message = String.format(
|
||||
"This Controller needs to have either a public default constructor or a" +
|
||||
" public single-argument constructor that takes a Bundle. (`%1$s`)",
|
||||
cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
declaration.getQualifiedName());
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package com.bluelinelabs.conductor.lint;
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.LintDetectorTest;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
public class ControllerChangeHandlerDetectorTest extends LintDetectorTest {
|
||||
|
||||
private static final String NO_WARNINGS = "No warnings.";
|
||||
private static final String CONSTRUCTOR =
|
||||
"src/test/SampleHandler.java:2: Error: This ControllerChangeHandler needs to have a public default constructor (test.SampleHandler) [ValidControllerChangeHandler]\n"
|
||||
+ "public class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ "^\n"
|
||||
+ "1 errors, 0 warnings\n";
|
||||
private static final String PRIVATE_CLASS_ERROR =
|
||||
"src/test/SampleHandler.java:2: Error: This ControllerChangeHandler class should be public (test.SampleHandler) [ValidControllerChangeHandler]\n"
|
||||
+ "private class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ "^\n"
|
||||
+ "1 errors, 0 warnings\n";
|
||||
|
||||
public void testWithNoConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(NO_WARNINGS);
|
||||
}
|
||||
|
||||
public void testWithEmptyConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ " public SampleHandler() { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(NO_WARNINGS);
|
||||
}
|
||||
|
||||
public void testWithInvalidConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ " public SampleHandler(int number) { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(CONSTRUCTOR);
|
||||
}
|
||||
|
||||
public void testWithEmptyAndInvalidConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ " public SampleHandler() { }\n"
|
||||
+ " public SampleHandler(int number) { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(NO_WARNINGS);
|
||||
}
|
||||
|
||||
public void testWithPrivateConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ " private SampleHandler() { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(CONSTRUCTOR);
|
||||
}
|
||||
|
||||
public void testWithPrivateClass() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "private class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||
+ " public SampleHandler() { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(PRIVATE_CLASS_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Detector getDetector() {
|
||||
return new ControllerChangeHandlerIssueDetector();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Issue> getIssues() {
|
||||
return Collections.singletonList(ControllerChangeHandlerIssueDetector.ISSUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowCompilationErrors() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package com.bluelinelabs.conductor.lint;
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.LintDetectorTest;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
public class ControllerDetectorTest extends LintDetectorTest {
|
||||
|
||||
private static final String NO_WARNINGS = "No warnings.";
|
||||
private static final String CONSTRUCTOR_ERROR =
|
||||
"src/test/SampleController.java:2: Error: This Controller needs to have either a public default constructor or a public single-argument constructor that takes a Bundle. (test.SampleController) [ValidController]\n"
|
||||
+ "public class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ "^\n"
|
||||
+ "1 errors, 0 warnings\n";
|
||||
private static final String CLASS_ERROR =
|
||||
"src/test/SampleController.java:2: Error: This Controller class should be public (test.SampleController) [ValidController]\n"
|
||||
+ "private class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ "^\n"
|
||||
+ "1 errors, 0 warnings\n";
|
||||
|
||||
public void testWithNoConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(NO_WARNINGS);
|
||||
}
|
||||
|
||||
public void testWithEmptyConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ " public SampleController() { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(NO_WARNINGS);
|
||||
}
|
||||
|
||||
public void testWithInvalidConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ " public SampleController(int number) { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(CONSTRUCTOR_ERROR);
|
||||
}
|
||||
|
||||
public void testWithEmptyAndInvalidConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ " public SampleController() { }\n"
|
||||
+ " public SampleController(int number) { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(NO_WARNINGS);
|
||||
}
|
||||
|
||||
public void testWithPrivateConstructor() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "public class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ " private SampleController() { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(CONSTRUCTOR_ERROR);
|
||||
}
|
||||
|
||||
public void testWithPrivateClass() throws Exception {
|
||||
@Language("JAVA") String source = ""
|
||||
+ "package test;\n"
|
||||
+ "private class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||
+ " public SampleController() { }\n"
|
||||
+ "}";
|
||||
assertThat(lintProject(java(source))).isEqualTo(CLASS_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Detector getDetector() {
|
||||
return new ControllerIssueDetector();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Issue> getIssues() {
|
||||
return Collections.singletonList(ControllerIssueDetector.ISSUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowCompilationErrors() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,6 @@ android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
@@ -26,7 +22,6 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile rootProject.ext.rxJava
|
||||
compile rootProject.ext.rxAndroid
|
||||
compile rootProject.ext.rxLifecycle
|
||||
compile rootProject.ext.rxLifecycleAndroid
|
||||
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CheckResult;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.bluelinelabs.conductor.RestoreViewOnCreateController;
|
||||
import com.trello.rxlifecycle.LifecycleProvider;
|
||||
import com.trello.rxlifecycle.LifecycleTransformer;
|
||||
import com.trello.rxlifecycle.RxLifecycle;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.subjects.BehaviorSubject;
|
||||
|
||||
/**
|
||||
* A base {@link RestoreViewOnCreateController} that can be used to expose lifecycle events using RxJava
|
||||
*/
|
||||
public abstract class RxRestoreViewOnCreateController extends RestoreViewOnCreateController implements LifecycleProvider<ControllerEvent> {
|
||||
|
||||
private final BehaviorSubject<ControllerEvent> lifecycleSubject;
|
||||
|
||||
public RxRestoreViewOnCreateController() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public RxRestoreViewOnCreateController(Bundle args) {
|
||||
super(args);
|
||||
lifecycleSubject = ControllerLifecycleSubjectHelper.create(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
@CheckResult
|
||||
public final Observable<ControllerEvent> lifecycle() {
|
||||
return lifecycleSubject.asObservable();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
apply from: rootProject.file('gradle-mvn-push.gradle')
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile rootProject.ext.rxJava2
|
||||
compile rootProject.ext.rxLifecycle2
|
||||
compile rootProject.ext.rxLifecycleAndroid2
|
||||
|
||||
compile project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-rxlifecycle2'
|
||||
@@ -0,0 +1,3 @@
|
||||
POM_NAME=Conductor RxLifecycle2 Extensions
|
||||
POM_ARTIFACT_ID=conductor-rxlifecycle2
|
||||
POM_PACKAGING=aar
|
||||
@@ -0,0 +1,4 @@
|
||||
<manifest package="com.bluelinelabs.conductor.rxlifecycle2">
|
||||
<application />
|
||||
</manifest>
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
public enum ControllerEvent {
|
||||
|
||||
CREATE,
|
||||
CREATE_VIEW,
|
||||
ATTACH,
|
||||
DETACH,
|
||||
DESTROY_VIEW,
|
||||
DESTROY
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
||||
public class ControllerLifecycleSubjectHelper {
|
||||
private ControllerLifecycleSubjectHelper() {
|
||||
}
|
||||
|
||||
public static BehaviorSubject<ControllerEvent> create(Controller controller){
|
||||
final BehaviorSubject<ControllerEvent> subject = BehaviorSubject.createDefault(ControllerEvent.CREATE);
|
||||
|
||||
controller.addLifecycleListener(new Controller.LifecycleListener() {
|
||||
@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 preDestroy(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.DESTROY);
|
||||
}
|
||||
});
|
||||
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CheckResult;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.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);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import android.support.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 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.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CheckResult;
|
||||
import android.support.annotation.NonNull;
|
||||
import com.bluelinelabs.conductor.RestoreViewOnCreateController;
|
||||
import com.trello.rxlifecycle2.LifecycleProvider;
|
||||
import com.trello.rxlifecycle2.LifecycleTransformer;
|
||||
import com.trello.rxlifecycle2.RxLifecycle;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
||||
public abstract class RxRestoreViewOnCreateController extends RestoreViewOnCreateController implements LifecycleProvider<ControllerEvent> {
|
||||
private final BehaviorSubject<ControllerEvent> lifecycleSubject;
|
||||
|
||||
public RxRestoreViewOnCreateController() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public RxRestoreViewOnCreateController(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);
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,6 @@ android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
|
||||
+50
-3
@@ -2,6 +2,7 @@ package com.bluelinelabs.conductor.support;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
@@ -12,16 +13,23 @@ import com.bluelinelabs.conductor.Router;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
|
||||
/**
|
||||
* @deprecated Use RouterPagerAdapter instead! This implementation was too limited and had too many
|
||||
* gotchas associated with it.
|
||||
*
|
||||
* An adapter for ViewPagers that will handle adding and removing Controllers
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
|
||||
private static final String KEY_SAVED_PAGES = "ControllerPagerAdapter.savedStates";
|
||||
private static final String KEY_SAVES_STATE = "ControllerPagerAdapter.savesState";
|
||||
private static final String KEY_VISIBLE_PAGE_IDS_KEYS = "ControllerPagerAdapter.visiblePageIds.keys";
|
||||
private static final String KEY_VISIBLE_PAGE_IDS_VALUES = "ControllerPagerAdapter.visiblePageIds.values";
|
||||
|
||||
private final Controller host;
|
||||
private boolean savesState;
|
||||
private SparseArray<Bundle> savedPages = new SparseArray<>();
|
||||
private SparseArray<String> visiblePageIds = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Creates a new ControllerPagerAdapter using the passed host.
|
||||
@@ -49,11 +57,17 @@ public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
final Controller controller;
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(getItem(position))
|
||||
.tag(name));
|
||||
controller = getItem(position);
|
||||
router.setRoot(RouterTransaction.with(controller).tag(name));
|
||||
} else {
|
||||
router.rebindIfNeeded();
|
||||
controller = router.getControllerWithTag(name);
|
||||
}
|
||||
|
||||
if (controller != null) {
|
||||
visiblePageIds.put(position, controller.getInstanceId());
|
||||
}
|
||||
|
||||
return router.getControllerWithTag(name);
|
||||
@@ -69,6 +83,8 @@ public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
savedPages.put(position, savedState);
|
||||
}
|
||||
|
||||
visiblePageIds.remove(position);
|
||||
|
||||
host.removeChildRouter(router);
|
||||
}
|
||||
|
||||
@@ -82,6 +98,16 @@ public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(KEY_SAVES_STATE, savesState);
|
||||
bundle.putSparseParcelableArray(KEY_SAVED_PAGES, savedPages);
|
||||
|
||||
int[] visiblePageIdsKeys = new int[visiblePageIds.size()];
|
||||
String[] visiblePageIdsValues = new String[visiblePageIds.size()];
|
||||
for (int i = 0; i < visiblePageIds.size(); i++) {
|
||||
visiblePageIdsKeys[i] = visiblePageIds.keyAt(i);
|
||||
visiblePageIdsValues[i] = visiblePageIds.valueAt(i);
|
||||
}
|
||||
bundle.putIntArray(KEY_VISIBLE_PAGE_IDS_KEYS, visiblePageIdsKeys);
|
||||
bundle.putStringArray(KEY_VISIBLE_PAGE_IDS_VALUES, visiblePageIdsValues);
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@@ -91,6 +117,27 @@ public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
if (state != null) {
|
||||
savesState = bundle.getBoolean(KEY_SAVES_STATE, false);
|
||||
savedPages = bundle.getSparseParcelableArray(KEY_SAVED_PAGES);
|
||||
|
||||
int[] visiblePageIdsKeys = bundle.getIntArray(KEY_VISIBLE_PAGE_IDS_KEYS);
|
||||
String[] visiblePageIdsValues = bundle.getStringArray(KEY_VISIBLE_PAGE_IDS_VALUES);
|
||||
visiblePageIds = new SparseArray<>(visiblePageIdsKeys.length);
|
||||
for (int i = 0; i < visiblePageIdsKeys.length; i++) {
|
||||
visiblePageIds.put(visiblePageIdsKeys[i], visiblePageIdsValues[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the already instantiated Controller in the specified position or {@code null} if
|
||||
* this position does not yet have a controller.
|
||||
*/
|
||||
@Nullable
|
||||
public Controller getController(int position) {
|
||||
String instanceId = visiblePageIds.get(position);
|
||||
if (instanceId != null) {
|
||||
return host.getRouter().getControllerWithInstanceId(instanceId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,4 +149,4 @@ public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
return viewId + ":" + id;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package com.bluelinelabs.conductor.support;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.Router;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An adapter for ViewPagers that uses Routers as pages
|
||||
*/
|
||||
public abstract class RouterPagerAdapter extends PagerAdapter {
|
||||
|
||||
private static final String KEY_SAVED_PAGES = "RouterPagerAdapter.savedStates";
|
||||
|
||||
private final Controller host;
|
||||
private SparseArray<Bundle> savedPages = new SparseArray<>();
|
||||
private SparseArray<Router> visibleRouters = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Creates a new RouterPagerAdapter using the passed host.
|
||||
*/
|
||||
public RouterPagerAdapter(Controller host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a router is instantiated. Here the router's root should be set if needed.
|
||||
*
|
||||
* @param router The router used for the page
|
||||
* @param position The page position to be instantiated.
|
||||
*/
|
||||
public abstract void configureRouter(Router router, int position);
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
final String name = makeRouterName(container.getId(), getItemId(position));
|
||||
|
||||
Router router = host.getChildRouter(container, name);
|
||||
if (!router.hasRootController()) {
|
||||
Bundle routerSavedState = savedPages.get(position);
|
||||
|
||||
if (routerSavedState != null) {
|
||||
router.restoreInstanceState(routerSavedState);
|
||||
}
|
||||
}
|
||||
|
||||
router.rebindIfNeeded();
|
||||
configureRouter(router, position);
|
||||
|
||||
visibleRouters.put(position, router);
|
||||
return router;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
Router router = (Router)object;
|
||||
|
||||
Bundle savedState = new Bundle();
|
||||
router.saveInstanceState(savedState);
|
||||
savedPages.put(position, savedState);
|
||||
|
||||
host.removeChildRouter(router);
|
||||
|
||||
visibleRouters.remove(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
Router router = (Router)object;
|
||||
final List<RouterTransaction> backstack = router.getBackstack();
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (transaction.controller().getView() == view) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable saveState() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSparseParcelableArray(KEY_SAVED_PAGES, savedPages);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState(Parcelable state, ClassLoader loader) {
|
||||
Bundle bundle = (Bundle)state;
|
||||
if (state != null) {
|
||||
savedPages = bundle.getSparseParcelableArray(KEY_SAVED_PAGES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the already instantiated Router in the specified position or {@code null} if there
|
||||
* is no router associated with this position.
|
||||
*/
|
||||
@Nullable
|
||||
public Router getRouter(int position) {
|
||||
return visibleRouters.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
private static String makeRouterName(int viewId, long id) {
|
||||
return viewId + ":" + id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,10 +14,6 @@ android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
|
||||
@@ -4,16 +4,19 @@ import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener;
|
||||
import com.bluelinelabs.conductor.internal.LifecycleHandler;
|
||||
import com.bluelinelabs.conductor.internal.TransactionIndexer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ActivityHostedRouter extends Router {
|
||||
|
||||
private LifecycleHandler lifecycleHandler;
|
||||
private final TransactionIndexer transactionIndexer = new TransactionIndexer();
|
||||
|
||||
public final void setHost(@NonNull LifecycleHandler lifecycleHandler, @NonNull ViewGroup container) {
|
||||
if (this.lifecycleHandler != lifecycleHandler || this.container != container) {
|
||||
@@ -31,12 +34,26 @@ public class ActivityHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInstanceState(@NonNull Bundle outState) {
|
||||
super.saveInstanceState(outState);
|
||||
|
||||
transactionIndexer.saveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
super.restoreInstanceState(savedInstanceState);
|
||||
|
||||
transactionIndexer.restoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override @Nullable
|
||||
public Activity getActivity() {
|
||||
return lifecycleHandler != null ? lifecycleHandler.getLifecycleActivity() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
public void onActivityDestroyed(@NonNull Activity activity) {
|
||||
super.onActivityDestroyed(activity);
|
||||
lifecycleHandler = null;
|
||||
}
|
||||
@@ -49,37 +66,37 @@ public class ActivityHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
lifecycleHandler.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
void startActivity(Intent intent) {
|
||||
void startActivity(@NonNull Intent intent) {
|
||||
lifecycleHandler.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
void startActivityForResult(String instanceId, Intent intent, int requestCode) {
|
||||
void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode) {
|
||||
lifecycleHandler.startActivityForResult(instanceId, intent, requestCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
void startActivityForResult(String instanceId, Intent intent, int requestCode, Bundle options) {
|
||||
void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode, @Nullable Bundle options) {
|
||||
lifecycleHandler.startActivityForResult(instanceId, intent, requestCode, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerForActivityResult(String instanceId, int requestCode) {
|
||||
void registerForActivityResult(@NonNull String instanceId, int requestCode) {
|
||||
lifecycleHandler.registerForActivityResult(instanceId, requestCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
void unregisterForActivityResults(String instanceId) {
|
||||
void unregisterForActivityResults(@NonNull String instanceId) {
|
||||
lifecycleHandler.unregisterForActivityResults(instanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
void requestPermissions(String instanceId, @NonNull String[] permissions, int requestCode) {
|
||||
void requestPermissions(@NonNull String instanceId, @NonNull String[] permissions, int requestCode) {
|
||||
lifecycleHandler.requestPermissions(instanceId, permissions, requestCode);
|
||||
}
|
||||
|
||||
@@ -88,13 +105,18 @@ public class ActivityHostedRouter extends Router {
|
||||
return lifecycleHandler != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
List<Router> getSiblingRouters() {
|
||||
return lifecycleHandler.getRouters();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
Router getRootRouter() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override @Nullable
|
||||
TransactionIndexer getTransactionIndexer() {
|
||||
return transactionIndexer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
@@ -13,34 +15,37 @@ class Backstack implements Iterable<RouterTransaction> {
|
||||
|
||||
private static final String KEY_ENTRIES = "Backstack.entries";
|
||||
|
||||
private final Deque<RouterTransaction> backStack = new ArrayDeque<>();
|
||||
private final Deque<RouterTransaction> backstack = new ArrayDeque<>();
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean isEmpty() {
|
||||
return backStack.isEmpty();
|
||||
return backstack.isEmpty();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return backStack.size();
|
||||
return backstack.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RouterTransaction root() {
|
||||
return backStack.size() > 0 ? backStack.getLast() : null;
|
||||
return backstack.size() > 0 ? backstack.getLast() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
public Iterator<RouterTransaction> iterator() {
|
||||
return backStack.iterator();
|
||||
return backstack.iterator();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Iterator<RouterTransaction> reverseIterator() {
|
||||
return backStack.descendingIterator();
|
||||
return backstack.descendingIterator();
|
||||
}
|
||||
|
||||
public List<RouterTransaction> popTo(RouterTransaction transaction) {
|
||||
@NonNull
|
||||
public List<RouterTransaction> popTo(@NonNull RouterTransaction transaction) {
|
||||
List<RouterTransaction> popped = new ArrayList<>();
|
||||
if (backStack.contains(transaction)) {
|
||||
while (backStack.peek() != transaction) {
|
||||
if (backstack.contains(transaction)) {
|
||||
while (backstack.peek() != transaction) {
|
||||
RouterTransaction poppedTransaction = pop();
|
||||
popped.add(poppedTransaction);
|
||||
}
|
||||
@@ -50,24 +55,27 @@ class Backstack implements Iterable<RouterTransaction> {
|
||||
return popped;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public RouterTransaction pop() {
|
||||
RouterTransaction popped = backStack.pop();
|
||||
RouterTransaction popped = backstack.pop();
|
||||
popped.controller.destroy();
|
||||
return popped;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RouterTransaction peek() {
|
||||
return backStack.peek();
|
||||
return backstack.peek();
|
||||
}
|
||||
|
||||
public void remove(RouterTransaction transaction) {
|
||||
backStack.removeFirstOccurrence(transaction);
|
||||
public void remove(@NonNull RouterTransaction transaction) {
|
||||
backstack.removeFirstOccurrence(transaction);
|
||||
}
|
||||
|
||||
public void push(RouterTransaction transaction) {
|
||||
backStack.push(transaction);
|
||||
public void push(@NonNull RouterTransaction transaction) {
|
||||
backstack.push(transaction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<RouterTransaction> popAll() {
|
||||
List<RouterTransaction> list = new ArrayList<>();
|
||||
while (!isEmpty()) {
|
||||
@@ -76,8 +84,8 @@ class Backstack implements Iterable<RouterTransaction> {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setBackstack(List<RouterTransaction> backstack) {
|
||||
for (RouterTransaction existingTransaction : backStack) {
|
||||
public void setBackstack(@NonNull List<RouterTransaction> backstack) {
|
||||
for (RouterTransaction existingTransaction : this.backstack) {
|
||||
boolean contains = false;
|
||||
for (RouterTransaction newTransaction : backstack) {
|
||||
if (existingTransaction.controller == newTransaction.controller) {
|
||||
@@ -91,27 +99,27 @@ class Backstack implements Iterable<RouterTransaction> {
|
||||
}
|
||||
}
|
||||
|
||||
backStack.clear();
|
||||
this.backstack.clear();
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
backStack.push(transaction);
|
||||
this.backstack.push(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveInstanceState(Bundle outState) {
|
||||
ArrayList<Bundle> entryBundles = new ArrayList<>(backStack.size());
|
||||
for (RouterTransaction entry : backStack) {
|
||||
public 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);
|
||||
}
|
||||
|
||||
public void restoreInstanceState(Bundle savedInstanceState) {
|
||||
public 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));
|
||||
backstack.push(new RouterTransaction(transactionBundle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.bluelinelabs.conductor;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
@@ -42,12 +44,12 @@ public class ChangeHandlerFrameLayout extends FrameLayout implements ControllerC
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeStarted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
|
||||
public void onChangeStarted(@Nullable Controller to, @Nullable Controller from, boolean isPush, @NonNull ViewGroup container, @NonNull ControllerChangeHandler handler) {
|
||||
inProgressTransactionCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeCompleted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
|
||||
public void onChangeCompleted(@Nullable Controller to, @Nullable Controller from, boolean isPush, @NonNull ViewGroup container, @NonNull ControllerChangeHandler handler) {
|
||||
inProgressTransactionCount--;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.bluelinelabs.conductor;
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.internal.LifecycleHandler;
|
||||
@@ -26,7 +28,8 @@ public final class Conductor {
|
||||
* for restoring the Router's state if possible.
|
||||
* @return A fully configured {@link Router} instance for use with this Activity/ViewGroup pair.
|
||||
*/
|
||||
public static Router attachRouter(@NonNull Activity activity, @NonNull ViewGroup container, Bundle savedInstanceState) {
|
||||
@NonNull @UiThread
|
||||
public static Router attachRouter(@NonNull Activity activity, @NonNull ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
LifecycleHandler lifecycleHandler = LifecycleHandler.install(activity);
|
||||
|
||||
Router router = lifecycleHandler.getRouter(container, savedInstanceState);
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -17,20 +18,19 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener;
|
||||
import com.bluelinelabs.conductor.internal.ClassUtils;
|
||||
import com.bluelinelabs.conductor.internal.RouterRequiringFunc;
|
||||
import com.bluelinelabs.conductor.internal.ViewAttachHandler;
|
||||
import com.bluelinelabs.conductor.internal.ViewAttachHandler.ViewAttachListener;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -74,32 +74,21 @@ public abstract class Controller {
|
||||
private String instanceId;
|
||||
private String targetInstanceId;
|
||||
private boolean needsAttach;
|
||||
private boolean attachedToUnownedParent;
|
||||
private boolean hasSavedViewState;
|
||||
private boolean isDetachFrozen;
|
||||
private ControllerChangeHandler overriddenPushHandler;
|
||||
private ControllerChangeHandler overriddenPopHandler;
|
||||
private RetainViewMode retainViewMode = RetainViewMode.RELEASE_DETACH;
|
||||
private OnAttachStateChangeListener onAttachStateChangeListener;
|
||||
private ViewAttachHandler viewAttachHandler;
|
||||
private final List<ControllerHostedRouter> childRouters = new ArrayList<>();
|
||||
private final List<LifecycleListener> lifecycleListeners = new ArrayList<>();
|
||||
private final ArrayList<String> requestedPermissions = new ArrayList<>();
|
||||
private final ArrayList<RouterRequiringFunc> onRouterSetListeners = new ArrayList<>();
|
||||
private final Deque<Controller> childBackstack = new ArrayDeque<>();
|
||||
private WeakReference<View> destroyedView;
|
||||
|
||||
private final ControllerChangeListener childRouterChangeListener = new ControllerChangeListener() {
|
||||
@Override
|
||||
public void onChangeStarted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
|
||||
if (isPush) {
|
||||
onChildControllerPushed(to);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeCompleted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) { }
|
||||
};
|
||||
|
||||
static Controller newInstance(Bundle bundle) {
|
||||
@NonNull
|
||||
static Controller newInstance(@NonNull Bundle bundle) {
|
||||
final String className = bundle.getString(KEY_CLASS_NAME);
|
||||
//noinspection ConstantConditions
|
||||
Constructor[] constructors = ClassUtils.classForName(className, false).getConstructors();
|
||||
@@ -133,8 +122,8 @@ public abstract class Controller {
|
||||
*
|
||||
* @param args Any arguments that need to be retained.
|
||||
*/
|
||||
protected Controller(Bundle args) {
|
||||
this.args = args;
|
||||
protected Controller(@Nullable Bundle args) {
|
||||
this.args = args != null ? args : new Bundle();
|
||||
instanceId = UUID.randomUUID().toString();
|
||||
ensureRequiredConstructor();
|
||||
}
|
||||
@@ -162,11 +151,50 @@ public abstract class Controller {
|
||||
/**
|
||||
* Returns any arguments that were set in this Controller's constructor
|
||||
*/
|
||||
@NonNull
|
||||
public Bundle getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public final Router getChildRouter(@NonNull ViewGroup container, String tag) {
|
||||
/**
|
||||
* Retrieves the child {@link Router} for the given container. If no child router for this container
|
||||
* exists yet, it will be created.
|
||||
*
|
||||
* @param container The ViewGroup that hosts the child Router
|
||||
*/
|
||||
@NonNull
|
||||
public final Router getChildRouter(@NonNull ViewGroup container) {
|
||||
return getChildRouter(container, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child {@link Router} for the given container/tag combination. If no child router for
|
||||
* this container exists yet, it will be created. 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).
|
||||
*
|
||||
* @param container The ViewGroup that hosts the child Router
|
||||
* @param tag The router's tag or {@code null} if none is needed
|
||||
*/
|
||||
@NonNull
|
||||
public final Router getChildRouter(@NonNull ViewGroup container, @Nullable String tag) {
|
||||
//noinspection ConstantConditions
|
||||
return getChildRouter(container, tag, 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.
|
||||
*/
|
||||
@Nullable
|
||||
public final Router getChildRouter(@NonNull ViewGroup container, @Nullable String tag, boolean createIfNeeded) {
|
||||
@IdRes final int containerId = container.getId();
|
||||
|
||||
ControllerHostedRouter childRouter = null;
|
||||
@@ -178,22 +206,28 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
if (childRouter == null) {
|
||||
childRouter = new ControllerHostedRouter(container.getId(), tag);
|
||||
monitorChildRouter(childRouter);
|
||||
childRouter.setHost(this, container);
|
||||
childRouters.add(childRouter);
|
||||
if (createIfNeeded) {
|
||||
childRouter = new ControllerHostedRouter(container.getId(), tag);
|
||||
childRouter.setHost(this, container);
|
||||
childRouters.add(childRouter);
|
||||
}
|
||||
} else if (!childRouter.hasHost()) {
|
||||
childRouter.setHost(this, container);
|
||||
monitorChildRouter(childRouter);
|
||||
childRouter.rebindIfNeeded();
|
||||
}
|
||||
|
||||
return childRouter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a child {@link Router} from this Controller. When removed, all Controllers currently managed by
|
||||
* the {@link Router} will be destroyed.
|
||||
*
|
||||
* @param childRouter The router to be removed
|
||||
*/
|
||||
public final void removeChildRouter(@NonNull Router childRouter) {
|
||||
if ((childRouter instanceof ControllerHostedRouter) && childRouters.remove(childRouter)) {
|
||||
childRouter.destroy();
|
||||
childRouter.destroy(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,38 +253,48 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this Controller's View, if available.
|
||||
* Return this Controller's View or {@code null} if it has not yet been created or has been
|
||||
* destroyed.
|
||||
*/
|
||||
@Nullable
|
||||
public final View getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host Activity of this Controller's {@link Router}
|
||||
* Returns the host Activity of this Controller's {@link Router} or {@code null} if this
|
||||
* Controller has not yet been attached to an Activity or if the Activity has been destroyed.
|
||||
*/
|
||||
@Nullable
|
||||
public final Activity getActivity() {
|
||||
return router.getActivity();
|
||||
return router != null ? router.getActivity() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Resources from the host Activity
|
||||
* Returns the Resources from the host Activity or {@code null} if this Controller has not
|
||||
* yet been attached to an Activity or if the Activity has been destroyed.
|
||||
*/
|
||||
@Nullable
|
||||
public final Resources getResources() {
|
||||
Activity activity = getActivity();
|
||||
return activity != null ? activity.getResources() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Application Context derived from the host Activity
|
||||
* Returns the Application Context derived from the host Activity or {@code null} if this Controller
|
||||
* has not yet been attached to an Activity or if the Activity has been destroyed.
|
||||
*/
|
||||
@Nullable
|
||||
public final Context getApplicationContext() {
|
||||
Activity activity = getActivity();
|
||||
return activity != null ? activity.getApplicationContext() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this Controller's parent Controller if it is a child Controller.
|
||||
* Returns this Controller's parent Controller if it is a child Controller or {@code null} if
|
||||
* it has no parent.
|
||||
*/
|
||||
@Nullable
|
||||
public final Controller getParentController() {
|
||||
return parentController;
|
||||
}
|
||||
@@ -259,17 +303,19 @@ public abstract class Controller {
|
||||
* Returns this Controller's instance ID, which is generated when the instance is created and
|
||||
* retained across restarts.
|
||||
*/
|
||||
@NonNull
|
||||
public final String getInstanceId() {
|
||||
return instanceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Controller with the given instance id, if available.
|
||||
* May return the controller itself or a matching descendant
|
||||
* Returns the Controller with the given instance id or {@code null} if no such Controller
|
||||
* exists. May return the Controller itself or a matching descendant
|
||||
*
|
||||
* @param instanceId The instance ID being searched for
|
||||
* @return The matching Controller, if one exists
|
||||
*/
|
||||
final Controller findController(String instanceId) {
|
||||
@Nullable
|
||||
final Controller findController(@NonNull String instanceId) {
|
||||
if (this.instanceId.equals(instanceId)) {
|
||||
return this;
|
||||
}
|
||||
@@ -286,6 +332,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Returns all of this Controller's child Routers
|
||||
*/
|
||||
@NonNull
|
||||
public final List<Router> getChildRouters() {
|
||||
List<Router> routers = new ArrayList<>();
|
||||
for (Router router : childRouters) {
|
||||
@@ -301,7 +348,7 @@ public abstract class Controller {
|
||||
*
|
||||
* @param target The Controller that is the target of this one.
|
||||
*/
|
||||
public void setTargetController(Controller target) {
|
||||
public void setTargetController(@Nullable Controller target) {
|
||||
if (targetInstanceId != null) {
|
||||
throw new RuntimeException("Target controller already set. A controller's target may only be set once.");
|
||||
}
|
||||
@@ -310,10 +357,12 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target Controller that was set with the {@link #setTargetController(Controller)} method
|
||||
* Returns the target Controller that was set with the {@link #setTargetController(Controller)}
|
||||
* method or {@code null} if this Controller has no target.
|
||||
*
|
||||
* @return This Controller's target
|
||||
*/
|
||||
@Nullable
|
||||
public final Controller getTargetController() {
|
||||
if (targetInstanceId != null) {
|
||||
return router.getRootRouter().getControllerWithInstanceId(targetInstanceId);
|
||||
@@ -327,7 +376,7 @@ public abstract class Controller {
|
||||
*
|
||||
* @param view The View to which this Controller should be bound.
|
||||
*/
|
||||
protected void onDestroyView(View view) { }
|
||||
protected void onDestroyView(@NonNull View view) { }
|
||||
|
||||
/**
|
||||
* Called when this Controller begins the process of being swapped in or out of the host view.
|
||||
@@ -367,22 +416,22 @@ public abstract class Controller {
|
||||
/**
|
||||
* Called when this Controller's host Activity is started
|
||||
*/
|
||||
protected void onActivityStarted(Activity activity) { }
|
||||
protected void onActivityStarted(@NonNull Activity activity) { }
|
||||
|
||||
/**
|
||||
* Called when this Controller's host Activity is resumed
|
||||
*/
|
||||
protected void onActivityResumed(Activity activity) { }
|
||||
protected void onActivityResumed(@NonNull Activity activity) { }
|
||||
|
||||
/**
|
||||
* Called when this Controller's host Activity is paused
|
||||
*/
|
||||
protected void onActivityPaused(Activity activity) { }
|
||||
protected void onActivityPaused(@NonNull Activity activity) { }
|
||||
|
||||
/**
|
||||
* Called when this Controller's host Activity is stopped
|
||||
*/
|
||||
protected void onActivityStopped(Activity activity) { }
|
||||
protected void onActivityStopped(@NonNull Activity activity) { }
|
||||
|
||||
/**
|
||||
* Called to save this Controller's View state. As Views can be detached and destroyed as part of the
|
||||
@@ -421,7 +470,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Calls startActivity(Intent) from this Controller's host Activity.
|
||||
*/
|
||||
public final void startActivity(final Intent intent) {
|
||||
public final void startActivity(@NonNull final Intent intent) {
|
||||
executeWithRouter(new RouterRequiringFunc() {
|
||||
@Override public void execute() { router.startActivity(intent); }
|
||||
});
|
||||
@@ -430,7 +479,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Calls startActivityForResult(Intent, int) from this Controller's host Activity.
|
||||
*/
|
||||
public final void startActivityForResult(final Intent intent, final int requestCode) {
|
||||
public final void startActivityForResult(@NonNull final Intent intent, final int requestCode) {
|
||||
executeWithRouter(new RouterRequiringFunc() {
|
||||
@Override public void execute() { router.startActivityForResult(instanceId, intent, requestCode); }
|
||||
});
|
||||
@@ -439,7 +488,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Calls startActivityForResult(Intent, int, Bundle) from this Controller's host Activity.
|
||||
*/
|
||||
public final void startActivityForResult(final Intent intent, final int requestCode, final Bundle options) {
|
||||
public final void startActivityForResult(@NonNull final Intent intent, final int requestCode, @Nullable final Bundle options) {
|
||||
executeWithRouter(new RouterRequiringFunc() {
|
||||
@Override public void execute() { router.startActivityForResult(instanceId, intent, requestCode, options); }
|
||||
});
|
||||
@@ -465,7 +514,7 @@ public abstract class Controller {
|
||||
* @param resultCode The resultCode that was returned to the host Activity's onActivityResult method
|
||||
* @param data The data Intent that was returned to the host Activity's onActivityResult method
|
||||
*/
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) { }
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { }
|
||||
|
||||
/**
|
||||
* Calls requestPermission(String[], int) from this Controller's host Activity. Results for this request,
|
||||
@@ -506,9 +555,22 @@ public abstract class Controller {
|
||||
* @return True if this Controller has consumed the back button press, otherwise false
|
||||
*/
|
||||
public boolean handleBack() {
|
||||
Iterator<Controller> childIterator = childBackstack.descendingIterator();
|
||||
while (childIterator.hasNext()) {
|
||||
Controller childController = childIterator.next();
|
||||
List<RouterTransaction> childTransactions = new ArrayList<>();
|
||||
|
||||
for (ControllerHostedRouter childRouter : childRouters) {
|
||||
childTransactions.addAll(childRouter.getBackstack());
|
||||
}
|
||||
|
||||
Collections.sort(childTransactions, new Comparator<RouterTransaction>() {
|
||||
@Override
|
||||
public int compare(RouterTransaction o1, RouterTransaction o2) {
|
||||
return o2.transactionIndex - o1.transactionIndex;
|
||||
}
|
||||
});
|
||||
|
||||
for (RouterTransaction transaction : childTransactions) {
|
||||
Controller childController = transaction.controller;
|
||||
|
||||
if (childController.isAttached() && childController.getRouter().handleBack()) {
|
||||
return true;
|
||||
}
|
||||
@@ -522,7 +584,7 @@ public abstract class Controller {
|
||||
*
|
||||
* @param lifecycleListener The listener
|
||||
*/
|
||||
public void addLifecycleListener(LifecycleListener lifecycleListener) {
|
||||
public void addLifecycleListener(@NonNull LifecycleListener lifecycleListener) {
|
||||
if (!lifecycleListeners.contains(lifecycleListener)) {
|
||||
lifecycleListeners.add(lifecycleListener);
|
||||
}
|
||||
@@ -533,13 +595,14 @@ public abstract class Controller {
|
||||
*
|
||||
* @param lifecycleListener The listener to be removed
|
||||
*/
|
||||
public void removeLifecycleListener(LifecycleListener lifecycleListener) {
|
||||
public void removeLifecycleListener(@NonNull LifecycleListener lifecycleListener) {
|
||||
lifecycleListeners.remove(lifecycleListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this Controller's {@link RetainViewMode}. Defaults to {@link RetainViewMode#RELEASE_DETACH}.
|
||||
*/
|
||||
@NonNull
|
||||
public RetainViewMode getRetainViewMode() {
|
||||
return retainViewMode;
|
||||
}
|
||||
@@ -548,8 +611,8 @@ public abstract class Controller {
|
||||
* Sets this Controller's {@link RetainViewMode}, which will influence when its view will be released.
|
||||
* This is useful when a Controller's view hierarchy is expensive to tear down and rebuild.
|
||||
*/
|
||||
public void setRetainViewMode(RetainViewMode retainViewMode) {
|
||||
this.retainViewMode = retainViewMode;
|
||||
public void setRetainViewMode(@NonNull RetainViewMode retainViewMode) {
|
||||
this.retainViewMode = retainViewMode != null ? retainViewMode : RetainViewMode.RELEASE_DETACH;
|
||||
if (this.retainViewMode == RetainViewMode.RELEASE_DETACH && !attached) {
|
||||
removeViewReference();
|
||||
}
|
||||
@@ -559,6 +622,7 @@ public abstract class Controller {
|
||||
* Returns the {@link ControllerChangeHandler} that should be used for pushing this Controller, or null
|
||||
* if the handler from the {@link RouterTransaction} should be used instead.
|
||||
*/
|
||||
@Nullable
|
||||
public final ControllerChangeHandler getOverriddenPushHandler() {
|
||||
return overriddenPushHandler;
|
||||
}
|
||||
@@ -567,7 +631,7 @@ public abstract class Controller {
|
||||
* Overrides the {@link ControllerChangeHandler} that should be used for pushing this Controller. If this is a
|
||||
* non-null value, it will be used instead of the handler from the {@link RouterTransaction}.
|
||||
*/
|
||||
public void overridePushHandler(ControllerChangeHandler overriddenPushHandler) {
|
||||
public void overridePushHandler(@Nullable ControllerChangeHandler overriddenPushHandler) {
|
||||
this.overriddenPushHandler = overriddenPushHandler;
|
||||
}
|
||||
|
||||
@@ -575,6 +639,7 @@ public abstract class Controller {
|
||||
* Returns the {@link ControllerChangeHandler} that should be used for popping this Controller, or null
|
||||
* if the handler from the {@link RouterTransaction} should be used instead.
|
||||
*/
|
||||
@Nullable
|
||||
public ControllerChangeHandler getOverriddenPopHandler() {
|
||||
return overriddenPopHandler;
|
||||
}
|
||||
@@ -583,7 +648,7 @@ public abstract class Controller {
|
||||
* Overrides the {@link ControllerChangeHandler} that should be used for popping this Controller. If this is a
|
||||
* non-null value, it will be used instead of the handler from the {@link RouterTransaction}.
|
||||
*/
|
||||
public void overridePopHandler(ControllerChangeHandler overriddenPopHandler) {
|
||||
public void overridePopHandler(@Nullable ControllerChangeHandler overriddenPopHandler) {
|
||||
this.overriddenPopHandler = overriddenPopHandler;
|
||||
}
|
||||
|
||||
@@ -627,7 +692,7 @@ public abstract class Controller {
|
||||
* @param menu The menu into which your options should be placed.
|
||||
* @param inflater The inflater that can be used to inflate your menu items.
|
||||
*/
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { }
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { }
|
||||
|
||||
/**
|
||||
* Prepare the screen's options menu to be displayed. This is called directly before showing the
|
||||
@@ -635,7 +700,7 @@ public abstract class Controller {
|
||||
*
|
||||
* @param menu The menu that will be displayed
|
||||
*/
|
||||
public void onPrepareOptionsMenu(Menu menu) { }
|
||||
public void onPrepareOptionsMenu(@NonNull Menu menu) { }
|
||||
|
||||
/**
|
||||
* Called when an option menu item has been selected by the user.
|
||||
@@ -643,7 +708,7 @@ public abstract class Controller {
|
||||
* @param item The selected item.
|
||||
* @return True if this event has been consumed, false if it has not.
|
||||
*/
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -695,40 +760,54 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
final void activityStarted(Activity activity) {
|
||||
final void activityStarted(@NonNull Activity activity) {
|
||||
if (viewAttachHandler != null) {
|
||||
viewAttachHandler.onActivityStarted();
|
||||
}
|
||||
|
||||
onActivityStarted(activity);
|
||||
}
|
||||
|
||||
final void activityResumed(Activity activity) {
|
||||
final void activityResumed(@NonNull Activity activity) {
|
||||
if (!attached && view != null && viewIsAttached) {
|
||||
attach(view);
|
||||
} else if (attached) {
|
||||
needsAttach = false;
|
||||
hasSavedViewState = false;
|
||||
}
|
||||
|
||||
onActivityResumed(activity);
|
||||
}
|
||||
|
||||
final void activityPaused(Activity activity) {
|
||||
final void activityPaused(@NonNull Activity activity) {
|
||||
onActivityPaused(activity);
|
||||
}
|
||||
|
||||
final void activityStopped(Activity activity) {
|
||||
final void activityStopped(@NonNull Activity activity) {
|
||||
if (viewAttachHandler != null) {
|
||||
viewAttachHandler.onActivityStopped();
|
||||
}
|
||||
onActivityStopped(activity);
|
||||
}
|
||||
|
||||
final void activityDestroyed(boolean isChangingConfigurations) {
|
||||
if (isChangingConfigurations) {
|
||||
detach(view, true);
|
||||
detach(view, true, false);
|
||||
} else {
|
||||
destroy(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void attach(@NonNull View view) {
|
||||
attachedToUnownedParent = router == null || view.getParent() != router.container;
|
||||
if (attachedToUnownedParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasSavedViewState = false;
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preAttach(this, view);
|
||||
}
|
||||
|
||||
@@ -741,20 +820,24 @@ public abstract class Controller {
|
||||
router.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postAttach(this, view);
|
||||
}
|
||||
}
|
||||
|
||||
void detach(@NonNull View view, boolean forceViewRefRemoval) {
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.prepareForHostDetach();
|
||||
void detach(@NonNull View view, boolean forceViewRefRemoval, boolean blockViewRefRemoval) {
|
||||
if (!attachedToUnownedParent) {
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.prepareForHostDetach();
|
||||
}
|
||||
}
|
||||
|
||||
final boolean removeViewRef = forceViewRefRemoval || retainViewMode == RetainViewMode.RELEASE_DETACH || isBeingDestroyed;
|
||||
final boolean removeViewRef = !blockViewRefRemoval && (forceViewRefRemoval || retainViewMode == RetainViewMode.RELEASE_DETACH || isBeingDestroyed);
|
||||
|
||||
if (attached) {
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preDetach(this, view);
|
||||
}
|
||||
|
||||
@@ -765,7 +848,8 @@ public abstract class Controller {
|
||||
router.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDetach(this, view);
|
||||
}
|
||||
}
|
||||
@@ -781,13 +865,15 @@ public abstract class Controller {
|
||||
saveViewState(view);
|
||||
}
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preDestroyView(this, view);
|
||||
}
|
||||
|
||||
onDestroyView(view);
|
||||
|
||||
view.removeOnAttachStateChangeListener(onAttachStateChangeListener);
|
||||
viewAttachHandler.unregisterAttachListener(view);
|
||||
viewAttachHandler = null;
|
||||
viewIsAttached = false;
|
||||
|
||||
if (isBeingDestroyed) {
|
||||
@@ -795,7 +881,8 @@ public abstract class Controller {
|
||||
}
|
||||
view = null;
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDestroyView(this);
|
||||
}
|
||||
|
||||
@@ -811,53 +898,78 @@ public abstract class Controller {
|
||||
|
||||
final View inflate(@NonNull ViewGroup parent) {
|
||||
if (view != null && view.getParent() != null && view.getParent() != parent) {
|
||||
detach(view, true);
|
||||
detach(view, true, false);
|
||||
removeViewReference();
|
||||
}
|
||||
|
||||
if (view == null) {
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preCreateView(this);
|
||||
}
|
||||
|
||||
view = onCreateView(LayoutInflater.from(parent.getContext()), parent);
|
||||
if (view == parent) {
|
||||
throw new IllegalStateException("Controller's onCreateView method returned the parent ViewGroup. Perhaps you forgot to pass false for LayoutInflater.inflate's attachToRoot parameter?");
|
||||
}
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postCreateView(this, view);
|
||||
}
|
||||
|
||||
restoreViewState(view);
|
||||
|
||||
onAttachStateChangeListener = new OnAttachStateChangeListener() {
|
||||
viewAttachHandler = new ViewAttachHandler(new ViewAttachListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
if (v == view) {
|
||||
viewIsAttached = true;
|
||||
viewWasDetached = false;
|
||||
}
|
||||
attach(v);
|
||||
public void onAttached() {
|
||||
viewIsAttached = true;
|
||||
viewWasDetached = false;
|
||||
attach(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
public void onDetached(boolean fromActivityStop) {
|
||||
viewIsAttached = false;
|
||||
viewWasDetached = true;
|
||||
|
||||
if (!isDetachFrozen) {
|
||||
detach(v, false);
|
||||
detach(view, false, fromActivityStop);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
view.addOnAttachStateChangeListener(onAttachStateChangeListener);
|
||||
@Override
|
||||
public void onViewDetachAfterStop() {
|
||||
if (!isDetachFrozen) {
|
||||
detach(view, false, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
viewAttachHandler.listenForAttach(view);
|
||||
} else if (retainViewMode == RetainViewMode.RETAIN_DETACH) {
|
||||
restoreChildControllerHosts();
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void restoreChildControllerHosts() {
|
||||
for (ControllerHostedRouter childRouter : childRouters) {
|
||||
if (!childRouter.hasHost()) {
|
||||
View containerView = view.findViewById(childRouter.getHostId());
|
||||
|
||||
if (containerView != null && containerView instanceof ViewGroup) {
|
||||
childRouter.setHost(this, (ViewGroup)containerView);
|
||||
childRouter.rebindIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void performDestroy() {
|
||||
if (!destroyed) {
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preDestroy(this);
|
||||
}
|
||||
|
||||
@@ -867,7 +979,8 @@ public abstract class Controller {
|
||||
|
||||
parentController = null;
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDestroy(this);
|
||||
}
|
||||
}
|
||||
@@ -885,20 +998,20 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
for (ControllerHostedRouter childRouter : childRouters) {
|
||||
childRouter.destroy();
|
||||
childRouter.destroy(false);
|
||||
}
|
||||
|
||||
if (!attached) {
|
||||
removeViewReference();
|
||||
} else if (removeViews) {
|
||||
detach(view, false);
|
||||
detach(view, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveViewState(@NonNull View view) {
|
||||
hasSavedViewState = true;
|
||||
|
||||
viewState = new Bundle();
|
||||
viewState = new Bundle(getClass().getClassLoader());
|
||||
|
||||
SparseArray<Parcelable> hierarchyState = new SparseArray<>();
|
||||
view.saveHierarchyState(hierarchyState);
|
||||
@@ -908,7 +1021,8 @@ public abstract class Controller {
|
||||
onSaveViewState(view, stateBundle);
|
||||
viewState.putBundle(KEY_VIEW_STATE_BUNDLE, stateBundle);
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.onSaveViewState(this, viewState);
|
||||
}
|
||||
}
|
||||
@@ -918,19 +1032,10 @@ public abstract class Controller {
|
||||
view.restoreHierarchyState(viewState.getSparseParcelableArray(KEY_VIEW_STATE_HIERARCHY));
|
||||
onRestoreViewState(view, viewState.getBundle(KEY_VIEW_STATE_BUNDLE));
|
||||
|
||||
for (ControllerHostedRouter childRouter : childRouters) {
|
||||
if (!childRouter.hasHost()) {
|
||||
View containerView = view.findViewById(childRouter.getHostId());
|
||||
restoreChildControllerHosts();
|
||||
|
||||
if (containerView != null && containerView instanceof ViewGroup) {
|
||||
childRouter.setHost(this, (ViewGroup)containerView);
|
||||
monitorChildRouter(childRouter);
|
||||
childRouter.rebindIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.onRestoreViewState(this, viewState);
|
||||
}
|
||||
}
|
||||
@@ -969,7 +1074,8 @@ public abstract class Controller {
|
||||
Bundle savedState = new Bundle();
|
||||
onSaveInstanceState(savedState);
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.onSaveInstanceState(this, savedState);
|
||||
}
|
||||
|
||||
@@ -980,6 +1086,10 @@ public abstract class Controller {
|
||||
|
||||
private void restoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
viewState = savedInstanceState.getBundle(KEY_VIEW_STATE);
|
||||
if (viewState != null) {
|
||||
viewState.setClassLoader(getClass().getClassLoader());
|
||||
}
|
||||
|
||||
instanceId = savedInstanceState.getString(KEY_INSTANCE_ID);
|
||||
targetInstanceId = savedInstanceState.getString(KEY_TARGET_INSTANCE_ID);
|
||||
requestedPermissions.addAll(savedInstanceState.getStringArrayList(KEY_REQUESTED_PERMISSIONS));
|
||||
@@ -992,7 +1102,6 @@ public abstract class Controller {
|
||||
for (Bundle childBundle : childBundles) {
|
||||
ControllerHostedRouter childRouter = new ControllerHostedRouter();
|
||||
childRouter.restoreInstanceState(childBundle);
|
||||
monitorChildRouter(childRouter);
|
||||
childRouters.add(childRouter);
|
||||
}
|
||||
|
||||
@@ -1004,7 +1113,8 @@ public abstract class Controller {
|
||||
if (savedInstanceState != null && router != null) {
|
||||
onRestoreInstanceState(savedInstanceState);
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.onRestoreInstanceState(this, savedInstanceState);
|
||||
}
|
||||
|
||||
@@ -1012,7 +1122,7 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
final void changeStarted(ControllerChangeHandler changeHandler, ControllerChangeType changeType) {
|
||||
final void changeStarted(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
if (!changeType.isEnter) {
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.setDetachFrozen(true);
|
||||
@@ -1021,12 +1131,13 @@ public abstract class Controller {
|
||||
|
||||
onChangeStarted(changeHandler, changeType);
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.onChangeStart(this, changeHandler, changeType);
|
||||
}
|
||||
}
|
||||
|
||||
final void changeEnded(ControllerChangeHandler changeHandler, ControllerChangeType changeType) {
|
||||
final void changeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
if (!changeType.isEnter) {
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.setDetachFrozen(false);
|
||||
@@ -1035,15 +1146,17 @@ public abstract class Controller {
|
||||
|
||||
onChangeEnded(changeHandler, changeType);
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.onChangeEnd(this, changeHandler, changeType);
|
||||
}
|
||||
|
||||
if (isBeingDestroyed && !viewIsAttached && !attached && destroyedView != null) {
|
||||
View view = destroyedView.get();
|
||||
if (router.container != null && view.getParent() == router.container) {
|
||||
if (router.container != null && view != null && view.getParent() == router.container) {
|
||||
router.container.removeView(view);
|
||||
}
|
||||
destroyedView = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1056,44 +1169,28 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
if (!frozen && view != null && viewWasDetached) {
|
||||
detach(view, false);
|
||||
detach(view, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void createOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
final void createOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
if (attached && hasOptionsMenu && !optionsMenuHidden) {
|
||||
onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
}
|
||||
|
||||
final void prepareOptionsMenu(Menu menu) {
|
||||
final void prepareOptionsMenu(@NonNull Menu menu) {
|
||||
if (attached && hasOptionsMenu && !optionsMenuHidden) {
|
||||
onPrepareOptionsMenu(menu);
|
||||
}
|
||||
}
|
||||
|
||||
final boolean optionsItemSelected(MenuItem item) {
|
||||
final boolean optionsItemSelected(@NonNull MenuItem item) {
|
||||
return attached && hasOptionsMenu && !optionsMenuHidden && onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void monitorChildRouter(ControllerHostedRouter childRouter) {
|
||||
childRouter.addChangeListener(childRouterChangeListener);
|
||||
}
|
||||
|
||||
private void onChildControllerPushed(Controller controller) {
|
||||
if (!childBackstack.contains(controller)) {
|
||||
childBackstack.add(controller);
|
||||
controller.addLifecycleListener(new LifecycleListener() {
|
||||
@Override
|
||||
public void postDestroy(@NonNull Controller controller) {
|
||||
childBackstack.remove(controller);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
final void setParentController(Controller controller) {
|
||||
final void setParentController(@Nullable Controller controller) {
|
||||
parentController = controller;
|
||||
}
|
||||
|
||||
@@ -1104,7 +1201,8 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
private static Constructor getDefaultConstructor(Constructor[] constructors) {
|
||||
@Nullable
|
||||
private static Constructor getDefaultConstructor(@NonNull Constructor[] constructors) {
|
||||
for (Constructor constructor : constructors) {
|
||||
if (constructor.getParameterTypes().length == 0) {
|
||||
return constructor;
|
||||
@@ -1113,7 +1211,8 @@ public abstract class Controller {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Constructor getBundleConstructor(Constructor[] constructors) {
|
||||
@Nullable
|
||||
private static Constructor getBundleConstructor(@NonNull Constructor[] constructors) {
|
||||
for (Constructor constructor : constructors) {
|
||||
if (constructor.getParameterTypes().length == 1 && constructor.getParameterTypes()[0] == Bundle.class) {
|
||||
return constructor;
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
@@ -9,7 +10,6 @@ import android.view.ViewParent;
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
|
||||
import com.bluelinelabs.conductor.internal.ClassUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -27,17 +27,18 @@ public abstract class ControllerChangeHandler {
|
||||
private static final Map<String, ControllerChangeHandler> inProgressPushHandlers = new HashMap<>();
|
||||
|
||||
private boolean forceRemoveViewOnPush;
|
||||
private boolean hasBeenUsed;
|
||||
|
||||
/**
|
||||
* Responsible for swapping Views from one Controller to another.
|
||||
*
|
||||
* @param container The container these Views are hosted in.
|
||||
* @param from The previous View in the container, if any.
|
||||
* @param to The next View that should be put in the container, if any.
|
||||
* @param from The previous View in the container or {@code null} if there was no Controller before this transition
|
||||
* @param to The next View that should be put in the container or {@code null} if no Controller is being transitioned to
|
||||
* @param isPush True if this is a push transaction, false if it's a pop.
|
||||
* @param changeListener This listener must be called when any transitions or animations are completed.
|
||||
*/
|
||||
public abstract void performChange(@NonNull ViewGroup container, View from, View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener);
|
||||
public abstract void performChange(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener);
|
||||
|
||||
public ControllerChangeHandler() {
|
||||
ensureDefaultConstructor();
|
||||
@@ -61,10 +62,11 @@ public abstract class ControllerChangeHandler {
|
||||
* Will be called on change handlers that push a controller if the controller being pushed is
|
||||
* popped before it has completed.
|
||||
*
|
||||
* @param newHandler the change handler that has caused this push to be aborted
|
||||
* @param newTop the controller that will now be at the top of the backstack
|
||||
* @param newHandler The change handler that has caused this push to be aborted
|
||||
* @param newTop The Controller that will now be at the top of the backstack or {@code null}
|
||||
* if there will be no new Controller at the top
|
||||
*/
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, Controller newTop) { }
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, @Nullable Controller newTop) { }
|
||||
|
||||
/**
|
||||
* Will be called on change handlers that push a controller if the controller being pushed is
|
||||
@@ -72,6 +74,27 @@ public abstract class ControllerChangeHandler {
|
||||
*/
|
||||
public void completeImmediately() { }
|
||||
|
||||
/**
|
||||
* Returns a copy of this ControllerChangeHandler. This method is internally used by the library, so
|
||||
* ensure it will return an exact copy of your handler if overriding. If not overriding, the handler
|
||||
* will be saved and restored from the Bundle format.
|
||||
*/
|
||||
@NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
return fromBundle(toBundle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this is a reusable ControllerChangeHandler. Defaults to false and should
|
||||
* ONLY be overridden if there are absolutely no side effects to using this handler more than once.
|
||||
* In the case that a handler is not reusable, it will be copied using the {@link #copy()} method
|
||||
* prior to use.
|
||||
*/
|
||||
public boolean isReusable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
final Bundle toBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_CLASS_NAME, getClass().getName());
|
||||
@@ -83,10 +106,6 @@ public abstract class ControllerChangeHandler {
|
||||
return bundle;
|
||||
}
|
||||
|
||||
final ControllerChangeHandler copy() {
|
||||
return fromBundle(toBundle());
|
||||
}
|
||||
|
||||
private void ensureDefaultConstructor() {
|
||||
try {
|
||||
getClass().getConstructor();
|
||||
@@ -95,7 +114,8 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static ControllerChangeHandler fromBundle(Bundle bundle) {
|
||||
@Nullable
|
||||
public static ControllerChangeHandler fromBundle(@Nullable Bundle bundle) {
|
||||
if (bundle != null) {
|
||||
String className = bundle.getString(KEY_CLASS_NAME);
|
||||
ControllerChangeHandler changeHandler = ClassUtils.newInstance(className);
|
||||
@@ -107,7 +127,7 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
static boolean completePushImmediately(String controllerInstanceId) {
|
||||
static boolean completePushImmediately(@NonNull String controllerInstanceId) {
|
||||
ControllerChangeHandler changeHandler = inProgressPushHandlers.get(controllerInstanceId);
|
||||
if (changeHandler != null) {
|
||||
changeHandler.completeImmediately();
|
||||
@@ -117,7 +137,7 @@ public abstract class ControllerChangeHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void abortPush(Controller toAbort, Controller newController, ControllerChangeHandler newChangeHandler) {
|
||||
static void abortPush(@NonNull Controller toAbort, @Nullable Controller newController, @NonNull ControllerChangeHandler newChangeHandler) {
|
||||
ControllerChangeHandler handlerForPush = inProgressPushHandlers.get(toAbort.getInstanceId());
|
||||
if (handlerForPush != null) {
|
||||
handlerForPush.onAbortPush(newChangeHandler, newController);
|
||||
@@ -125,22 +145,34 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static void executeChange(final Controller to, final Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler inHandler) {
|
||||
executeChange(to, from, isPush, container, inHandler, new ArrayList<ControllerChangeListener>());
|
||||
}
|
||||
static void executeChange(@Nullable final Controller to, @Nullable final Controller from, final boolean isPush, @Nullable final ViewGroup container, @Nullable final ControllerChangeHandler inHandler, @NonNull final List<ControllerChangeListener> listeners) {
|
||||
if (isPush && to != null && to.isDestroyed()) {
|
||||
throw new IllegalStateException("Trying to push a controller that has already been destroyed. (" + to.getClass().getSimpleName() + ")");
|
||||
}
|
||||
|
||||
public static void executeChange(final Controller to, final Controller from, final boolean isPush, final ViewGroup container, final ControllerChangeHandler inHandler, @NonNull final List<ControllerChangeListener> listeners) {
|
||||
if (container != null) {
|
||||
final ControllerChangeHandler handler = inHandler != null ? inHandler : new SimpleSwapChangeHandler();
|
||||
final ControllerChangeHandler handler;
|
||||
if (inHandler == null) {
|
||||
handler = new SimpleSwapChangeHandler();
|
||||
} else if (inHandler.hasBeenUsed && !inHandler.isReusable()) {
|
||||
handler = inHandler.copy();
|
||||
} else {
|
||||
handler = inHandler;
|
||||
}
|
||||
handler.hasBeenUsed = true;
|
||||
|
||||
if (isPush && to != null) {
|
||||
inProgressPushHandlers.put(to.getInstanceId(), handler);
|
||||
|
||||
if (from != null) {
|
||||
completePushImmediately(from.getInstanceId());
|
||||
}
|
||||
} else if (!isPush && from != null) {
|
||||
abortPush(from, to, handler);
|
||||
}
|
||||
|
||||
for (ControllerChangeListener listener : listeners) {
|
||||
listener.onChangeStarted(to, from, isPush, container, inHandler);
|
||||
listener.onChangeStarted(to, from, isPush, container, handler);
|
||||
}
|
||||
|
||||
final ControllerChangeType toChangeType = isPush ? ControllerChangeType.PUSH_ENTER : ControllerChangeType.POP_ENTER;
|
||||
@@ -175,7 +207,7 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
|
||||
for (ControllerChangeListener listener : listeners) {
|
||||
listener.onChangeCompleted(to, from, isPush, container, inHandler);
|
||||
listener.onChangeCompleted(to, from, isPush, container, handler);
|
||||
}
|
||||
|
||||
if (handler.forceRemoveViewOnPush && fromView != null) {
|
||||
@@ -204,24 +236,24 @@ public abstract class ControllerChangeHandler {
|
||||
/**
|
||||
* Called when a {@link ControllerChangeHandler} has started changing {@link Controller}s
|
||||
*
|
||||
* @param to The new Controller
|
||||
* @param from The old Controller
|
||||
* @param to The new Controller or {@code null} if no Controller is being transitioned to
|
||||
* @param from The old Controller or {@code null} if there was no Controller before this transition
|
||||
* @param isPush True if this is a push operation, or false if it's a pop.
|
||||
* @param container The containing ViewGroup
|
||||
* @param handler The change handler being used.
|
||||
*/
|
||||
void onChangeStarted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler);
|
||||
void onChangeStarted(@Nullable Controller to, @Nullable Controller from, boolean isPush, @NonNull ViewGroup container, @NonNull ControllerChangeHandler handler);
|
||||
|
||||
/**
|
||||
* Called when a {@link ControllerChangeHandler} has completed changing {@link Controller}s
|
||||
*
|
||||
* @param to The new Controller
|
||||
* @param from The old Controller
|
||||
* @param isPush True if this was a push operation, or false if it's a pop.
|
||||
* @param to The new Controller or {@code null} if no Controller is being transitioned to
|
||||
* @param from The old Controller or {@code null} if there was no Controller before this transition
|
||||
* @param isPush True if this was a push operation, or false if it's a pop
|
||||
* @param container The containing ViewGroup
|
||||
* @param handler The change handler that was used.
|
||||
*/
|
||||
void onChangeCompleted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler);
|
||||
void onChangeCompleted(@Nullable Controller to, @Nullable Controller from, boolean isPush, @NonNull ViewGroup container, @NonNull ControllerChangeHandler handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,9 +5,11 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener;
|
||||
import com.bluelinelabs.conductor.internal.TransactionIndexer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -24,7 +26,7 @@ class ControllerHostedRouter extends Router {
|
||||
|
||||
ControllerHostedRouter() { }
|
||||
|
||||
ControllerHostedRouter(int hostId, String tag) {
|
||||
ControllerHostedRouter(int hostId, @Nullable String tag) {
|
||||
this.hostId = hostId;
|
||||
this.tag = tag;
|
||||
}
|
||||
@@ -50,12 +52,12 @@ class ControllerHostedRouter extends Router {
|
||||
final List<Controller> controllersToDestroy = new ArrayList<>(destroyingControllers);
|
||||
for (Controller controller : controllersToDestroy) {
|
||||
if (controller.getView() != null) {
|
||||
controller.detach(controller.getView(), true);
|
||||
controller.detach(controller.getView(), true, false);
|
||||
}
|
||||
}
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (transaction.controller.getView() != null) {
|
||||
transaction.controller.detach(transaction.controller.getView(), true);
|
||||
transaction.controller.detach(transaction.controller.getView(), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,25 +73,25 @@ class ControllerHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
void destroy() {
|
||||
void destroy(boolean popViews) {
|
||||
setDetachFrozen(false);
|
||||
super.destroy();
|
||||
super.destroy(popViews);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @Nullable
|
||||
public Activity getActivity() {
|
||||
return hostController != null ? hostController.getActivity() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
public void onActivityDestroyed(@NonNull Activity activity) {
|
||||
super.onActivityDestroyed(activity);
|
||||
|
||||
removeHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
hostController.getRouter().onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
@@ -103,42 +105,42 @@ class ControllerHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
void startActivity(Intent intent) {
|
||||
void startActivity(@NonNull Intent intent) {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
hostController.getRouter().startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void startActivityForResult(String instanceId, Intent intent, int requestCode) {
|
||||
void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode) {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
hostController.getRouter().startActivityForResult(instanceId, intent, requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void startActivityForResult(String instanceId, Intent intent, int requestCode, Bundle options) {
|
||||
void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode, @Nullable Bundle options) {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
hostController.getRouter().startActivityForResult(instanceId, intent, requestCode, options);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerForActivityResult(String instanceId, int requestCode) {
|
||||
void registerForActivityResult(@NonNull String instanceId, int requestCode) {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
hostController.getRouter().registerForActivityResult(instanceId, requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void unregisterForActivityResults(String instanceId) {
|
||||
void unregisterForActivityResults(@NonNull String instanceId) {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
hostController.getRouter().unregisterForActivityResults(instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void requestPermissions(String instanceId, String[] permissions, int requestCode) {
|
||||
void requestPermissions(@NonNull String instanceId, @NonNull String[] permissions, int requestCode) {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
hostController.getRouter().requestPermissions(instanceId, permissions, requestCode);
|
||||
}
|
||||
@@ -150,7 +152,7 @@ class ControllerHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInstanceState(Bundle outState) {
|
||||
public void saveInstanceState(@NonNull Bundle outState) {
|
||||
super.saveInstanceState(outState);
|
||||
|
||||
outState.putInt(KEY_HOST_ID, hostId);
|
||||
@@ -158,7 +160,7 @@ class ControllerHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreInstanceState(Bundle savedInstanceState) {
|
||||
public void restoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
super.restoreInstanceState(savedInstanceState);
|
||||
|
||||
hostId = savedInstanceState.getInt(KEY_HOST_ID);
|
||||
@@ -166,7 +168,7 @@ class ControllerHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
void setControllerRouter(Controller controller) {
|
||||
void setControllerRouter(@NonNull Controller controller) {
|
||||
super.setControllerRouter(controller);
|
||||
controller.setParentController(hostController);
|
||||
}
|
||||
@@ -175,11 +177,12 @@ class ControllerHostedRouter extends Router {
|
||||
return hostId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
List<Router> getSiblingRouters() {
|
||||
List<Router> list = new ArrayList<>();
|
||||
list.addAll(hostController.getChildRouters());
|
||||
@@ -187,7 +190,7 @@ class ControllerHostedRouter extends Router {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
Router getRootRouter() {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
return hostController.getRouter().getRootRouter();
|
||||
@@ -195,4 +198,9 @@ class ControllerHostedRouter extends Router {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override @Nullable
|
||||
TransactionIndexer getTransactionIndexer() {
|
||||
return getRootRouter().getTransactionIndexer();
|
||||
}
|
||||
}
|
||||
|
||||
+18
-3
@@ -14,8 +14,23 @@ import android.view.ViewGroup;
|
||||
*/
|
||||
abstract public class RestoreViewOnCreateController extends Controller {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
/**
|
||||
* Convenience constructor for use when no arguments are needed.
|
||||
*/
|
||||
protected RestoreViewOnCreateController() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes arguments that need to be retained across restarts.
|
||||
*
|
||||
* @param args Any arguments that need to be retained.
|
||||
*/
|
||||
protected RestoreViewOnCreateController(@Nullable Bundle args) {
|
||||
super(args);
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
protected final View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return onCreateView(inflater, container, viewState);
|
||||
}
|
||||
@@ -30,7 +45,7 @@ abstract public class RestoreViewOnCreateController extends Controller {
|
||||
* This Controller's view should NOT be added in this method. It is simply passed in
|
||||
* so that valid LayoutParams can be used during inflation.
|
||||
* @param savedViewState A bundle for the view's state, which would have been created in {@link #onSaveViewState(View, Bundle)},
|
||||
* or null if no saved state exists.
|
||||
* or {@code null} if no saved state exists.
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container, @Nullable Bundle savedViewState);
|
||||
|
||||
@@ -4,6 +4,8 @@ import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -14,6 +16,7 @@ import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener;
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
|
||||
import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.internal.TransactionIndexer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -39,8 +42,10 @@ public abstract class Router {
|
||||
ViewGroup container;
|
||||
|
||||
/**
|
||||
* Returns this Router's host Activity
|
||||
* Returns this Router's host Activity or {@code null} if it has either not yet been attached to
|
||||
* an Activity or if the Activity has been destroyed.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Activity getActivity();
|
||||
|
||||
/**
|
||||
@@ -48,21 +53,21 @@ public abstract class Router {
|
||||
* of the controller that called startActivityForResult is not known.
|
||||
*
|
||||
* @param requestCode The Activity's onActivityResult requestCode
|
||||
* @param resultCode The Activity's onActivityResult resultCode
|
||||
* @param data The Activity's onActivityResult data
|
||||
* @param resultCode The Activity's onActivityResult resultCode
|
||||
* @param data The Activity's onActivityResult data
|
||||
*/
|
||||
public abstract void onActivityResult(int requestCode, int resultCode, Intent data);
|
||||
public abstract void onActivityResult(int requestCode, int resultCode, @Nullable Intent data);
|
||||
|
||||
/**
|
||||
* This should be called by the host Activity when its onRequestPermissionsResult method is called. The call will be forwarded
|
||||
* to the {@link Controller} with the instanceId passed in.
|
||||
*
|
||||
* @param instanceId The instanceId of the Controller to which this result should be forwarded
|
||||
* @param requestCode The Activity's onRequestPermissionsResult requestCode
|
||||
* @param permissions The Activity's onRequestPermissionsResult permissions
|
||||
* @param instanceId The instanceId of the Controller to which this result should be forwarded
|
||||
* @param requestCode The Activity's onRequestPermissionsResult requestCode
|
||||
* @param permissions The Activity's onRequestPermissionsResult permissions
|
||||
* @param grantResults The Activity's onRequestPermissionsResult grantResults
|
||||
*/
|
||||
public void onRequestPermissionsResult(String instanceId, int requestCode, String[] permissions, int[] grantResults) {
|
||||
public void onRequestPermissionsResult(@NonNull String instanceId, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
Controller controller = getControllerWithInstanceId(instanceId);
|
||||
if (controller != null) {
|
||||
controller.requestPermissionsResult(requestCode, permissions, grantResults);
|
||||
@@ -75,8 +80,10 @@ public abstract class Router {
|
||||
*
|
||||
* @return Whether or not a back action was handled by the Router
|
||||
*/
|
||||
@UiThread
|
||||
public boolean handleBack() {
|
||||
if (!backstack.isEmpty()) {
|
||||
//noinspection ConstantConditions
|
||||
if (backstack.peek().controller.handleBack()) {
|
||||
return true;
|
||||
} else if (popCurrentController()) {
|
||||
@@ -92,8 +99,13 @@ public abstract class Router {
|
||||
*
|
||||
* @return Whether or not this Router still has controllers remaining on it after popping.
|
||||
*/
|
||||
@UiThread
|
||||
public boolean popCurrentController() {
|
||||
return popController(backstack.peek().controller);
|
||||
RouterTransaction transaction = backstack.peek();
|
||||
if (transaction == null) {
|
||||
throw new IllegalStateException("Trying to pop the current controller when there are none on the backstack.");
|
||||
}
|
||||
return popController(transaction.controller);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +114,8 @@ public abstract class Router {
|
||||
* @param controller The controller that should be popped from this Router
|
||||
* @return Whether or not this Router still has controllers remaining on it after popping.
|
||||
*/
|
||||
public boolean popController(Controller controller) {
|
||||
@UiThread
|
||||
public boolean popController(@NonNull Controller controller) {
|
||||
RouterTransaction topController = backstack.peek();
|
||||
boolean poppingTopController = topController != null && topController.controller == controller;
|
||||
|
||||
@@ -134,6 +147,7 @@ public abstract class Router {
|
||||
* @param transaction The transaction detailing what should be pushed, including the {@link Controller},
|
||||
* and its push and pop {@link ControllerChangeHandler}, and its tag.
|
||||
*/
|
||||
@UiThread
|
||||
public void pushController(@NonNull RouterTransaction transaction) {
|
||||
RouterTransaction from = backstack.peek();
|
||||
pushToBackstack(transaction);
|
||||
@@ -146,6 +160,7 @@ public abstract class Router {
|
||||
* @param transaction The transaction detailing what should be pushed, including the {@link Controller},
|
||||
* and its push and pop {@link ControllerChangeHandler}, and its tag.
|
||||
*/
|
||||
@UiThread
|
||||
public void replaceTopController(@NonNull RouterTransaction transaction) {
|
||||
RouterTransaction topTransaction = backstack.peek();
|
||||
if (!backstack.isEmpty()) {
|
||||
@@ -153,11 +168,13 @@ public abstract class Router {
|
||||
}
|
||||
|
||||
final ControllerChangeHandler handler = transaction.pushChangeHandler();
|
||||
final boolean oldHandlerRemovedViews = topTransaction.pushChangeHandler() == null || topTransaction.pushChangeHandler().removesFromViewOnPush();
|
||||
final boolean newHandlerRemovesViews = handler == null || handler.removesFromViewOnPush();
|
||||
if (!oldHandlerRemovedViews && newHandlerRemovesViews) {
|
||||
for (RouterTransaction visibleTransaction : getVisibleTransactions(backstack.iterator())) {
|
||||
performControllerChange(null, visibleTransaction.controller, true, handler != null ? handler.copy() : new SimpleSwapChangeHandler());
|
||||
if (topTransaction != null) {
|
||||
final boolean oldHandlerRemovedViews = topTransaction.pushChangeHandler() == null || topTransaction.pushChangeHandler().removesFromViewOnPush();
|
||||
final boolean newHandlerRemovesViews = handler == null || handler.removesFromViewOnPush();
|
||||
if (!oldHandlerRemovedViews && newHandlerRemovesViews) {
|
||||
for (RouterTransaction visibleTransaction : getVisibleTransactions(backstack.iterator())) {
|
||||
performControllerChange(null, visibleTransaction, true, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,14 +186,13 @@ public abstract class Router {
|
||||
performControllerChange(transaction.pushChangeHandler(handler), topTransaction, true);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
void destroy(boolean popViews) {
|
||||
popsLastView = true;
|
||||
List<RouterTransaction> poppedControllers = backstack.popAll();
|
||||
trackDestroyingControllers(poppedControllers);
|
||||
|
||||
if (poppedControllers.size() > 0) {
|
||||
trackDestroyingControllers(poppedControllers);
|
||||
|
||||
performControllerChange(null, poppedControllers.get(0).controller, false, poppedControllers.get(0).popChangeHandler());
|
||||
if (popViews && poppedControllers.size() > 0) {
|
||||
performControllerChange(null, poppedControllers.get(0), false, poppedControllers.get(0).popChangeHandler());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +205,7 @@ public abstract class Router {
|
||||
* in the stack. This defaults to false so that the developer can either finish its containing Activity or otherwise
|
||||
* hide its parent view without any strange artifacting.
|
||||
*/
|
||||
@NonNull
|
||||
public Router setPopsLastView(boolean popsLastView) {
|
||||
this.popsLastView = popsLastView;
|
||||
return this;
|
||||
@@ -199,6 +216,7 @@ public abstract class Router {
|
||||
*
|
||||
* @return Whether or not any {@link Controller}s were popped in order to get to the root transaction
|
||||
*/
|
||||
@UiThread
|
||||
public boolean popToRoot() {
|
||||
return popToRoot(null);
|
||||
}
|
||||
@@ -209,8 +227,10 @@ public abstract class Router {
|
||||
* @param changeHandler The {@link ControllerChangeHandler} to handle this transaction
|
||||
* @return Whether or not any {@link Controller}s were popped in order to get to the root transaction
|
||||
*/
|
||||
public boolean popToRoot(ControllerChangeHandler changeHandler) {
|
||||
@UiThread
|
||||
public boolean popToRoot(@Nullable ControllerChangeHandler changeHandler) {
|
||||
if (backstack.size() > 1) {
|
||||
//noinspection ConstantConditions
|
||||
popToTransaction(backstack.root(), changeHandler);
|
||||
return true;
|
||||
} else {
|
||||
@@ -224,6 +244,7 @@ public abstract class Router {
|
||||
* @param tag The tag being popped to
|
||||
* @return Whether or not any {@link Controller}s were popped in order to get to the transaction with the passed tag
|
||||
*/
|
||||
@UiThread
|
||||
public boolean popToTag(@NonNull String tag) {
|
||||
return popToTag(tag, null);
|
||||
}
|
||||
@@ -231,11 +252,12 @@ public abstract class Router {
|
||||
/**
|
||||
* Pops all {@link Controller}s until the {@link Controller} with the passed tag is at the top
|
||||
*
|
||||
* @param tag The tag being popped to
|
||||
* @param tag The tag being popped to
|
||||
* @param changeHandler The {@link ControllerChangeHandler} to handle this transaction
|
||||
* @return Whether or not the {@link Controller} with the passed tag is now at the top
|
||||
*/
|
||||
public boolean popToTag(@NonNull String tag, ControllerChangeHandler changeHandler) {
|
||||
@UiThread
|
||||
public boolean popToTag(@NonNull String tag, @Nullable ControllerChangeHandler changeHandler) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (tag.equals(transaction.tag())) {
|
||||
popToTransaction(transaction, changeHandler);
|
||||
@@ -251,39 +273,21 @@ public abstract class Router {
|
||||
* @param transaction The transaction detailing what should be pushed, including the {@link Controller},
|
||||
* and its push and pop {@link ControllerChangeHandler}, and its tag.
|
||||
*/
|
||||
@UiThread
|
||||
public void setRoot(@NonNull RouterTransaction transaction) {
|
||||
ControllerChangeHandler newHandler = transaction.pushChangeHandler() != null ? transaction.pushChangeHandler() : new SimpleSwapChangeHandler();
|
||||
|
||||
List<RouterTransaction> visibleTransactions = getVisibleTransactions(backstack.iterator());
|
||||
RouterTransaction rootTransaction = visibleTransactions.size() > 0 ? visibleTransactions.get(0) : null;
|
||||
|
||||
removeAllExceptVisibleAndUnowned();
|
||||
|
||||
trackDestroyingControllers(backstack.popAll());
|
||||
|
||||
pushToBackstack(transaction);
|
||||
|
||||
for (int i = visibleTransactions.size() - 1; i > 0; i--) {
|
||||
if (visibleTransactions.get(i).controller.getView() == null) {
|
||||
ControllerChangeHandler.abortPush(visibleTransactions.get(i).controller, transaction.controller, newHandler);
|
||||
} else {
|
||||
performControllerChange(null, visibleTransactions.get(i).controller, true, newHandler);
|
||||
}
|
||||
}
|
||||
|
||||
if (rootTransaction != null && rootTransaction.controller.getView() == null) {
|
||||
ControllerChangeHandler.abortPush(rootTransaction.controller, transaction.controller, newHandler);
|
||||
}
|
||||
performControllerChange(transaction, rootTransaction, true);
|
||||
List<RouterTransaction> transactions = new ArrayList<>();
|
||||
transactions.add(transaction);
|
||||
setBackstack(transactions, transaction.pushChangeHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hosted Controller with the given instance id, if available.
|
||||
* Returns the hosted Controller with the given instance id or {@code null} if no such
|
||||
* Controller exists in this Router.
|
||||
*
|
||||
* @param instanceId The instance ID being searched for
|
||||
* @return The matching Controller, if one exists
|
||||
*/
|
||||
public Controller getControllerWithInstanceId(String instanceId) {
|
||||
@Nullable
|
||||
public Controller getControllerWithInstanceId(@NonNull String instanceId) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
Controller controllerWithId = transaction.controller.findController(instanceId);
|
||||
if (controllerWithId != null) {
|
||||
@@ -294,12 +298,13 @@ public abstract class Router {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hosted Controller that was pushed with the given tag, if available.
|
||||
* Returns the hosted Controller that was pushed with the given tag or {@code null} if no
|
||||
* such Controller exists in this Router.
|
||||
*
|
||||
* @param tag The tag being searched for
|
||||
* @return The matching Controller, if one exists
|
||||
*/
|
||||
public Controller getControllerWithTag(String tag) {
|
||||
@Nullable
|
||||
public Controller getControllerWithTag(@NonNull String tag) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (tag.equals(transaction.tag())) {
|
||||
return transaction.controller;
|
||||
@@ -318,6 +323,7 @@ public abstract class Router {
|
||||
/**
|
||||
* Returns the current backstack, ordered from root to most recently pushed.
|
||||
*/
|
||||
@NonNull
|
||||
public List<RouterTransaction> getBackstack() {
|
||||
List<RouterTransaction> list = new ArrayList<>();
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
@@ -331,55 +337,49 @@ public abstract class Router {
|
||||
* Sets the backstack, transitioning from the current top controller to the top of the new stack (if different)
|
||||
* using the passed {@link ControllerChangeHandler}
|
||||
*
|
||||
* @param newBackstack The new backstack
|
||||
* @param newBackstack The new backstack
|
||||
* @param changeHandler An optional change handler to be used to handle the root view of transition
|
||||
*/
|
||||
public void setBackstack(@NonNull List<RouterTransaction> newBackstack, ControllerChangeHandler changeHandler) {
|
||||
@UiThread
|
||||
public void setBackstack(@NonNull List<RouterTransaction> newBackstack, @Nullable ControllerChangeHandler changeHandler) {
|
||||
List<RouterTransaction> oldVisibleTransactions = getVisibleTransactions(backstack.iterator());
|
||||
|
||||
removeAllExceptVisibleAndUnowned();
|
||||
ensureOrderedTransactionIndices(newBackstack);
|
||||
|
||||
backstack.setBackstack(newBackstack);
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.onAttachedToRouter();
|
||||
}
|
||||
|
||||
if (newBackstack.size() > 0) {
|
||||
List<RouterTransaction> reverseNewBackstack = new ArrayList<>(newBackstack);
|
||||
Collections.reverse(reverseNewBackstack);
|
||||
List<RouterTransaction> newVisibleTransactions = getVisibleTransactions(reverseNewBackstack.iterator());
|
||||
|
||||
boolean visibleTransactionsChanged = newVisibleTransactions.size() != oldVisibleTransactions.size();
|
||||
if (!visibleTransactionsChanged) {
|
||||
for (int i = 0; i < oldVisibleTransactions.size(); i++) {
|
||||
if (oldVisibleTransactions.get(i).controller != newVisibleTransactions.get(i).controller) {
|
||||
visibleTransactionsChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean visibleTransactionsChanged = !backstacksAreEqual(newVisibleTransactions, oldVisibleTransactions);
|
||||
if (visibleTransactionsChanged) {
|
||||
ControllerChangeHandler handler = changeHandler != null ? changeHandler : new SimpleSwapChangeHandler();
|
||||
|
||||
Controller rootController = oldVisibleTransactions.size() > 0 ? oldVisibleTransactions.get(0).controller : null;
|
||||
performControllerChange(newVisibleTransactions.get(0).controller, rootController, true, handler.copy());
|
||||
RouterTransaction rootTransaction = oldVisibleTransactions.size() > 0 ? oldVisibleTransactions.get(0) : null;
|
||||
performControllerChange(newVisibleTransactions.get(0), rootTransaction, true, changeHandler);
|
||||
|
||||
for (int i = oldVisibleTransactions.size() - 1; i > 0; i--) {
|
||||
RouterTransaction transaction = oldVisibleTransactions.get(i);
|
||||
ControllerChangeHandler localHandler = handler.copy();
|
||||
ControllerChangeHandler localHandler = changeHandler != null ? changeHandler.copy() : new SimpleSwapChangeHandler();
|
||||
localHandler.setForceRemoveViewOnPush(true);
|
||||
performControllerChange(null, transaction.controller, true, localHandler);
|
||||
performControllerChange(null, transaction, true, localHandler);
|
||||
}
|
||||
|
||||
for (int i = 1; i < newVisibleTransactions.size(); i++) {
|
||||
RouterTransaction transaction = newVisibleTransactions.get(i);
|
||||
handler = transaction.pushChangeHandler() != null ? transaction.pushChangeHandler().copy() : new SimpleSwapChangeHandler();
|
||||
performControllerChange(transaction.controller, newVisibleTransactions.get(i - 1).controller, true, handler.copy());
|
||||
performControllerChange(transaction, newVisibleTransactions.get(i - 1), true, transaction.pushChangeHandler());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.onAttachedToRouter();
|
||||
// Ensure all new controllers have a valid router set
|
||||
for (RouterTransaction transaction : newBackstack) {
|
||||
transaction.controller.setRouter(this);
|
||||
}
|
||||
}
|
||||
|
||||
backstack.setBackstack(newBackstack);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -394,7 +394,7 @@ public abstract class Router {
|
||||
*
|
||||
* @param changeListener The listener
|
||||
*/
|
||||
public void addChangeListener(ControllerChangeListener changeListener) {
|
||||
public void addChangeListener(@NonNull ControllerChangeListener changeListener) {
|
||||
if (!changeListeners.contains(changeListener)) {
|
||||
changeListeners.add(changeListener);
|
||||
}
|
||||
@@ -405,32 +405,33 @@ public abstract class Router {
|
||||
*
|
||||
* @param changeListener The listener to be removed
|
||||
*/
|
||||
public void removeChangeListener(ControllerChangeListener changeListener) {
|
||||
public void removeChangeListener(@NonNull ControllerChangeListener changeListener) {
|
||||
changeListeners.remove(changeListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches this Router's existing backstack to its container if one exists.
|
||||
*/
|
||||
@UiThread
|
||||
public void rebindIfNeeded() {
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
while (backstackIterator.hasNext()) {
|
||||
RouterTransaction transaction = backstackIterator.next();
|
||||
|
||||
if (transaction.controller.getNeedsAttach()) {
|
||||
performControllerChange(transaction.controller, null, true, new SimpleSwapChangeHandler(false));
|
||||
performControllerChange(transaction, null, true, new SimpleSwapChangeHandler(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void onActivityResult(String instanceId, int requestCode, int resultCode, Intent data) {
|
||||
public final void onActivityResult(@NonNull String instanceId, int requestCode, int resultCode, @Nullable Intent data) {
|
||||
Controller controller = getControllerWithInstanceId(instanceId);
|
||||
if (controller != null) {
|
||||
controller.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
public final void onActivityStarted(Activity activity) {
|
||||
public final void onActivityStarted(@NonNull Activity activity) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.activityStarted(activity);
|
||||
|
||||
@@ -440,7 +441,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public final void onActivityResumed(Activity activity) {
|
||||
public final void onActivityResumed(@NonNull Activity activity) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.activityResumed(activity);
|
||||
|
||||
@@ -450,7 +451,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public final void onActivityPaused(Activity activity) {
|
||||
public final void onActivityPaused(@NonNull Activity activity) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.activityPaused(activity);
|
||||
|
||||
@@ -460,7 +461,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public final void onActivityStopped(Activity activity) {
|
||||
public final void onActivityStopped(@NonNull Activity activity) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.activityStopped(activity);
|
||||
|
||||
@@ -470,7 +471,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
public void onActivityDestroyed(@NonNull Activity activity) {
|
||||
prepareForContainerRemoval();
|
||||
changeListeners.clear();
|
||||
|
||||
@@ -503,7 +504,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public void saveInstanceState(Bundle outState) {
|
||||
public void saveInstanceState(@NonNull Bundle outState) {
|
||||
prepareForHostDetach();
|
||||
|
||||
Bundle backstackState = new Bundle();
|
||||
@@ -513,7 +514,7 @@ public abstract class Router {
|
||||
outState.putBoolean(KEY_POPS_LAST_VIEW, popsLastView);
|
||||
}
|
||||
|
||||
public void restoreInstanceState(Bundle savedInstanceState) {
|
||||
public void restoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
Bundle backstackBundle = savedInstanceState.getParcelable(KEY_BACKSTACK);
|
||||
backstack.restoreInstanceState(backstackBundle);
|
||||
popsLastView = savedInstanceState.getBoolean(KEY_POPS_LAST_VIEW);
|
||||
@@ -524,7 +525,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public final void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
public final void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.createOptionsMenu(menu, inflater);
|
||||
|
||||
@@ -534,7 +535,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public final void onPrepareOptionsMenu(Menu menu) {
|
||||
public final void onPrepareOptionsMenu(@NonNull Menu menu) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.prepareOptionsMenu(menu);
|
||||
|
||||
@@ -544,7 +545,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean onOptionsItemSelected(MenuItem item) {
|
||||
public final boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (transaction.controller.optionsItemSelected(item)) {
|
||||
return true;
|
||||
@@ -559,7 +560,7 @@ public abstract class Router {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void popToTransaction(@NonNull RouterTransaction transaction, ControllerChangeHandler changeHandler) {
|
||||
private void popToTransaction(@NonNull RouterTransaction transaction, @Nullable ControllerChangeHandler changeHandler) {
|
||||
RouterTransaction topTransaction = backstack.peek();
|
||||
List<RouterTransaction> poppedTransactions = backstack.popTo(transaction);
|
||||
trackDestroyingControllers(poppedTransactions);
|
||||
@@ -569,7 +570,7 @@ public abstract class Router {
|
||||
changeHandler = topTransaction.popChangeHandler();
|
||||
}
|
||||
|
||||
performControllerChange(backstack.peek().controller, topTransaction.controller, false, changeHandler);
|
||||
performControllerChange(backstack.peek(), topTransaction, false, changeHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,6 +580,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
final List<Controller> getControllers() {
|
||||
List<Controller> controllers = new ArrayList<>();
|
||||
|
||||
@@ -590,6 +592,7 @@ public abstract class Router {
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public final Boolean handleRequestedPermission(@NonNull String permission) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (transaction.controller.didRequestPermission(permission)) {
|
||||
@@ -599,7 +602,7 @@ public abstract class Router {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void performControllerChange(RouterTransaction to, RouterTransaction from, boolean isPush) {
|
||||
private void performControllerChange(@Nullable RouterTransaction to, @Nullable RouterTransaction from, boolean isPush) {
|
||||
if (isPush && to != null) {
|
||||
to.onAttachedToRouter();
|
||||
}
|
||||
@@ -611,32 +614,33 @@ public abstract class Router {
|
||||
} else if (from != null) {
|
||||
changeHandler = from.popChangeHandler();
|
||||
} else {
|
||||
changeHandler = new SimpleSwapChangeHandler();
|
||||
changeHandler = null;
|
||||
}
|
||||
|
||||
performControllerChange(to, from, isPush, changeHandler);
|
||||
}
|
||||
|
||||
private void performControllerChange(@Nullable final RouterTransaction to, @Nullable final RouterTransaction from, boolean isPush, @Nullable ControllerChangeHandler changeHandler) {
|
||||
Controller toController = to != null ? to.controller : null;
|
||||
Controller fromController = from != null ? from.controller : null;
|
||||
|
||||
performControllerChange(toController, fromController, isPush, changeHandler);
|
||||
}
|
||||
|
||||
private void performControllerChange(final Controller to, final Controller from, boolean isPush, @NonNull ControllerChangeHandler changeHandler) {
|
||||
if (to != null) {
|
||||
setControllerRouter(to);
|
||||
to.ensureValidIndex(getTransactionIndexer());
|
||||
setControllerRouter(toController);
|
||||
} else if (backstack.size() == 0 && !popsLastView) {
|
||||
// We're emptying out the backstack. Views get weird if you transition them out, so just no-op it. The hosting
|
||||
// Activity should be handling this by finishing or at least hiding this view.
|
||||
changeHandler = new NoOpControllerChangeHandler();
|
||||
}
|
||||
|
||||
ControllerChangeHandler.executeChange(to, from, isPush, container, changeHandler, changeListeners);
|
||||
ControllerChangeHandler.executeChange(toController, fromController, isPush, container, changeHandler, changeListeners);
|
||||
}
|
||||
|
||||
private void pushToBackstack(@NonNull RouterTransaction entry) {
|
||||
backstack.push(entry);
|
||||
}
|
||||
|
||||
private void trackDestroyingController(RouterTransaction transaction) {
|
||||
private void trackDestroyingController(@NonNull RouterTransaction transaction) {
|
||||
if (!transaction.controller.isDestroyed()) {
|
||||
destroyingControllers.add(transaction.controller);
|
||||
|
||||
@@ -649,7 +653,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
private void trackDestroyingControllers(List<RouterTransaction> transactions) {
|
||||
private void trackDestroyingControllers(@NonNull List<RouterTransaction> transactions) {
|
||||
for (RouterTransaction transaction : transactions) {
|
||||
trackDestroyingController(transaction);
|
||||
}
|
||||
@@ -679,7 +683,23 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
private void addRouterViewsToList(Router router, List<View> list) {
|
||||
// Swap around transaction indicies to ensure they don't get thrown out of order by the
|
||||
// developer rearranging the backstack at runtime.
|
||||
private void ensureOrderedTransactionIndices(List<RouterTransaction> backstack) {
|
||||
List<Integer> indices = new ArrayList<>();
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.ensureValidIndex(getTransactionIndexer());
|
||||
indices.add(transaction.transactionIndex);
|
||||
}
|
||||
|
||||
Collections.sort(indices);
|
||||
|
||||
for (int i = 0; i < backstack.size(); i++) {
|
||||
backstack.get(i).transactionIndex = indices.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void addRouterViewsToList(@NonNull Router router, @NonNull List<View> list) {
|
||||
for (Controller controller : router.getControllers()) {
|
||||
if (controller.getView() != null) {
|
||||
list.add(controller.getView());
|
||||
@@ -691,7 +711,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
private List<RouterTransaction> getVisibleTransactions(Iterator<RouterTransaction> backstackIterator) {
|
||||
private List<RouterTransaction> getVisibleTransactions(@NonNull Iterator<RouterTransaction> backstackIterator) {
|
||||
List<RouterTransaction> transactions = new ArrayList<>();
|
||||
while (backstackIterator.hasNext()) {
|
||||
RouterTransaction transaction = backstackIterator.next();
|
||||
@@ -706,18 +726,34 @@ public abstract class Router {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
void setControllerRouter(Controller controller) {
|
||||
private boolean backstacksAreEqual(List<RouterTransaction> lhs, List<RouterTransaction> rhs) {
|
||||
if (lhs.size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rhs.size(); i++) {
|
||||
if (rhs.get(i).controller() != lhs.get(i).controller()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setControllerRouter(@NonNull Controller controller) {
|
||||
controller.setRouter(this);
|
||||
}
|
||||
|
||||
abstract void invalidateOptionsMenu();
|
||||
abstract void startActivity(Intent intent);
|
||||
abstract void startActivityForResult(String instanceId, Intent intent, int requestCode);
|
||||
abstract void startActivityForResult(String instanceId, Intent intent, int requestCode, Bundle options);
|
||||
abstract void registerForActivityResult(String instanceId, int requestCode);
|
||||
abstract void unregisterForActivityResults(String instanceId);
|
||||
abstract void requestPermissions(String instanceId, String[] permissions, int requestCode);
|
||||
abstract void startActivity(@NonNull Intent intent);
|
||||
abstract void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode);
|
||||
abstract void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode, @Nullable Bundle options);
|
||||
abstract void registerForActivityResult(@NonNull String instanceId, int requestCode);
|
||||
abstract void unregisterForActivityResults(@NonNull String instanceId);
|
||||
abstract void requestPermissions(@NonNull String instanceId, @NonNull String[] permissions, int requestCode);
|
||||
abstract boolean hasHost();
|
||||
abstract List<Router> getSiblingRouters();
|
||||
abstract Router getRootRouter();
|
||||
@NonNull abstract List<Router> getSiblingRouters();
|
||||
@NonNull abstract Router getRootRouter();
|
||||
@Nullable abstract TransactionIndexer getTransactionIndexer();
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,22 @@ package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.conductor.internal.TransactionIndexer;
|
||||
|
||||
/**
|
||||
* Metadata used for adding {@link Controller}s to a {@link Router}.
|
||||
*/
|
||||
public class RouterTransaction {
|
||||
|
||||
private static int INVALID_INDEX = -1;
|
||||
|
||||
private static final String KEY_VIEW_CONTROLLER_BUNDLE = "RouterTransaction.controller.bundle";
|
||||
private static final String KEY_PUSH_TRANSITION = "RouterTransaction.pushControllerChangeHandler";
|
||||
private static final String KEY_POP_TRANSITION = "RouterTransaction.popControllerChangeHandler";
|
||||
private static final String KEY_TAG = "RouterTransaction.tag";
|
||||
private static final String KEY_INDEX = "RouterTransaction.transactionIndex";
|
||||
private static final String KEY_ATTACHED_TO_ROUTER = "RouterTransaction.attachedToRouter";
|
||||
|
||||
@NonNull final Controller controller;
|
||||
@@ -20,7 +26,9 @@ public class RouterTransaction {
|
||||
private ControllerChangeHandler pushControllerChangeHandler;
|
||||
private ControllerChangeHandler popControllerChangeHandler;
|
||||
private boolean attachedToRouter;
|
||||
int transactionIndex = INVALID_INDEX;
|
||||
|
||||
@NonNull
|
||||
public static RouterTransaction with(@NonNull Controller controller) {
|
||||
return new RouterTransaction(controller);
|
||||
}
|
||||
@@ -34,6 +42,7 @@ public class RouterTransaction {
|
||||
pushControllerChangeHandler = ControllerChangeHandler.fromBundle(bundle.getBundle(KEY_PUSH_TRANSITION));
|
||||
popControllerChangeHandler = ControllerChangeHandler.fromBundle(bundle.getBundle(KEY_POP_TRANSITION));
|
||||
tag = bundle.getString(KEY_TAG);
|
||||
transactionIndex = bundle.getInt(KEY_INDEX);
|
||||
attachedToRouter = bundle.getBoolean(KEY_ATTACHED_TO_ROUTER);
|
||||
}
|
||||
|
||||
@@ -41,15 +50,18 @@ public class RouterTransaction {
|
||||
attachedToRouter = true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Controller controller() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String tag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public RouterTransaction tag(String tag) {
|
||||
@NonNull
|
||||
public RouterTransaction tag(@Nullable String tag) {
|
||||
if (!attachedToRouter) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
@@ -58,6 +70,7 @@ public class RouterTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ControllerChangeHandler pushChangeHandler() {
|
||||
ControllerChangeHandler handler = controller.getOverriddenPushHandler();
|
||||
if (handler == null) {
|
||||
@@ -66,7 +79,8 @@ public class RouterTransaction {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public RouterTransaction pushChangeHandler(ControllerChangeHandler handler) {
|
||||
@NonNull
|
||||
public RouterTransaction pushChangeHandler(@Nullable ControllerChangeHandler handler) {
|
||||
if (!attachedToRouter) {
|
||||
pushControllerChangeHandler = handler;
|
||||
return this;
|
||||
@@ -75,6 +89,7 @@ public class RouterTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ControllerChangeHandler popChangeHandler() {
|
||||
ControllerChangeHandler handler = controller.getOverriddenPopHandler();
|
||||
if (handler == null) {
|
||||
@@ -83,7 +98,8 @@ public class RouterTransaction {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public RouterTransaction popChangeHandler(ControllerChangeHandler handler) {
|
||||
@NonNull
|
||||
public RouterTransaction popChangeHandler(@Nullable ControllerChangeHandler handler) {
|
||||
if (!attachedToRouter) {
|
||||
popControllerChangeHandler = handler;
|
||||
return this;
|
||||
@@ -92,9 +108,19 @@ public class RouterTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
void ensureValidIndex(@Nullable TransactionIndexer indexer) {
|
||||
if (indexer == null) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (transactionIndex == INVALID_INDEX && indexer != null) {
|
||||
transactionIndex = indexer.nextIndex();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to serialize this transaction into a Bundle
|
||||
*/
|
||||
@NonNull
|
||||
public Bundle saveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
|
||||
@@ -108,6 +134,7 @@ public class RouterTransaction {
|
||||
}
|
||||
|
||||
bundle.putString(KEY_TAG, tag);
|
||||
bundle.putInt(KEY_INDEX, transactionIndex);
|
||||
bundle.putBoolean(KEY_ATTACHED_TO_ROUTER, attachedToRouter);
|
||||
|
||||
return bundle;
|
||||
|
||||
+29
-15
@@ -1,9 +1,11 @@
|
||||
package com.bluelinelabs.conductor.changehandler;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.Animator.AnimatorListener;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
@@ -25,6 +27,7 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
private boolean removesFromViewOnPush;
|
||||
private boolean canceled;
|
||||
private boolean needsImmediateCompletion;
|
||||
private boolean completed;
|
||||
private Animator animator;
|
||||
|
||||
public AnimatorChangeHandler() {
|
||||
@@ -59,7 +62,7 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, Controller newTop) {
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, @Nullable Controller newTop) {
|
||||
super.onAbortPush(newHandler, newTop);
|
||||
|
||||
canceled = true;
|
||||
@@ -74,7 +77,7 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
needsImmediateCompletion = true;
|
||||
if (animator != null) {
|
||||
animator.cancel();
|
||||
animator.end();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,12 +94,13 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
* Should be overridden to return the Animator to use while replacing Views.
|
||||
*
|
||||
* @param container The container these Views are hosted in.
|
||||
* @param from The previous View in the container, if any.
|
||||
* @param to The next View that should be put in the container, if any.
|
||||
* @param from The previous View in the container or {@code null} if there was no Controller before this transition
|
||||
* @param to The next View that should be put in the container or {@code null} if no Controller is being transitioned to
|
||||
* @param isPush True if this is a push transaction, false if it's a pop.
|
||||
* @param toAddedToContainer True if the "to" view was added to the container as a part of this ChangeHandler. False if it was already in the hierarchy.
|
||||
*/
|
||||
protected abstract Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer);
|
||||
@NonNull
|
||||
protected abstract Animator getAnimator(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, boolean toAddedToContainer);
|
||||
|
||||
/**
|
||||
* Will be called after the animation is complete to reset the View that was removed to its pre-animation state.
|
||||
@@ -104,7 +108,7 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
protected abstract void resetFromView(@NonNull View from);
|
||||
|
||||
@Override
|
||||
public final void performChange(@NonNull final ViewGroup container, final View from, final View to, final boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
public final void performChange(@NonNull final ViewGroup container, @Nullable final View from, @Nullable final View to, final boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
boolean readyToAnimate = true;
|
||||
final boolean addingToView = to != null && to.getParent() == null;
|
||||
|
||||
@@ -136,9 +140,24 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void performAnimation(@NonNull final ViewGroup container, final View from, final View to, final boolean isPush, final boolean toAddedToContainer, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
if (canceled) {
|
||||
private void complete(@NonNull ControllerChangeCompletedListener changeListener, @Nullable AnimatorListener animatorListener) {
|
||||
if (!completed) {
|
||||
completed = true;
|
||||
changeListener.onChangeCompleted();
|
||||
}
|
||||
|
||||
if (animator != null) {
|
||||
if (animatorListener != null) {
|
||||
animator.removeListener(animatorListener);
|
||||
}
|
||||
animator.cancel();
|
||||
animator = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void performAnimation(@NonNull final ViewGroup container, @Nullable final View from, @Nullable final View to, final boolean isPush, final boolean toAddedToContainer, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
if (canceled) {
|
||||
complete(changeListener, null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,9 +174,7 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
container.removeView(from);
|
||||
}
|
||||
|
||||
changeListener.onChangeCompleted();
|
||||
animator.removeListener(this);
|
||||
animator = null;
|
||||
complete(changeListener, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -167,14 +184,11 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
container.removeView(from);
|
||||
}
|
||||
|
||||
changeListener.onChangeCompleted();
|
||||
animator.removeListener(this);
|
||||
complete(changeListener, this);
|
||||
|
||||
if (isPush && from != null) {
|
||||
resetFromView(from);
|
||||
}
|
||||
|
||||
animator = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+10
-3
@@ -3,21 +3,28 @@ package com.bluelinelabs.conductor.changehandler;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.transition.AutoTransition;
|
||||
import android.transition.Transition;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
|
||||
/**
|
||||
* A change handler that will use an AutoTransition.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public class AutoTransitionChangeHandler extends TransitionChangeHandler {
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected Transition getTransition(@NonNull ViewGroup container, View from, View to, boolean isPush) {
|
||||
@Override @NonNull
|
||||
protected Transition getTransition(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush) {
|
||||
return new AutoTransition();
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
return new AutoTransitionChangeHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-4
@@ -4,9 +4,12 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
|
||||
/**
|
||||
* An {@link AnimatorChangeHandler} that will cross fade two views
|
||||
*/
|
||||
@@ -26,11 +29,12 @@ public class FadeChangeHandler extends AnimatorChangeHandler {
|
||||
super(duration, removesFromViewOnPush);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer) {
|
||||
@Override @NonNull
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, boolean toAddedToContainer) {
|
||||
AnimatorSet animator = new AnimatorSet();
|
||||
if (to != null && toAddedToContainer) {
|
||||
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, 0, 1));
|
||||
if (to != null) {
|
||||
float start = toAddedToContainer ? 0 : to.getAlpha();
|
||||
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, start, 1));
|
||||
}
|
||||
|
||||
if (from != null) {
|
||||
@@ -44,4 +48,10 @@ public class FadeChangeHandler extends AnimatorChangeHandler {
|
||||
protected void resetFromView(@NonNull View from) {
|
||||
from.setAlpha(1);
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
return new FadeChangeHandler(getAnimationDuration(), removesFromViewOnPush());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-3
@@ -4,9 +4,12 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
|
||||
/**
|
||||
* An {@link AnimatorChangeHandler} that will slide the views left or right, depending on if it's a push or pop.
|
||||
*/
|
||||
@@ -26,8 +29,8 @@ public class HorizontalChangeHandler extends AnimatorChangeHandler {
|
||||
super(duration, removesFromViewOnPush);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer) {
|
||||
@Override @NonNull
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, boolean toAddedToContainer) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
|
||||
if (isPush) {
|
||||
@@ -42,7 +45,9 @@ public class HorizontalChangeHandler extends AnimatorChangeHandler {
|
||||
animatorSet.play(ObjectAnimator.ofFloat(from, View.TRANSLATION_X, from.getWidth()));
|
||||
}
|
||||
if (to != null) {
|
||||
animatorSet.play(ObjectAnimator.ofFloat(to, View.TRANSLATION_X, -to.getWidth(), 0));
|
||||
// Allow this to have a nice transition when coming off an aborted push animation
|
||||
float fromLeft = from != null ? from.getX() : 0;
|
||||
animatorSet.play(ObjectAnimator.ofFloat(to, View.TRANSLATION_X, fromLeft - to.getWidth(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,4 +58,10 @@ public class HorizontalChangeHandler extends AnimatorChangeHandler {
|
||||
protected void resetFromView(@NonNull View from) {
|
||||
from.setTranslationX(0);
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
return new HorizontalChangeHandler(getAnimationDuration(), removesFromViewOnPush());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-4
@@ -2,6 +2,7 @@ package com.bluelinelabs.conductor.changehandler;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
@@ -44,7 +45,7 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, Controller newTop) {
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, @Nullable Controller newTop) {
|
||||
super.onAbortPush(newHandler, newTop);
|
||||
|
||||
canceled = true;
|
||||
@@ -62,7 +63,7 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull ViewGroup container, View from, View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
public void performChange(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
if (!canceled) {
|
||||
if (from != null && (!isPush || removesFromViewOnPush)) {
|
||||
container.removeView(from);
|
||||
@@ -89,7 +90,7 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
public void onViewAttachedToWindow(@NonNull View v) {
|
||||
v.removeOnAttachStateChangeListener(this);
|
||||
|
||||
if (changeListener != null) {
|
||||
@@ -100,5 +101,15 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) { }
|
||||
public void onViewDetachedFromWindow(@NonNull View v) { }
|
||||
|
||||
@Override @NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
return new SimpleSwapChangeHandler(removesFromViewOnPush());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReusable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-8
@@ -3,6 +3,7 @@ package com.bluelinelabs.conductor.changehandler;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.transition.Transition;
|
||||
import android.transition.Transition.TransitionListener;
|
||||
import android.transition.TransitionManager;
|
||||
@@ -23,23 +24,23 @@ public abstract class TransitionChangeHandler extends ControllerChangeHandler {
|
||||
/**
|
||||
* Should be overridden to return the Transition to use while replacing Views.
|
||||
*
|
||||
* @param container The container these Views are hosted in.
|
||||
* @param from The previous View in the container, if any.
|
||||
* @param to The next View that should be put in the container, if any.
|
||||
* @param isPush True if this is a push transaction, false if it's a pop.
|
||||
* @param container The container these Views are hosted in
|
||||
* @param from The previous View in the container or {@code null} if there was no Controller before this transition
|
||||
* @param to The next View that should be put in the container or {@code null} if no Controller is being transitioned to
|
||||
* @param isPush True if this is a push transaction, false if it's a pop
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract Transition getTransition(@NonNull ViewGroup container, View from, View to, boolean isPush);
|
||||
protected abstract Transition getTransition(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush);
|
||||
|
||||
@Override
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, Controller newTop) {
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, @Nullable Controller newTop) {
|
||||
super.onAbortPush(newHandler, newTop);
|
||||
|
||||
canceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull final ViewGroup container, View from, View to, boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
public void performChange(@NonNull final ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
if (canceled) {
|
||||
changeListener.onChangeCompleted();
|
||||
return;
|
||||
@@ -71,7 +72,7 @@ public abstract class TransitionChangeHandler extends ControllerChangeHandler {
|
||||
if (from != null) {
|
||||
container.removeView(from);
|
||||
}
|
||||
if (to != null) {
|
||||
if (to != null && to.getParent() == null) {
|
||||
container.addView(to);
|
||||
}
|
||||
}
|
||||
@@ -80,4 +81,5 @@ public abstract class TransitionChangeHandler extends ControllerChangeHandler {
|
||||
public final boolean removesFromViewOnPush() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+27
-34
@@ -3,6 +3,7 @@ package com.bluelinelabs.conductor.changehandler;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -15,13 +16,10 @@ import com.bluelinelabs.conductor.internal.ClassUtils;
|
||||
*/
|
||||
public class TransitionChangeHandlerCompat extends ControllerChangeHandler {
|
||||
|
||||
private static final String KEY_TRANSITION_HANDLER_CLASS = "TransitionChangeHandlerCompat.transitionChangeHandler.class";
|
||||
private static final String KEY_FALLBACK_HANDLER_CLASS = "TransitionChangeHandlerCompat.fallbackChangeHandler.class";
|
||||
private static final String KEY_TRANSITION_HANDLER_STATE = "TransitionChangeHandlerCompat.transitionChangeHandler.state";
|
||||
private static final String KEY_FALLBACK_HANDLER_STATE = "TransitionChangeHandlerCompat.fallbackChangeHandler.state";
|
||||
private static final String KEY_CHANGE_HANDLER_CLASS = "TransitionChangeHandlerCompat.changeHandler.class";
|
||||
private static final String KEY_HANDLER_STATE = "TransitionChangeHandlerCompat.changeHandler.state";
|
||||
|
||||
private TransitionChangeHandler transitionChangeHandler;
|
||||
private ControllerChangeHandler fallbackChangeHandler;
|
||||
private ControllerChangeHandler changeHandler;
|
||||
|
||||
public TransitionChangeHandlerCompat() { }
|
||||
|
||||
@@ -32,57 +30,52 @@ public class TransitionChangeHandlerCompat extends ControllerChangeHandler {
|
||||
* @param transitionChangeHandler The change handler that will be used on API 21 and above
|
||||
* @param fallbackChangeHandler The change handler that will be used on APIs below 21
|
||||
*/
|
||||
public TransitionChangeHandlerCompat(TransitionChangeHandler transitionChangeHandler, ControllerChangeHandler fallbackChangeHandler) {
|
||||
this.transitionChangeHandler = transitionChangeHandler;
|
||||
this.fallbackChangeHandler = fallbackChangeHandler;
|
||||
public TransitionChangeHandlerCompat(@NonNull TransitionChangeHandler transitionChangeHandler, @NonNull ControllerChangeHandler fallbackChangeHandler) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
changeHandler = transitionChangeHandler;
|
||||
} else {
|
||||
changeHandler = fallbackChangeHandler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull final ViewGroup container, View from, View to, boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
transitionChangeHandler.performChange(container, from, to, isPush, changeListener);
|
||||
} else {
|
||||
fallbackChangeHandler.performChange(container, from, to, isPush, changeListener);
|
||||
}
|
||||
public void performChange(@NonNull final ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
changeHandler.performChange(container, from, to, isPush, changeListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToBundle(@NonNull Bundle bundle) {
|
||||
super.saveToBundle(bundle);
|
||||
|
||||
bundle.putString(KEY_TRANSITION_HANDLER_CLASS, transitionChangeHandler.getClass().getName());
|
||||
bundle.putString(KEY_FALLBACK_HANDLER_CLASS, fallbackChangeHandler.getClass().getName());
|
||||
bundle.putString(KEY_CHANGE_HANDLER_CLASS, changeHandler.getClass().getName());
|
||||
|
||||
Bundle transitionBundle = new Bundle();
|
||||
transitionChangeHandler.saveToBundle(transitionBundle);
|
||||
bundle.putBundle(KEY_TRANSITION_HANDLER_STATE, transitionBundle);
|
||||
|
||||
Bundle fallbackBundle = new Bundle();
|
||||
fallbackChangeHandler.saveToBundle(fallbackBundle);
|
||||
bundle.putBundle(KEY_FALLBACK_HANDLER_STATE, fallbackBundle);
|
||||
Bundle stateBundle = new Bundle();
|
||||
changeHandler.saveToBundle(stateBundle);
|
||||
bundle.putBundle(KEY_HANDLER_STATE, stateBundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(@NonNull Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
|
||||
String transitionClassName = bundle.getString(KEY_TRANSITION_HANDLER_CLASS);
|
||||
transitionChangeHandler = ClassUtils.newInstance(transitionClassName);
|
||||
String className = bundle.getString(KEY_CHANGE_HANDLER_CLASS);
|
||||
changeHandler = ClassUtils.newInstance(className);
|
||||
//noinspection ConstantConditions
|
||||
transitionChangeHandler.restoreFromBundle(bundle.getBundle(KEY_TRANSITION_HANDLER_STATE));
|
||||
|
||||
String fallbackClassName = bundle.getString(KEY_FALLBACK_HANDLER_CLASS);
|
||||
fallbackChangeHandler = ClassUtils.newInstance(fallbackClassName);
|
||||
//noinspection ConstantConditions
|
||||
fallbackChangeHandler.restoreFromBundle(bundle.getBundle(KEY_FALLBACK_HANDLER_STATE));
|
||||
changeHandler.restoreFromBundle(bundle.getBundle(KEY_HANDLER_STATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removesFromViewOnPush() {
|
||||
return changeHandler.removesFromViewOnPush();
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
return transitionChangeHandler.removesFromViewOnPush();
|
||||
return new TransitionChangeHandlerCompat((TransitionChangeHandler)changeHandler.copy(), null);
|
||||
} else {
|
||||
return fallbackChangeHandler.removesFromViewOnPush();
|
||||
return new TransitionChangeHandlerCompat(null, changeHandler.copy());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-2
@@ -4,9 +4,12 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -30,8 +33,8 @@ public class VerticalChangeHandler extends AnimatorChangeHandler {
|
||||
super(duration, removesFromViewOnPush);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer) {
|
||||
@Override @NonNull
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, boolean toAddedToContainer) {
|
||||
AnimatorSet animator = new AnimatorSet();
|
||||
List<Animator> viewAnimators = new ArrayList<>();
|
||||
|
||||
@@ -48,4 +51,9 @@ public class VerticalChangeHandler extends AnimatorChangeHandler {
|
||||
@Override
|
||||
protected void resetFromView(@NonNull View from) { }
|
||||
|
||||
@Override @NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
return new VerticalChangeHandler(getAnimationDuration(), removesFromViewOnPush());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class ClassUtils {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Class<? extends T> classForName(String className) {
|
||||
return classForName(className, true);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Class<? extends T> classForName(String className, boolean allowEmptyName) {
|
||||
@Nullable @SuppressWarnings("unchecked")
|
||||
public static <T> Class<? extends T> classForName(@NonNull String className, boolean allowEmptyName) {
|
||||
if (allowEmptyName && TextUtils.isEmpty(className)) {
|
||||
return null;
|
||||
}
|
||||
@@ -22,10 +19,10 @@ public class ClassUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T newInstance(String className) {
|
||||
@Nullable @SuppressWarnings("unchecked")
|
||||
public static <T> T newInstance(@NonNull String className) {
|
||||
try {
|
||||
Class<? extends T> cls = classForName(className);
|
||||
Class<? extends T> cls = classForName(className, true);
|
||||
return cls != null ? cls.newInstance() : null;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("An exception occurred while creating a new instance of " + className + ". " + e.getMessage());
|
||||
|
||||
@@ -8,7 +8,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@@ -27,6 +30,7 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
|
||||
private static final String FRAGMENT_TAG = "LifecycleHandler";
|
||||
|
||||
private static final String KEY_PENDING_PERMISSION_REQUESTS = "LifecycleHandler.pendingPermissionRequests";
|
||||
private static final String KEY_PERMISSION_REQUEST_CODES = "LifecycleHandler.permissionRequests";
|
||||
private static final String KEY_ACTIVITY_REQUEST_CODES = "LifecycleHandler.activityRequests";
|
||||
private static final String KEY_ROUTER_STATE_PREFIX = "LifecycleHandler.routerState";
|
||||
@@ -34,9 +38,11 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
private Activity activity;
|
||||
private boolean hasRegisteredCallbacks;
|
||||
private boolean destroyed;
|
||||
private boolean attached;
|
||||
|
||||
private SparseArray<String> permissionRequestMap = new SparseArray<>();
|
||||
private SparseArray<String> activityRequestMap = new SparseArray<>();
|
||||
private ArrayList<PendingPermissionRequest> pendingPermissionRequests = new ArrayList<>();
|
||||
|
||||
private final Map<Integer, ActivityHostedRouter> routerMap = new HashMap<>();
|
||||
|
||||
@@ -45,7 +51,8 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
private static LifecycleHandler findInActivity(Activity activity) {
|
||||
@Nullable
|
||||
private static LifecycleHandler findInActivity(@NonNull Activity activity) {
|
||||
LifecycleHandler lifecycleHandler = (LifecycleHandler)activity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||
if (lifecycleHandler != null) {
|
||||
lifecycleHandler.registerActivityListener(activity);
|
||||
@@ -53,7 +60,8 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
return lifecycleHandler;
|
||||
}
|
||||
|
||||
public static LifecycleHandler install(Activity activity) {
|
||||
@NonNull
|
||||
public static LifecycleHandler install(@NonNull Activity activity) {
|
||||
LifecycleHandler lifecycleHandler = findInActivity(activity);
|
||||
if (lifecycleHandler == null) {
|
||||
lifecycleHandler = new LifecycleHandler();
|
||||
@@ -63,7 +71,8 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
return lifecycleHandler;
|
||||
}
|
||||
|
||||
public Router getRouter(ViewGroup container, Bundle savedInstanceState) {
|
||||
@NonNull
|
||||
public Router getRouter(@NonNull ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
ActivityHostedRouter router = routerMap.get(getRouterHashKey(container));
|
||||
if (router == null) {
|
||||
router = new ActivityHostedRouter();
|
||||
@@ -83,19 +92,21 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
return router;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Router> getRouters() {
|
||||
return new ArrayList<Router>(routerMap.values());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Activity getLifecycleActivity() {
|
||||
return activity;
|
||||
}
|
||||
|
||||
private static int getRouterHashKey(ViewGroup viewGroup) {
|
||||
private static int getRouterHashKey(@NonNull ViewGroup viewGroup) {
|
||||
return viewGroup.getId();
|
||||
}
|
||||
|
||||
private void registerActivityListener(Activity activity) {
|
||||
private void registerActivityListener(@NonNull Activity activity) {
|
||||
this.activity = activity;
|
||||
|
||||
if (!hasRegisteredCallbacks) {
|
||||
@@ -110,10 +121,13 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
StringSparseArrayParceler permissionParcel = savedInstanceState.getParcelable(KEY_PERMISSION_REQUEST_CODES);
|
||||
permissionRequestMap = permissionParcel != null ? permissionParcel.getStringSparseArray() : null;
|
||||
permissionRequestMap = permissionParcel != null ? permissionParcel.getStringSparseArray() : new SparseArray<String>();
|
||||
|
||||
StringSparseArrayParceler activityParcel = savedInstanceState.getParcelable(KEY_ACTIVITY_REQUEST_CODES);
|
||||
activityRequestMap = activityParcel != null ? activityParcel.getStringSparseArray() : null;
|
||||
activityRequestMap = activityParcel != null ? activityParcel.getStringSparseArray() : new SparseArray<String>();
|
||||
|
||||
ArrayList<PendingPermissionRequest> pendingRequests = savedInstanceState.getParcelableArrayList(KEY_PENDING_PERMISSION_REQUESTS);
|
||||
pendingPermissionRequests = pendingRequests != null ? pendingRequests : new ArrayList<PendingPermissionRequest>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +137,7 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
|
||||
outState.putParcelable(KEY_PERMISSION_REQUEST_CODES, new StringSparseArrayParceler(permissionRequestMap));
|
||||
outState.putParcelable(KEY_ACTIVITY_REQUEST_CODES, new StringSparseArrayParceler(activityRequestMap));
|
||||
outState.putParcelableArrayList(KEY_PENDING_PERMISSION_REQUESTS, pendingPermissionRequests);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,21 +156,35 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
destroyed = false;
|
||||
setAttached();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
destroyed = false;
|
||||
setAttached();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
|
||||
attached = false;
|
||||
destroyRouters();
|
||||
}
|
||||
|
||||
private void setAttached() {
|
||||
if (!attached) {
|
||||
attached = true;
|
||||
|
||||
for (int i = pendingPermissionRequests.size() - 1; i >= 0; i--) {
|
||||
PendingPermissionRequest request = pendingPermissionRequests.remove(i);
|
||||
requestPermissions(request.instanceId, request.permissions, request.requestCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyRouters() {
|
||||
if (!destroyed) {
|
||||
destroyed = true;
|
||||
@@ -232,11 +261,11 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public void registerForActivityResult(String instanceId, int requestCode) {
|
||||
public void registerForActivityResult(@NonNull String instanceId, int requestCode) {
|
||||
activityRequestMap.put(requestCode, instanceId);
|
||||
}
|
||||
|
||||
public void unregisterForActivityResults(String instanceId) {
|
||||
public void unregisterForActivityResults(@NonNull String instanceId) {
|
||||
for (int i = activityRequestMap.size() - 1; i >= 0; i--) {
|
||||
if (instanceId.equals(activityRequestMap.get(activityRequestMap.keyAt(i)))) {
|
||||
activityRequestMap.removeAt(i);
|
||||
@@ -244,20 +273,24 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
}
|
||||
}
|
||||
|
||||
public void startActivityForResult(String instanceId, Intent intent, int requestCode) {
|
||||
public void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode) {
|
||||
registerForActivityResult(instanceId, requestCode);
|
||||
startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
public void startActivityForResult(String instanceId, Intent intent, int requestCode, Bundle options) {
|
||||
public void startActivityForResult(@NonNull String instanceId, @NonNull Intent intent, int requestCode, @Nullable Bundle options) {
|
||||
registerForActivityResult(instanceId, requestCode);
|
||||
startActivityForResult(intent, requestCode, options);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public void requestPermissions(String instanceId, String[] permissions, int requestCode) {
|
||||
permissionRequestMap.put(requestCode, instanceId);
|
||||
requestPermissions(permissions, requestCode);
|
||||
public void requestPermissions(@NonNull String instanceId, @NonNull String[] permissions, int requestCode) {
|
||||
if (attached) {
|
||||
permissionRequestMap.put(requestCode, instanceId);
|
||||
requestPermissions(permissions, requestCode);
|
||||
} else {
|
||||
pendingPermissionRequests.add(new PendingPermissionRequest(instanceId, permissions, requestCode));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -316,4 +349,47 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) { }
|
||||
|
||||
private static class PendingPermissionRequest implements Parcelable {
|
||||
final String instanceId;
|
||||
final String[] permissions;
|
||||
final int requestCode;
|
||||
|
||||
PendingPermissionRequest(@NonNull String instanceId, @NonNull String[] permissions, int requestCode) {
|
||||
this.instanceId = instanceId;
|
||||
this.permissions = permissions;
|
||||
this.requestCode = requestCode;
|
||||
}
|
||||
|
||||
private PendingPermissionRequest(Parcel in) {
|
||||
instanceId = in.readString();
|
||||
permissions = in.createStringArray();
|
||||
requestCode = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(instanceId);
|
||||
out.writeStringArray(permissions);
|
||||
out.writeInt(requestCode);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<PendingPermissionRequest> CREATOR = new Parcelable.Creator<PendingPermissionRequest>() {
|
||||
@Override
|
||||
public PendingPermissionRequest createFromParcel(Parcel in) {
|
||||
return new PendingPermissionRequest(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingPermissionRequest[] newArray(int size) {
|
||||
return new PendingPermissionRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -1,6 +1,7 @@
|
||||
package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -9,8 +10,18 @@ import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
public class NoOpControllerChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull ViewGroup container, @NonNull View from, @NonNull View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
public void performChange(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
changeListener.onChangeCompleted();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ControllerChangeHandler copy() {
|
||||
return new NoOpControllerChangeHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReusable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -2,17 +2,18 @@ package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.SparseArray;
|
||||
|
||||
public class StringSparseArrayParceler implements Parcelable {
|
||||
|
||||
private final SparseArray<String> stringSparseArray;
|
||||
|
||||
public StringSparseArrayParceler(SparseArray<String> stringSparseArray) {
|
||||
public StringSparseArrayParceler(@NonNull SparseArray<String> stringSparseArray) {
|
||||
this.stringSparseArray = stringSparseArray;
|
||||
}
|
||||
|
||||
private StringSparseArrayParceler(Parcel in) {
|
||||
private StringSparseArrayParceler(@NonNull Parcel in) {
|
||||
stringSparseArray = new SparseArray<>();
|
||||
|
||||
final int size = in.readInt();
|
||||
@@ -22,14 +23,17 @@ public class StringSparseArrayParceler implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
@@ -44,10 +48,12 @@ public class StringSparseArrayParceler implements Parcelable {
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public class TransactionIndexer {
|
||||
|
||||
private static final String KEY_INDEX = "TransactionIndexer.currentIndex";
|
||||
|
||||
private int currentIndex;
|
||||
|
||||
public int nextIndex() {
|
||||
return ++currentIndex;
|
||||
}
|
||||
|
||||
public void saveInstanceState(@NonNull Bundle outState) {
|
||||
outState.putInt(KEY_INDEX, currentIndex);
|
||||
}
|
||||
|
||||
public void restoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
currentIndex = savedInstanceState.getInt(KEY_INDEX);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class ViewAttachHandler implements OnAttachStateChangeListener {
|
||||
|
||||
private enum ReportedState {
|
||||
VIEW_DETACHED,
|
||||
ACTIVITY_STOPPED,
|
||||
ATTACHED
|
||||
}
|
||||
|
||||
public interface ViewAttachListener {
|
||||
void onAttached();
|
||||
void onDetached(boolean fromActivityStop);
|
||||
void onViewDetachAfterStop();
|
||||
}
|
||||
|
||||
private interface ChildAttachListener {
|
||||
void onAttached();
|
||||
}
|
||||
|
||||
private boolean rootAttached = false;
|
||||
boolean childrenAttached = false;
|
||||
private boolean activityStopped = false;
|
||||
private ReportedState reportedState = ReportedState.VIEW_DETACHED;
|
||||
private ViewAttachListener attachListener;
|
||||
private OnAttachStateChangeListener childOnAttachStateChangeListener;
|
||||
|
||||
public ViewAttachHandler(ViewAttachListener attachListener) {
|
||||
this.attachListener = attachListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(final View v) {
|
||||
if (rootAttached) {
|
||||
return;
|
||||
}
|
||||
|
||||
rootAttached = true;
|
||||
listenForDeepestChildAttach(v, new ChildAttachListener() {
|
||||
@Override
|
||||
public void onAttached() {
|
||||
childrenAttached = true;
|
||||
reportAttached();
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
rootAttached = false;
|
||||
if (childrenAttached) {
|
||||
childrenAttached = false;
|
||||
reportDetached();
|
||||
}
|
||||
}
|
||||
|
||||
public void listenForAttach(final View view) {
|
||||
view.addOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
public void unregisterAttachListener(View view) {
|
||||
view.removeOnAttachStateChangeListener(this);
|
||||
|
||||
if (childOnAttachStateChangeListener != null && view instanceof ViewGroup) {
|
||||
findDeepestChild((ViewGroup)view).removeOnAttachStateChangeListener(childOnAttachStateChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void onActivityStarted() {
|
||||
activityStopped = false;
|
||||
reportAttached();
|
||||
}
|
||||
|
||||
public void onActivityStopped() {
|
||||
activityStopped = true;
|
||||
reportDetached();
|
||||
}
|
||||
|
||||
void reportAttached() {
|
||||
if (rootAttached && childrenAttached && !activityStopped && reportedState != ReportedState.ATTACHED) {
|
||||
reportedState = ReportedState.ATTACHED;
|
||||
attachListener.onAttached();
|
||||
}
|
||||
}
|
||||
|
||||
void reportDetached() {
|
||||
boolean wasDetachedForActivity = reportedState == ReportedState.ACTIVITY_STOPPED;
|
||||
boolean isDetachedForActivity = rootAttached;
|
||||
|
||||
if (isDetachedForActivity) {
|
||||
reportedState = ReportedState.ACTIVITY_STOPPED;
|
||||
} else {
|
||||
reportedState = ReportedState.VIEW_DETACHED;
|
||||
}
|
||||
|
||||
if (wasDetachedForActivity && !isDetachedForActivity) {
|
||||
attachListener.onViewDetachAfterStop();
|
||||
} else {
|
||||
attachListener.onDetached(isDetachedForActivity);
|
||||
}
|
||||
}
|
||||
|
||||
void listenForDeepestChildAttach(final View view, final ChildAttachListener attachListener) {
|
||||
if (!(view instanceof ViewGroup)) {
|
||||
attachListener.onAttached();
|
||||
return;
|
||||
}
|
||||
|
||||
ViewGroup viewGroup = (ViewGroup)view;
|
||||
if (viewGroup.getChildCount() == 0) {
|
||||
attachListener.onAttached();
|
||||
return;
|
||||
}
|
||||
|
||||
childOnAttachStateChangeListener = new OnAttachStateChangeListener() {
|
||||
boolean attached = false;
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
if (!attached) {
|
||||
attached = true;
|
||||
attachListener.onAttached();
|
||||
v.removeOnAttachStateChangeListener(this);
|
||||
childOnAttachStateChangeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) { }
|
||||
};
|
||||
findDeepestChild(viewGroup).addOnAttachStateChangeListener(childOnAttachStateChangeListener);
|
||||
}
|
||||
|
||||
private View findDeepestChild(ViewGroup viewGroup) {
|
||||
if (viewGroup.getChildCount() == 0) {
|
||||
return viewGroup;
|
||||
}
|
||||
|
||||
View lastChild = viewGroup.getChildAt(viewGroup.getChildCount() - 1);
|
||||
if (lastChild instanceof ViewGroup) {
|
||||
return findDeepestChild((ViewGroup)lastChild);
|
||||
} else {
|
||||
return lastChild;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import org.junit.Assert;
|
||||
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;
|
||||
@@ -15,20 +18,20 @@ public class BackstackTests {
|
||||
|
||||
@Test
|
||||
public void testPush() {
|
||||
Assert.assertEquals(0, backstack.size());
|
||||
assertEquals(0, backstack.size());
|
||||
backstack.push(RouterTransaction.with(new TestController()));
|
||||
Assert.assertEquals(1, backstack.size());
|
||||
assertEquals(1, backstack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPop() {
|
||||
backstack.push(RouterTransaction.with(new TestController()));
|
||||
backstack.push(RouterTransaction.with(new TestController()));
|
||||
Assert.assertEquals(2, backstack.size());
|
||||
assertEquals(2, backstack.size());
|
||||
backstack.pop();
|
||||
Assert.assertEquals(1, backstack.size());
|
||||
assertEquals(1, backstack.size());
|
||||
backstack.pop();
|
||||
Assert.assertEquals(0, backstack.size());
|
||||
assertEquals(0, backstack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -37,13 +40,13 @@ public class BackstackTests {
|
||||
RouterTransaction transaction2 = RouterTransaction.with(new TestController());
|
||||
|
||||
backstack.push(transaction1);
|
||||
Assert.assertEquals(transaction1, backstack.peek());
|
||||
assertEquals(transaction1, backstack.peek());
|
||||
|
||||
backstack.push(transaction2);
|
||||
Assert.assertEquals(transaction2, backstack.peek());
|
||||
assertEquals(transaction2, backstack.peek());
|
||||
|
||||
backstack.pop();
|
||||
Assert.assertEquals(transaction1, backstack.peek());
|
||||
assertEquals(transaction1, backstack.peek());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,11 +59,11 @@ public class BackstackTests {
|
||||
backstack.push(transaction2);
|
||||
backstack.push(transaction3);
|
||||
|
||||
Assert.assertEquals(3, backstack.size());
|
||||
assertEquals(3, backstack.size());
|
||||
|
||||
backstack.popTo(transaction1);
|
||||
|
||||
Assert.assertEquals(1, backstack.size());
|
||||
Assert.assertEquals(transaction1, backstack.peek());
|
||||
assertEquals(1, backstack.size());
|
||||
assertEquals(transaction1, backstack.peek());
|
||||
}
|
||||
}
|
||||
|
||||
+9
-7
@@ -2,10 +2,12 @@ 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.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ControllerChangeHandlerTests {
|
||||
|
||||
@Test
|
||||
@@ -21,17 +23,17 @@ public class ControllerChangeHandlerTests {
|
||||
ControllerChangeHandler restoredHorizontal = restoredTransaction.pushChangeHandler();
|
||||
ControllerChangeHandler restoredFade = restoredTransaction.popChangeHandler();
|
||||
|
||||
Assert.assertEquals(horizontalChangeHandler.getClass(), restoredHorizontal.getClass());
|
||||
Assert.assertEquals(fadeChangeHandler.getClass(), restoredFade.getClass());
|
||||
assertEquals(horizontalChangeHandler.getClass(), restoredHorizontal.getClass());
|
||||
assertEquals(fadeChangeHandler.getClass(), restoredFade.getClass());
|
||||
|
||||
HorizontalChangeHandler restoredHorizontalCast = (HorizontalChangeHandler)restoredHorizontal;
|
||||
FadeChangeHandler restoredFadeCast = (FadeChangeHandler)restoredFade;
|
||||
|
||||
Assert.assertEquals(horizontalChangeHandler.getAnimationDuration(), restoredHorizontalCast.getAnimationDuration());
|
||||
Assert.assertEquals(horizontalChangeHandler.removesFromViewOnPush(), restoredHorizontalCast.removesFromViewOnPush());
|
||||
assertEquals(horizontalChangeHandler.getAnimationDuration(), restoredHorizontalCast.getAnimationDuration());
|
||||
assertEquals(horizontalChangeHandler.removesFromViewOnPush(), restoredHorizontalCast.removesFromViewOnPush());
|
||||
|
||||
Assert.assertEquals(fadeChangeHandler.getAnimationDuration(), restoredFadeCast.getAnimationDuration());
|
||||
Assert.assertEquals(fadeChangeHandler.removesFromViewOnPush(), restoredFadeCast.removesFromViewOnPush());
|
||||
assertEquals(fadeChangeHandler.getAnimationDuration(), restoredFadeCast.getAnimationDuration());
|
||||
assertEquals(fadeChangeHandler.removesFromViewOnPush(), restoredFadeCast.removesFromViewOnPush());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.ListUtils;
|
||||
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.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(ListUtils.listOf(true), listener.changeEndReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postCreateViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postAttachReferences);
|
||||
assertEquals(ListUtils.listOf(), listener.postDetachReferences);
|
||||
assertEquals(ListUtils.listOf(), listener.postDestroyViewReferences);
|
||||
assertEquals(ListUtils.listOf(), 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(ListUtils.listOf(true), listener.changeEndReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postCreateViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postAttachReferences);
|
||||
assertEquals(ListUtils.listOf(), listener.postDetachReferences);
|
||||
assertEquals(ListUtils.listOf(), listener.postDestroyViewReferences);
|
||||
assertEquals(ListUtils.listOf(), 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(ListUtils.listOf(true, true), listener.changeEndReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postCreateViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postAttachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDetachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDestroyViewReferences);
|
||||
assertEquals(ListUtils.listOf(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(ListUtils.listOf(true, true), listener.changeEndReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postCreateViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postAttachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDetachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDestroyViewReferences);
|
||||
assertEquals(ListUtils.listOf(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(ListUtils.listOf(true), listener.changeEndReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postCreateViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postAttachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDetachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDestroyViewReferences);
|
||||
assertEquals(ListUtils.listOf(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(ListUtils.listOf(true), listener.changeEndReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postCreateViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postAttachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDetachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDestroyViewReferences);
|
||||
assertEquals(ListUtils.listOf(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(ListUtils.listOf(true), listener.changeEndReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postCreateViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postAttachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDetachReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDestroyViewReferences);
|
||||
assertEquals(ListUtils.listOf(true), listener.postDestroyReferences);
|
||||
}
|
||||
|
||||
static class ActivityReferencingLifecycleListener extends Controller.LifecycleListener {
|
||||
List<Boolean> changeEndReferences = new ArrayList<>();
|
||||
List<Boolean> postCreateViewReferences = new ArrayList<>();
|
||||
List<Boolean> postAttachReferences = new ArrayList<>();
|
||||
List<Boolean> postDetachReferences = new ArrayList<>();
|
||||
List<Boolean> postDestroyViewReferences = new ArrayList<>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+171
-128
@@ -6,18 +6,26 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
import com.bluelinelabs.conductor.MockChangeHandler.ChangeHandlerListener;
|
||||
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.Assert;
|
||||
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;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ControllerLifecycleTests {
|
||||
public class ControllerLifecycleCallbacksTests {
|
||||
|
||||
private Router router;
|
||||
|
||||
@@ -60,11 +68,42 @@ public class ControllerLifecycleTests {
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
Assert.assertNull(controller.getView());
|
||||
assertNull(controller.getView());
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleWithActivityStop() {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
|
||||
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();
|
||||
@@ -83,7 +122,7 @@ public class ControllerLifecycleTests {
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.stop();
|
||||
activityProxy.stop(true);
|
||||
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
expectedCallState.detachCalls++;
|
||||
@@ -122,7 +161,7 @@ public class ControllerLifecycleTests {
|
||||
activityProxy.pause();
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.stop();
|
||||
activityProxy.stop(true);
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
@@ -194,212 +233,212 @@ public class ControllerLifecycleTests {
|
||||
@Override
|
||||
public void preCreateView(@NonNull Controller controller) {
|
||||
callState.createViewCalls++;
|
||||
Assert.assertEquals(1, callState.createViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.createViewCalls);
|
||||
assertEquals(1, callState.createViewCalls);
|
||||
assertEquals(0, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.attachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.attachCalls);
|
||||
assertEquals(0, callState.attachCalls);
|
||||
assertEquals(0, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.detachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls);
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCreateView(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.createViewCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.attachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.attachCalls);
|
||||
assertEquals(0, callState.attachCalls);
|
||||
assertEquals(0, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.detachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls);
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.attachCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(1, callState.attachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.attachCalls);
|
||||
assertEquals(1, callState.attachCalls);
|
||||
assertEquals(0, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.detachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls);
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.attachCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.attachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.detachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls);
|
||||
assertEquals(0, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.detachCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.attachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(1, callState.detachCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.detachCalls);
|
||||
assertEquals(1, callState.detachCalls);
|
||||
assertEquals(0, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.detachCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.attachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.detachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls);
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(0, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroyView(@NonNull Controller controller, @NonNull View view) {
|
||||
callState.destroyViewCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.attachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.detachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls);
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(1, callState.destroyViewCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(1, callState.destroyViewCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroyView(@NonNull Controller controller) {
|
||||
callState.destroyViewCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.attachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.detachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls);
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.destroyViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(0, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(0, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
callState.destroyCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.attachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.detachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls);
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.destroyViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(1, callState.destroyCalls);
|
||||
Assert.assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
assertEquals(1, callState.destroyCalls);
|
||||
assertEquals(0, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroy(@NonNull Controller controller) {
|
||||
callState.destroyCalls++;
|
||||
Assert.assertEquals(2, callState.createViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(1, testController.currentCallState.createViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.attachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.attachCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(1, testController.currentCallState.attachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.detachCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.detachCalls);
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(1, testController.currentCallState.detachCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.destroyViewCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyViewCalls);
|
||||
|
||||
Assert.assertEquals(2, callState.destroyCalls);
|
||||
Assert.assertEquals(1, testController.currentCallState.destroyCalls);
|
||||
assertEquals(2, callState.destroyCalls);
|
||||
assertEquals(1, testController.currentCallState.destroyCalls);
|
||||
}
|
||||
});
|
||||
|
||||
router.pushController(RouterTransaction.with(testController)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
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);
|
||||
assertEquals(2, callState.createViewCalls);
|
||||
assertEquals(2, callState.attachCalls);
|
||||
assertEquals(2, callState.detachCalls);
|
||||
assertEquals(2, callState.destroyViewCalls);
|
||||
assertEquals(2, callState.destroyCalls);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildLifecycle() {
|
||||
Controller parent = new TestController();
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
attachLifecycleListener(child);
|
||||
@@ -408,7 +447,7 @@ public class ControllerLifecycleTests {
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter
|
||||
.setRoot(RouterTransaction.with(child)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, child))
|
||||
@@ -425,8 +464,8 @@ public class ControllerLifecycleTests {
|
||||
public void testChildLifecycle2() {
|
||||
Controller parent = new TestController();
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
attachLifecycleListener(child);
|
||||
@@ -435,7 +474,7 @@ public class ControllerLifecycleTests {
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter
|
||||
.setRoot(RouterTransaction.with(child)
|
||||
.pushChangeHandler(getPushHandler(expectedCallState, child))
|
||||
@@ -445,26 +484,30 @@ public class ControllerLifecycleTests {
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
}
|
||||
|
||||
private MockChangeHandler getPushHandler(final CallState expectedCallState, final TestController controller) {
|
||||
return new MockChangeHandler(new ChangeHandlerListener() {
|
||||
return MockChangeHandler.listeningChangeHandler(new ChangeHandlerListener() {
|
||||
@Override
|
||||
void willStartChange() {
|
||||
public void willStartChange() {
|
||||
expectedCallState.changeStartCalls++;
|
||||
expectedCallState.createViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
void didAttachOrDetach() {
|
||||
public void didAttachOrDetach() {
|
||||
expectedCallState.attachCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
void didEndChange() {
|
||||
public void didEndChange() {
|
||||
expectedCallState.changeEndCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
@@ -472,15 +515,15 @@ public class ControllerLifecycleTests {
|
||||
}
|
||||
|
||||
private MockChangeHandler getPopHandler(final CallState expectedCallState, final TestController controller) {
|
||||
return new MockChangeHandler(new ChangeHandlerListener() {
|
||||
return MockChangeHandler.listeningChangeHandler(new ChangeHandlerListener() {
|
||||
@Override
|
||||
void willStartChange() {
|
||||
public void willStartChange() {
|
||||
expectedCallState.changeStartCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
void didAttachOrDetach() {
|
||||
public void didAttachOrDetach() {
|
||||
expectedCallState.destroyViewCalls++;
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
@@ -488,7 +531,7 @@ public class ControllerLifecycleTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
void didEndChange() {
|
||||
public void didEndChange() {
|
||||
expectedCallState.changeEndCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
@@ -496,8 +539,8 @@ public class ControllerLifecycleTests {
|
||||
}
|
||||
|
||||
private void assertCalls(CallState callState, TestController controller) {
|
||||
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);
|
||||
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) {
|
||||
@@ -7,14 +7,22 @@ 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.Assert;
|
||||
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 {
|
||||
@@ -38,29 +46,30 @@ public class ControllerTests {
|
||||
@Test
|
||||
public void testViewRetention() {
|
||||
Controller controller = new TestController();
|
||||
controller.setRouter(router);
|
||||
|
||||
// Test View getting released w/ RELEASE_DETACH
|
||||
controller.setRetainViewMode(RetainViewMode.RELEASE_DETACH);
|
||||
Assert.assertNull(controller.getView());
|
||||
View view = controller.inflate(new AttachFakingFrameLayout(router.getActivity()));
|
||||
Assert.assertNotNull(controller.getView());
|
||||
assertNull(controller.getView());
|
||||
View view = controller.inflate(router.container);
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertNull(controller.getView());
|
||||
assertNull(controller.getView());
|
||||
|
||||
// Test View getting retained w/ RETAIN_DETACH
|
||||
controller.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
view = controller.inflate(new AttachFakingFrameLayout(router.getActivity()));
|
||||
Assert.assertNotNull(controller.getView());
|
||||
view = controller.inflate(router.container);
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
assertNotNull(controller.getView());
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
// Ensure re-setting RELEASE_DETACH releases
|
||||
controller.setRetainViewMode(RetainViewMode.RELEASE_DETACH);
|
||||
Assert.assertNull(controller.getView());
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,7 +102,7 @@ public class ControllerTests {
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null)
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
@@ -150,7 +159,7 @@ public class ControllerTests {
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null)
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
@@ -214,7 +223,7 @@ public class ControllerTests {
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null)
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
@@ -262,48 +271,48 @@ public class ControllerTests {
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
|
||||
Assert.assertEquals(0, parent.getChildRouters().size());
|
||||
Assert.assertNull(child1.getParentController());
|
||||
Assert.assertNull(child2.getParentController());
|
||||
assertEquals(0, parent.getChildRouters().size());
|
||||
assertNull(child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.setRoot(RouterTransaction.with(child1));
|
||||
|
||||
Assert.assertEquals(1, parent.getChildRouters().size());
|
||||
Assert.assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
Assert.assertEquals(1, childRouter.getBackstackSize());
|
||||
Assert.assertEquals(child1, childRouter.getControllers().get(0));
|
||||
Assert.assertEquals(parent, child1.getParentController());
|
||||
Assert.assertNull(child2.getParentController());
|
||||
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), null);
|
||||
childRouter = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(child2));
|
||||
|
||||
Assert.assertEquals(1, parent.getChildRouters().size());
|
||||
Assert.assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
Assert.assertEquals(2, childRouter.getBackstackSize());
|
||||
Assert.assertEquals(child1, childRouter.getControllers().get(0));
|
||||
Assert.assertEquals(child2, childRouter.getControllers().get(1));
|
||||
Assert.assertEquals(parent, child1.getParentController());
|
||||
Assert.assertEquals(parent, child2.getParentController());
|
||||
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);
|
||||
|
||||
Assert.assertEquals(1, parent.getChildRouters().size());
|
||||
Assert.assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
Assert.assertEquals(1, childRouter.getBackstackSize());
|
||||
Assert.assertEquals(child1, childRouter.getControllers().get(0));
|
||||
Assert.assertEquals(parent, child1.getParentController());
|
||||
Assert.assertNull(child2.getParentController());
|
||||
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);
|
||||
|
||||
Assert.assertEquals(1, parent.getChildRouters().size());
|
||||
Assert.assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
Assert.assertEquals(0, childRouter.getBackstackSize());
|
||||
Assert.assertNull(child1.getParentController());
|
||||
Assert.assertNull(child2.getParentController());
|
||||
assertEquals(1, parent.getChildRouters().size());
|
||||
assertEquals(childRouter, parent.getChildRouters().get(0));
|
||||
assertEquals(0, childRouter.getBackstackSize());
|
||||
assertNull(child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -315,47 +324,89 @@ public class ControllerTests {
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
|
||||
Assert.assertEquals(0, parent.getChildRouters().size());
|
||||
Assert.assertNull(child1.getParentController());
|
||||
Assert.assertNull(child2.getParentController());
|
||||
assertEquals(0, parent.getChildRouters().size());
|
||||
assertNull(child1.getParentController());
|
||||
assertNull(child2.getParentController());
|
||||
|
||||
Router childRouter1 = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.CHILD_VIEW_ID_1), null);
|
||||
Router childRouter2 = parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.CHILD_VIEW_ID_2), null);
|
||||
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));
|
||||
|
||||
Assert.assertEquals(2, parent.getChildRouters().size());
|
||||
Assert.assertEquals(childRouter1, parent.getChildRouters().get(0));
|
||||
Assert.assertEquals(childRouter2, parent.getChildRouters().get(1));
|
||||
Assert.assertEquals(1, childRouter1.getBackstackSize());
|
||||
Assert.assertEquals(1, childRouter2.getBackstackSize());
|
||||
Assert.assertEquals(child1, childRouter1.getControllers().get(0));
|
||||
Assert.assertEquals(child2, childRouter2.getControllers().get(0));
|
||||
Assert.assertEquals(parent, child1.getParentController());
|
||||
Assert.assertEquals(parent, child2.getParentController());
|
||||
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);
|
||||
|
||||
Assert.assertEquals(1, parent.getChildRouters().size());
|
||||
Assert.assertEquals(childRouter1, parent.getChildRouters().get(0));
|
||||
Assert.assertEquals(1, childRouter1.getBackstackSize());
|
||||
Assert.assertEquals(0, childRouter2.getBackstackSize());
|
||||
Assert.assertEquals(child1, childRouter1.getControllers().get(0));
|
||||
Assert.assertEquals(parent, child1.getParentController());
|
||||
Assert.assertNull(child2.getParentController());
|
||||
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);
|
||||
|
||||
Assert.assertEquals(0, parent.getChildRouters().size());
|
||||
Assert.assertEquals(0, childRouter1.getBackstackSize());
|
||||
Assert.assertEquals(0, childRouter2.getBackstackSize());
|
||||
Assert.assertNull(child1.getParentController());
|
||||
Assert.assertNull(child2.getParentController());
|
||||
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.transactionIndex, restoredChildTransaction1.transactionIndex);
|
||||
assertEquals(childTransaction1.controller.getInstanceId(), restoredChildTransaction1.controller.getInstanceId());
|
||||
assertEquals(childTransaction2.transactionIndex, restoredChildTransaction2.transactionIndex);
|
||||
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) {
|
||||
Assert.assertEquals("Expected call counts and controller call counts do not match.", callState, controller.currentCallState);
|
||||
assertEquals("Expected call counts and controller call counts do not match.", callState, controller.currentCallState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ import android.os.Bundle;
|
||||
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import com.bluelinelabs.conductor.util.TestController;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ControllerTransactionTests {
|
||||
|
||||
@Test
|
||||
@@ -22,10 +23,10 @@ public class ControllerTransactionTests {
|
||||
|
||||
RouterTransaction restoredTransaction = new RouterTransaction(bundle);
|
||||
|
||||
Assert.assertEquals(transaction.controller.getClass(), restoredTransaction.controller.getClass());
|
||||
Assert.assertEquals(transaction.pushChangeHandler().getClass(), restoredTransaction.pushChangeHandler().getClass());
|
||||
Assert.assertEquals(transaction.popChangeHandler().getClass(), restoredTransaction.popChangeHandler().getClass());
|
||||
Assert.assertEquals(transaction.tag(), restoredTransaction.tag());
|
||||
assertEquals(transaction.controller.getClass(), restoredTransaction.controller.getClass());
|
||||
assertEquals(transaction.pushChangeHandler().getClass(), restoredTransaction.pushChangeHandler().getClass());
|
||||
assertEquals(transaction.popChangeHandler().getClass(), restoredTransaction.popChangeHandler().getClass());
|
||||
assertEquals(transaction.tag(), restoredTransaction.tag());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class MockChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
private static final String KEY_REMOVES_FROM_VIEW_ON_PUSH = "MockChangeHandler.removesFromViewOnPush";
|
||||
|
||||
static class ChangeHandlerListener {
|
||||
void willStartChange() { }
|
||||
void didAttachOrDetach() { }
|
||||
void didEndChange() { }
|
||||
}
|
||||
|
||||
final ChangeHandlerListener listener;
|
||||
boolean removesFromViewOnPush;
|
||||
|
||||
public MockChangeHandler() {
|
||||
this(true, null);
|
||||
}
|
||||
|
||||
public MockChangeHandler(boolean removesViewOnPush) {
|
||||
this(removesViewOnPush, null);
|
||||
}
|
||||
|
||||
public MockChangeHandler(@NonNull ChangeHandlerListener listener) {
|
||||
this(true, listener);
|
||||
}
|
||||
|
||||
public MockChangeHandler(boolean removesFromViewOnPush, ChangeHandlerListener listener) {
|
||||
this.removesFromViewOnPush = removesFromViewOnPush;
|
||||
|
||||
if (listener == null) {
|
||||
this.listener = new ChangeHandlerListener() { };
|
||||
} else {
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull ViewGroup container, View from, View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
listener.willStartChange();
|
||||
|
||||
if (isPush) {
|
||||
container.addView(to);
|
||||
listener.didAttachOrDetach();
|
||||
|
||||
if (removesFromViewOnPush && from != null) {
|
||||
container.removeView(from);
|
||||
}
|
||||
} else {
|
||||
container.removeView(from);
|
||||
listener.didAttachOrDetach();
|
||||
|
||||
if (to != null) {
|
||||
container.addView(to);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
changeListener.onChangeCompleted();
|
||||
listener.didEndChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removesFromViewOnPush() {
|
||||
return removesFromViewOnPush;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToBundle(@NonNull Bundle bundle) {
|
||||
super.saveToBundle(bundle);
|
||||
bundle.putBoolean(KEY_REMOVES_FROM_VIEW_ON_PUSH, removesFromViewOnPush);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(@NonNull Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
removesFromViewOnPush = bundle.getBoolean(KEY_REMOVES_FROM_VIEW_ON_PUSH);
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,19 @@ package com.bluelinelabs.conductor;
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.junit.Assert;
|
||||
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.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ReattachCaseTests {
|
||||
@@ -36,71 +42,71 @@ public class ReattachCaseTests {
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
sleepWakeDevice();
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildNeedsAttachOnPauseAndOrientation() {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController childController = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
final Controller controllerA = new TestController();
|
||||
final Controller childController = new TestController();
|
||||
final Controller controllerB = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
sleepWakeDevice();
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
Assert.assertTrue(childController.getNeedsAttach());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
assertTrue(childController.getNeedsAttach());
|
||||
assertTrue(controllerB.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,45 +116,45 @@ public class ReattachCaseTests {
|
||||
final TestController childController = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouter = controllerB.getChildRouter((ViewGroup)controllerB.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = controllerB.getChildRouter((ViewGroup)controllerB.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
}
|
||||
|
||||
// Attempt to test https://github.com/bluelinelabs/Conductor/issues/86#issuecomment-231381271
|
||||
@@ -159,71 +165,71 @@ public class ReattachCaseTests {
|
||||
TestController childController = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Router childRouter = controllerB.getChildRouter((ViewGroup)controllerB.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = controllerB.getChildRouter((ViewGroup)controllerB.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.setPopsLastView(true);
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
childController = new TestController();
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
childController = new TestController();
|
||||
childRouter.pushController(RouterTransaction.with(childController)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertTrue(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertTrue(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
assertFalse(controllerA.isAttached());
|
||||
assertTrue(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
|
||||
router.handleBack();
|
||||
|
||||
Assert.assertTrue(controllerA.isAttached());
|
||||
Assert.assertFalse(controllerB.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
assertTrue(controllerA.isAttached());
|
||||
assertFalse(controllerB.isAttached());
|
||||
assertFalse(childController.isAttached());
|
||||
}
|
||||
|
||||
private void sleepWakeDevice() {
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.ListUtils;
|
||||
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.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 = ListUtils.listOf(
|
||||
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);
|
||||
|
||||
List<RouterTransaction> newBackstack = ListUtils.listOf(
|
||||
RouterTransaction.with(newController1),
|
||||
RouterTransaction.with(newController2).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler())
|
||||
);
|
||||
|
||||
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.latestChangeHandler().tag);
|
||||
assertTrue(newController1.changeHandlerHistory.latestIsPush());
|
||||
|
||||
assertNotNull(newController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController2.getView(), newController2.changeHandlerHistory.latestToView());
|
||||
assertEquals(newController1.getView(), newController2.changeHandlerHistory.latestFromView());
|
||||
assertEquals(setBackstackHandler.tag, newController2.changeHandlerHistory.latestChangeHandler().tag);
|
||||
assertTrue(newController2.changeHandlerHistory.latestIsPush());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,25 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import org.junit.Assert;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
import com.bluelinelabs.conductor.util.ListUtils;
|
||||
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.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 {
|
||||
@@ -28,13 +38,13 @@ public class RouterTests {
|
||||
|
||||
Controller rootController = new TestController();
|
||||
|
||||
Assert.assertFalse(router.hasRootController());
|
||||
assertFalse(router.hasRootController());
|
||||
|
||||
router.setRoot(RouterTransaction.with(rootController).tag(rootTag));
|
||||
|
||||
Assert.assertTrue(router.hasRootController());
|
||||
assertTrue(router.hasRootController());
|
||||
|
||||
Assert.assertEquals(rootController, router.getControllerWithTag(rootTag));
|
||||
assertEquals(rootController, router.getControllerWithTag(rootTag));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -48,8 +58,8 @@ public class RouterTests {
|
||||
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));
|
||||
assertNull(router.getControllerWithTag(oldRootTag));
|
||||
assertEquals(newRootController, router.getControllerWithTag(newRootTag));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -58,8 +68,8 @@ public class RouterTests {
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
|
||||
Assert.assertEquals(controller, router.getControllerWithInstanceId(controller.getInstanceId()));
|
||||
Assert.assertNull(router.getControllerWithInstanceId("fake id"));
|
||||
assertEquals(controller, router.getControllerWithInstanceId(controller.getInstanceId()));
|
||||
assertNull(router.getControllerWithInstanceId("fake id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,8 +86,8 @@ public class RouterTests {
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.tag(controller2Tag));
|
||||
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
Assert.assertEquals(controller2, router.getControllerWithTag(controller2Tag));
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertEquals(controller2, router.getControllerWithTag(controller2Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -91,26 +101,26 @@ public class RouterTests {
|
||||
router.pushController(RouterTransaction.with(controller1)
|
||||
.tag(controller1Tag));
|
||||
|
||||
Assert.assertEquals(1, router.getBackstackSize());
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
|
||||
router.pushController(RouterTransaction.with(controller2)
|
||||
.tag(controller2Tag));
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
Assert.assertEquals(1, router.getBackstackSize());
|
||||
assertEquals(1, router.getBackstackSize());
|
||||
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
Assert.assertNull(router.getControllerWithTag(controller2Tag));
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertNull(router.getControllerWithTag(controller2Tag));
|
||||
|
||||
router.popCurrentController();
|
||||
|
||||
Assert.assertEquals(0, router.getBackstackSize());
|
||||
assertEquals(0, router.getBackstackSize());
|
||||
|
||||
Assert.assertNull(router.getControllerWithTag(controller1Tag));
|
||||
Assert.assertNull(router.getControllerWithTag(controller2Tag));
|
||||
assertNull(router.getControllerWithTag(controller1Tag));
|
||||
assertNull(router.getControllerWithTag(controller2Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -139,11 +149,11 @@ public class RouterTests {
|
||||
|
||||
router.popToTag(controller2Tag);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
Assert.assertEquals(controller2, router.getControllerWithTag(controller2Tag));
|
||||
Assert.assertNull(router.getControllerWithTag(controller3Tag));
|
||||
Assert.assertNull(router.getControllerWithTag(controller4Tag));
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertEquals(controller2, router.getControllerWithTag(controller2Tag));
|
||||
assertNull(router.getControllerWithTag(controller3Tag));
|
||||
assertNull(router.getControllerWithTag(controller4Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,10 +177,10 @@ public class RouterTests {
|
||||
|
||||
router.popController(controller2);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
Assert.assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
Assert.assertNull(router.getControllerWithTag(controller2Tag));
|
||||
Assert.assertEquals(controller3, router.getControllerWithTag(controller3Tag));
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(controller1, router.getControllerWithTag(controller1Tag));
|
||||
assertNull(router.getControllerWithTag(controller2Tag));
|
||||
assertEquals(controller3, router.getControllerWithTag(controller3Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -179,81 +189,73 @@ public class RouterTests {
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(middleTransaction);
|
||||
backstack.add(topTransaction);
|
||||
|
||||
List<RouterTransaction> backstack = ListUtils.listOf(rootTransaction, middleTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.assertEquals(3, router.getBackstackSize());
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(middleTransaction, fetchedBackstack.get(1));
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack.get(2));
|
||||
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()));
|
||||
|
||||
Assert.assertEquals(1, router.getBackstackSize());
|
||||
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 = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(middleTransaction);
|
||||
backstack.add(topTransaction);
|
||||
|
||||
List<RouterTransaction> backstack = ListUtils.listOf(rootTransaction, middleTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.assertEquals(3, router.getBackstackSize());
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(middleTransaction, fetchedBackstack.get(1));
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack.get(2));
|
||||
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(new MockChangeHandler(false));
|
||||
RouterTransaction oldTopTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
router.setRoot(oldRootTransaction);
|
||||
router.pushController(oldTopTransaction);
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
Assert.assertTrue(oldRootTransaction.controller.isAttached());
|
||||
Assert.assertTrue(oldTopTransaction.controller.isAttached());
|
||||
assertTrue(oldRootTransaction.controller.isAttached());
|
||||
assertTrue(oldTopTransaction.controller.isAttached());
|
||||
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(new MockChangeHandler(false));
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(new MockChangeHandler(false));
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(middleTransaction);
|
||||
backstack.add(topTransaction);
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
List<RouterTransaction> backstack = ListUtils.listOf(rootTransaction, middleTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.assertEquals(3, router.getBackstackSize());
|
||||
assertEquals(3, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(middleTransaction, fetchedBackstack.get(1));
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack.get(2));
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(middleTransaction, fetchedBackstack.get(1));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(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());
|
||||
assertFalse(oldRootTransaction.controller.isAttached());
|
||||
assertFalse(oldTopTransaction.controller.isAttached());
|
||||
assertTrue(rootTransaction.controller.isAttached());
|
||||
assertTrue(middleTransaction.controller.isAttached());
|
||||
assertTrue(topTransaction.controller.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -261,61 +263,112 @@ public class RouterTests {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(topTransaction);
|
||||
|
||||
List<RouterTransaction> backstack = ListUtils.listOf(rootTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
|
||||
RouterTransaction newTopTransaction = RouterTransaction.with(new TestController());
|
||||
router.replaceTopController(newTopTransaction);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(newTopTransaction, fetchedBackstack.get(1));
|
||||
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(new MockChangeHandler(false));
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(topTransaction);
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
List<RouterTransaction> backstack = ListUtils.listOf(rootTransaction, topTransaction);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached());
|
||||
Assert.assertTrue(topTransaction.controller.isAttached());
|
||||
assertTrue(rootTransaction.controller.isAttached());
|
||||
assertTrue(topTransaction.controller.isAttached());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
|
||||
RouterTransaction newTopTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(new MockChangeHandler(false));
|
||||
RouterTransaction newTopTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
router.replaceTopController(newTopTransaction);
|
||||
newTopTransaction.pushChangeHandler().completeImmediately();
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
assertEquals(2, router.getBackstackSize());
|
||||
|
||||
fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(newTopTransaction, fetchedBackstack.get(1));
|
||||
assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
assertEquals(newTopTransaction, fetchedBackstack.get(1));
|
||||
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached());
|
||||
Assert.assertFalse(topTransaction.controller.isAttached());
|
||||
Assert.assertTrue(newTopTransaction.controller.isAttached());
|
||||
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 = ListUtils.listOf(transaction1, transaction2);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(1, transaction1.transactionIndex);
|
||||
assertEquals(2, transaction2.transactionIndex);
|
||||
|
||||
backstack = ListUtils.listOf(transaction2, transaction1);
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(1, transaction2.transactionIndex);
|
||||
assertEquals(2, transaction1.transactionIndex);
|
||||
|
||||
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 = ListUtils.listOf(transaction1, transaction2);
|
||||
childRouter.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(2, transaction1.transactionIndex);
|
||||
assertEquals(3, transaction2.transactionIndex);
|
||||
|
||||
backstack = ListUtils.listOf(transaction2, transaction1);
|
||||
childRouter.setBackstack(backstack, null);
|
||||
|
||||
assertEquals(2, transaction2.transactionIndex);
|
||||
assertEquals(3, transaction1.transactionIndex);
|
||||
|
||||
childRouter.handleBack();
|
||||
|
||||
assertEquals(1, childRouter.getBackstackSize());
|
||||
assertEquals(transaction2, childRouter.getBackstack().get(0));
|
||||
|
||||
childRouter.handleBack();
|
||||
assertEquals(0, childRouter.getBackstackSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,13 +3,19 @@ package com.bluelinelabs.conductor;
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.junit.Assert;
|
||||
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 {
|
||||
@@ -34,21 +40,21 @@ public class TargetControllerTests {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
Assert.assertNull(controllerA.getTargetController());
|
||||
Assert.assertNull(controllerB.getTargetController());
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertNull(controllerB.getTargetController());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
controllerB.setTargetController(controllerA);
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertNull(controllerA.getTargetController());
|
||||
Assert.assertEquals(controllerA, controllerB.getTargetController());
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertEquals(controllerA, controllerB.getTargetController());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,22 +62,22 @@ public class TargetControllerTests {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
Assert.assertNull(controllerA.getTargetController());
|
||||
Assert.assertNull(controllerB.getTargetController());
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertNull(controllerB.getTargetController());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
controllerB.setTargetController(controllerA);
|
||||
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertNull(controllerA.getTargetController());
|
||||
Assert.assertEquals(controllerA, controllerB.getTargetController());
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertEquals(controllerA, controllerB.getTargetController());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,22 +85,22 @@ public class TargetControllerTests {
|
||||
final TestController controllerA = new TestController();
|
||||
final TestController controllerB = new TestController();
|
||||
|
||||
Assert.assertNull(controllerA.getTargetController());
|
||||
Assert.assertNull(controllerB.getTargetController());
|
||||
assertNull(controllerA.getTargetController());
|
||||
assertNull(controllerB.getTargetController());
|
||||
|
||||
router.pushController(RouterTransaction.with(controllerA)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
controllerA.setTargetController(controllerB);
|
||||
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID), null);
|
||||
Router childRouter = controllerA.getChildRouter((ViewGroup)controllerA.getView().findViewById(TestController.VIEW_ID));
|
||||
childRouter.pushController(RouterTransaction.with(controllerB)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
Assert.assertNull(controllerB.getTargetController());
|
||||
Assert.assertEquals(controllerB, controllerA.getTargetController());
|
||||
assertNull(controllerB.getTargetController());
|
||||
assertEquals(controllerB, controllerA.getTargetController());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.bluelinelabs.conductor.internal.ViewAttachHandler;
|
||||
import com.bluelinelabs.conductor.internal.ViewAttachHandler.ViewAttachListener;
|
||||
import com.bluelinelabs.conductor.util.ActivityProxy;
|
||||
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;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ViewAttachHandlerTests {
|
||||
|
||||
private Activity activity;
|
||||
private ViewAttachHandler viewAttachHandler;
|
||||
private CountingViewAttachListener viewAttachListener;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
activity = new ActivityProxy().create(null).getActivity();
|
||||
viewAttachListener = new CountingViewAttachListener();
|
||||
viewAttachHandler = new ViewAttachHandler(viewAttachListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleViewAttachDetach() {
|
||||
View view = new View(activity);
|
||||
viewAttachHandler.listenForAttach(view);
|
||||
|
||||
assertEquals(0, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
viewAttachHandler.onActivityStopped();
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
|
||||
viewAttachHandler.onActivityStarted();
|
||||
assertEquals(3, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleViewGroupAttachDetach() {
|
||||
View view = new View(activity);
|
||||
viewAttachHandler.listenForAttach(view);
|
||||
|
||||
assertEquals(0, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
viewAttachHandler.onActivityStopped();
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
|
||||
viewAttachHandler.onActivityStarted();
|
||||
assertEquals(3, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedViewGroupAttachDetach() {
|
||||
ViewGroup view = new LinearLayout(activity);
|
||||
View child = new LinearLayout(activity);
|
||||
view.addView(child);
|
||||
viewAttachHandler.listenForAttach(view);
|
||||
|
||||
assertEquals(0, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true, false);
|
||||
assertEquals(0, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(child, true, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true, false);
|
||||
ViewUtils.reportAttached(child, true, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(0, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true, false);
|
||||
assertEquals(1, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(child, true, false);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(1, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
viewAttachHandler.onActivityStopped();
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(0, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, false, false);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
|
||||
ViewUtils.reportAttached(view, true, false);
|
||||
ViewUtils.reportAttached(child, true, false);
|
||||
assertEquals(2, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
|
||||
viewAttachHandler.onActivityStarted();
|
||||
assertEquals(3, viewAttachListener.attaches);
|
||||
assertEquals(2, viewAttachListener.detaches);
|
||||
assertEquals(1, viewAttachListener.detachAfterStops);
|
||||
}
|
||||
|
||||
private static class CountingViewAttachListener implements ViewAttachListener {
|
||||
int attaches;
|
||||
int detaches;
|
||||
int detachAfterStops;
|
||||
|
||||
@Override
|
||||
public void onAttached() {
|
||||
attaches++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetached(boolean fromActivityStop) {
|
||||
detaches++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachAfterStop() {
|
||||
detachAfterStops++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+8
-3
@@ -1,4 +1,4 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
@@ -45,14 +45,19 @@ public class ActivityProxy {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy stop() {
|
||||
public ActivityProxy stop(boolean detachView) {
|
||||
activityController.stop();
|
||||
view.setAttached(false);
|
||||
|
||||
if (detachView) {
|
||||
view.setAttached(false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy destroy() {
|
||||
activityController.destroy();
|
||||
view.setAttached(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChangeHandlerHistory {
|
||||
|
||||
private List<Entry> entries = new ArrayList<>();
|
||||
public boolean isValidHistory = true;
|
||||
|
||||
public void addEntry(View from, View to, boolean isPush, MockChangeHandler handler) {
|
||||
entries.add(new Entry(from, to, isPush, handler));
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
public View fromViewAt(int index) {
|
||||
return entries.get(index).from;
|
||||
}
|
||||
|
||||
public View toViewAt(int index) {
|
||||
return entries.get(index).to;
|
||||
}
|
||||
|
||||
public boolean isPushAt(int index) {
|
||||
return entries.get(index).isPush;
|
||||
}
|
||||
|
||||
public MockChangeHandler changeHandlerAt(int index) {
|
||||
return entries.get(index).changeHandler;
|
||||
}
|
||||
|
||||
public View latestFromView() {
|
||||
return fromViewAt(size() - 1);
|
||||
}
|
||||
|
||||
public View latestToView() {
|
||||
return toViewAt(size() - 1);
|
||||
}
|
||||
|
||||
public boolean latestIsPush() {
|
||||
return isPushAt(size() - 1);
|
||||
}
|
||||
|
||||
public MockChangeHandler latestChangeHandler() {
|
||||
return changeHandlerAt(size() - 1);
|
||||
}
|
||||
|
||||
private static class Entry {
|
||||
final View from;
|
||||
final View to;
|
||||
final boolean isPush;
|
||||
final MockChangeHandler changeHandler;
|
||||
|
||||
Entry(View from, View to, boolean isPush, MockChangeHandler changeHandler) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.isPush = isPush;
|
||||
this.changeHandler = changeHandler;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ListUtils {
|
||||
|
||||
public static <T> List<T> listOf(T... elements) {
|
||||
List<T> list = new ArrayList<>();
|
||||
for (T element : elements) {
|
||||
list.add(element);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
|
||||
public class MockChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
private static final String KEY_REMOVES_FROM_VIEW_ON_PUSH = "MockChangeHandler.removesFromViewOnPush";
|
||||
private static final String KEY_TAG = "MockChangeHandler.tag";
|
||||
|
||||
public static class ChangeHandlerListener {
|
||||
public void willStartChange() { }
|
||||
public void didAttachOrDetach() { }
|
||||
public void didEndChange() { }
|
||||
}
|
||||
|
||||
private final ChangeHandlerListener listener;
|
||||
private boolean removesFromViewOnPush;
|
||||
|
||||
public View from;
|
||||
public View to;
|
||||
public String tag;
|
||||
|
||||
public static MockChangeHandler defaultHandler() {
|
||||
return new MockChangeHandler(true, null, null);
|
||||
}
|
||||
|
||||
public static MockChangeHandler noRemoveViewOnPushHandler() {
|
||||
return new MockChangeHandler(false, null, null);
|
||||
}
|
||||
|
||||
public static MockChangeHandler listeningChangeHandler(@NonNull ChangeHandlerListener listener) {
|
||||
return new MockChangeHandler(true, null, listener);
|
||||
}
|
||||
|
||||
public static MockChangeHandler taggedHandler(String tag, boolean removeViewOnPush) {
|
||||
return new MockChangeHandler(removeViewOnPush, tag, null);
|
||||
}
|
||||
|
||||
public MockChangeHandler() {
|
||||
listener = null;
|
||||
}
|
||||
|
||||
private MockChangeHandler(boolean removesFromViewOnPush, String tag, ChangeHandlerListener listener) {
|
||||
this.removesFromViewOnPush = removesFromViewOnPush;
|
||||
|
||||
if (listener == null) {
|
||||
this.listener = new ChangeHandlerListener() { };
|
||||
} else {
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
|
||||
listener.willStartChange();
|
||||
|
||||
if (isPush) {
|
||||
if (to != null) {
|
||||
container.addView(to);
|
||||
listener.didAttachOrDetach();
|
||||
}
|
||||
|
||||
if (removesFromViewOnPush && from != null) {
|
||||
container.removeView(from);
|
||||
}
|
||||
} else {
|
||||
container.removeView(from);
|
||||
listener.didAttachOrDetach();
|
||||
|
||||
if (to != null) {
|
||||
container.addView(to);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
changeListener.onChangeCompleted();
|
||||
listener.didEndChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removesFromViewOnPush() {
|
||||
return removesFromViewOnPush;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToBundle(@NonNull Bundle bundle) {
|
||||
super.saveToBundle(bundle);
|
||||
bundle.putBoolean(KEY_REMOVES_FROM_VIEW_ON_PUSH, removesFromViewOnPush);
|
||||
bundle.putString(KEY_TAG, tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(@NonNull Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
removesFromViewOnPush = bundle.getBoolean(KEY_REMOVES_FROM_VIEW_ON_PUSH);
|
||||
tag = bundle.getString(KEY_TAG);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ControllerChangeHandler copy() {
|
||||
return new MockChangeHandler(removesFromViewOnPush, tag, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReusable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
+17
-9
@@ -1,4 +1,4 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
@@ -11,6 +11,10 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
|
||||
public class TestController extends Controller {
|
||||
|
||||
@IdRes public static final int VIEW_ID = 2342;
|
||||
@@ -19,11 +23,8 @@ public class TestController extends Controller {
|
||||
|
||||
private static final String KEY_CALL_STATE = "TestController.currentCallState";
|
||||
|
||||
public CallState currentCallState;
|
||||
|
||||
public TestController() {
|
||||
currentCallState = new CallState();
|
||||
}
|
||||
public CallState currentCallState = new CallState();
|
||||
public ChangeHandlerHistory changeHandlerHistory = new ChangeHandlerHistory();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@@ -32,11 +33,11 @@ public class TestController extends Controller {
|
||||
FrameLayout view = new AttachFakingFrameLayout(inflater.getContext());
|
||||
view.setId(VIEW_ID);
|
||||
|
||||
FrameLayout childContainer1 = new FrameLayout(inflater.getContext());
|
||||
FrameLayout childContainer1 = new AttachFakingFrameLayout(inflater.getContext());
|
||||
childContainer1.setId(CHILD_VIEW_ID_1);
|
||||
view.addView(childContainer1);
|
||||
|
||||
FrameLayout childContainer2 = new FrameLayout(inflater.getContext());
|
||||
FrameLayout childContainer2 = new AttachFakingFrameLayout(inflater.getContext());
|
||||
childContainer2.setId(CHILD_VIEW_ID_2);
|
||||
view.addView(childContainer2);
|
||||
|
||||
@@ -53,6 +54,13 @@ public class TestController extends Controller {
|
||||
protected void onChangeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
super.onChangeEnded(changeHandler, changeType);
|
||||
currentCallState.changeEndCalls++;
|
||||
|
||||
if (changeHandler instanceof MockChangeHandler) {
|
||||
MockChangeHandler mockHandler = (MockChangeHandler)changeHandler;
|
||||
changeHandlerHistory.addEntry(mockHandler.from, mockHandler.to, changeType.isPush, mockHandler);
|
||||
} else {
|
||||
changeHandlerHistory.isValidHistory = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,7 +76,7 @@ public class TestController extends Controller {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(View view) {
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
currentCallState.destroyViewCalls++;
|
||||
}
|
||||
+14
-1
@@ -1,7 +1,8 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@@ -10,6 +11,10 @@ import java.util.List;
|
||||
public class ViewUtils {
|
||||
|
||||
public static void reportAttached(View view, boolean attached) {
|
||||
reportAttached(view, attached, true);
|
||||
}
|
||||
|
||||
public static void reportAttached(View view, boolean attached, boolean propogateToChildren) {
|
||||
if (view instanceof AttachFakingFrameLayout) {
|
||||
((AttachFakingFrameLayout)view).setAttached(attached, false);
|
||||
}
|
||||
@@ -38,6 +43,14 @@ public class ViewUtils {
|
||||
}
|
||||
}
|
||||
|
||||
if (propogateToChildren && view instanceof ViewGroup) {
|
||||
ViewGroup viewGroup = (ViewGroup)view;
|
||||
int childCount = viewGroup.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
reportAttached(viewGroup.getChildAt(i), attached, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static List<OnAttachStateChangeListener> getAttachStateListeners(View view) {
|
||||
+10
-4
@@ -11,11 +11,12 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.neenbedankt.android-apt'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.2"
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '24.0.3'
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
abortOnError true
|
||||
ignore 'UnusedResources'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@@ -26,7 +27,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId "com.bluelinelabs.conductor.demo"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 23
|
||||
targetSdkVersion 25
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
}
|
||||
@@ -37,6 +38,10 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/rxjava.properties'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -49,6 +54,7 @@ dependencies {
|
||||
|
||||
compile project(':conductor-support')
|
||||
compile project(':conductor-rxlifecycle')
|
||||
compile project(':conductor-rxlifecycle2')
|
||||
|
||||
debugCompile rootProject.ext.leakCanary
|
||||
releaseCompile rootProject.ext.leakCanaryNoOp
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ public class CircularRevealChangeHandler extends AnimatorChangeHandler {
|
||||
this.cy = cy;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer) {
|
||||
final float radius = (float) Math.hypot(cx, cy);
|
||||
Animator animator = null;
|
||||
|
||||
+4
-3
@@ -16,14 +16,15 @@ public class CircularRevealChangeHandlerCompat extends CircularRevealChangeHandl
|
||||
super(fromView, containerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
return super.getAnimator(container, from, to, isPush, toAddedToContainer);
|
||||
} else {
|
||||
AnimatorSet animator = new AnimatorSet();
|
||||
if (to != null && toAddedToContainer) {
|
||||
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, 0, 1));
|
||||
if (to != null) {
|
||||
float start = toAddedToContainer ? 0 : to.getAlpha();
|
||||
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, start, 1));
|
||||
}
|
||||
|
||||
if (from != null) {
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ public class FlipChangeHandler extends AnimatorChangeHandler {
|
||||
this.animationDuration = animationDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
|
||||
|
||||
+4
-3
@@ -15,11 +15,12 @@ public class ScaleFadeChangeHandler extends AnimatorChangeHandler {
|
||||
super(DEFAULT_ANIMATION_DURATION, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
protected Animator getAnimator(@NonNull ViewGroup container, View from, View to, boolean isPush, boolean toAddedToContainer) {
|
||||
AnimatorSet animator = new AnimatorSet();
|
||||
if (to != null && toAddedToContainer) {
|
||||
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, 0, 1));
|
||||
if (to != null) {
|
||||
float start = toAddedToContainer ? 0 : to.getAlpha();
|
||||
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, start, 1));
|
||||
}
|
||||
|
||||
if (from != null) {
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class DragDismissController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(View view) {
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
|
||||
((ElasticDragDismissFrameLayout)view).removeListener(dragDismissListener);
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.controllers.NavigationDemoController.DisplayUpMode;
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController;
|
||||
|
||||
import butterknife.BindView;
|
||||
@@ -45,6 +46,7 @@ public class HomeController extends BaseController {
|
||||
MASTER_DETAIL("Master Detail", R.color.grey_300),
|
||||
DRAG_DISMISS("Drag Dismiss", R.color.lime_300),
|
||||
RX_LIFECYCLE("Rx Lifecycle", R.color.teal_300),
|
||||
RX_LIFECYCLE_2("Rx Lifecycle 2", R.color.brown_300),
|
||||
OVERLAY("Overlay Controller", R.color.purple_300);
|
||||
|
||||
String title;
|
||||
@@ -79,7 +81,7 @@ public class HomeController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.home, menu);
|
||||
}
|
||||
@@ -94,7 +96,7 @@ public class HomeController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == R.id.about) {
|
||||
SpannableString details = new SpannableString("A small, yet full-featured framework that allows building View-based Android applications");
|
||||
details.setSpan(new AbsoluteSizeSpan(16, true), 0, details.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
@@ -115,7 +117,7 @@ public class HomeController extends BaseController {
|
||||
content.append("\n\n");
|
||||
content.append(link);
|
||||
|
||||
getChildRouter(overlayRoot, null)
|
||||
getChildRouter(overlayRoot)
|
||||
.setPopsLastView(true)
|
||||
.setRoot(RouterTransaction.with(new OverlayController(content))
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
@@ -133,7 +135,7 @@ public class HomeController extends BaseController {
|
||||
void onModelRowClick(HomeDemoModel model) {
|
||||
switch (model) {
|
||||
case NAVIGATION:
|
||||
getRouter().pushController(RouterTransaction.with(new NavigationDemoController(0, true))
|
||||
getRouter().pushController(RouterTransaction.with(new NavigationDemoController(0, DisplayUpMode.SHOW_FOR_CHILDREN_ONLY))
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler())
|
||||
.tag(NavigationDemoController.TAG_UP_TRANSACTION)
|
||||
@@ -159,7 +161,7 @@ public class HomeController extends BaseController {
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case OVERLAY:
|
||||
getChildRouter(overlayRoot, null)
|
||||
getChildRouter(overlayRoot)
|
||||
.setPopsLastView(true)
|
||||
.setRoot(RouterTransaction.with(new OverlayController("I'm an overlay!"))
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
@@ -175,6 +177,11 @@ public class HomeController extends BaseController {
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case RX_LIFECYCLE_2:
|
||||
getRouter().pushController(RouterTransaction.with(new RxLifecycle2Controller())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case MULTIPLE_CHILD_ROUTERS:
|
||||
getRouter().pushController(RouterTransaction.with(new MultipleChildRouterController())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ public class MasterDetailListController extends BaseController {
|
||||
ChildController controller = new ChildController(model.detail, model.backgroundColor, true);
|
||||
|
||||
if (twoPaneView) {
|
||||
getChildRouter(detailContainer, null).setRoot(RouterTransaction.with(controller));
|
||||
getChildRouter(detailContainer).setRoot(RouterTransaction.with(controller));
|
||||
} else {
|
||||
getRouter().pushController(RouterTransaction.with(controller)
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
|
||||
+3
-2
@@ -8,6 +8,7 @@ import android.view.ViewGroup;
|
||||
import com.bluelinelabs.conductor.Router;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.controllers.NavigationDemoController.DisplayUpMode;
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController;
|
||||
|
||||
import butterknife.BindViews;
|
||||
@@ -26,9 +27,9 @@ public class MultipleChildRouterController extends BaseController {
|
||||
super.onViewBound(view);
|
||||
|
||||
for (ViewGroup childContainer : childContainers) {
|
||||
Router childRouter = getChildRouter(childContainer, null).setPopsLastView(false);
|
||||
Router childRouter = getChildRouter(childContainer).setPopsLastView(false);
|
||||
if (!childRouter.hasRootController()) {
|
||||
childRouter.setRoot(RouterTransaction.with(new NavigationDemoController(0, false)));
|
||||
childRouter.setRoot(RouterTransaction.with(new NavigationDemoController(0, DisplayUpMode.HIDE)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+47
-7
@@ -7,6 +7,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
@@ -19,27 +21,42 @@ import butterknife.OnClick;
|
||||
|
||||
public class NavigationDemoController extends BaseController {
|
||||
|
||||
public enum DisplayUpMode {
|
||||
SHOW,
|
||||
SHOW_FOR_CHILDREN_ONLY,
|
||||
HIDE;
|
||||
|
||||
private DisplayUpMode getDisplayUpModeForChild() {
|
||||
switch (this) {
|
||||
case HIDE:
|
||||
return HIDE;
|
||||
default:
|
||||
return SHOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final String TAG_UP_TRANSACTION = "NavigationDemoController.up";
|
||||
|
||||
private static final String KEY_INDEX = "NavigationDemoController.index";
|
||||
private static final String KEY_DISPLAY_UP = "NavigationDemoController.displayUp";
|
||||
private static final String KEY_DISPLAY_UP_MODE = "NavigationDemoController.displayUpMode";
|
||||
|
||||
@BindView(R.id.tv_title) TextView tvTitle;
|
||||
|
||||
private int index;
|
||||
private boolean displayUp;
|
||||
private DisplayUpMode displayUpMode;
|
||||
|
||||
public NavigationDemoController(int index, boolean displayUpButton) {
|
||||
public NavigationDemoController(int index, DisplayUpMode displayUpMode) {
|
||||
this(new BundleBuilder(new Bundle())
|
||||
.putInt(KEY_INDEX, index)
|
||||
.putBoolean(KEY_DISPLAY_UP, displayUpButton)
|
||||
.putInt(KEY_DISPLAY_UP_MODE, displayUpMode.ordinal())
|
||||
.build());
|
||||
}
|
||||
|
||||
public NavigationDemoController(Bundle args) {
|
||||
super(args);
|
||||
index = args.getInt(KEY_INDEX);
|
||||
displayUp = args.getBoolean(KEY_DISPLAY_UP);
|
||||
displayUpMode = DisplayUpMode.values()[args.getInt(KEY_DISPLAY_UP_MODE)];
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -52,7 +69,7 @@ public class NavigationDemoController extends BaseController {
|
||||
protected void onViewBound(@NonNull View view) {
|
||||
super.onViewBound(view);
|
||||
|
||||
if (!displayUp) {
|
||||
if (displayUpMode != DisplayUpMode.SHOW) {
|
||||
view.findViewById(R.id.btn_up).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@@ -60,13 +77,36 @@ public class NavigationDemoController extends BaseController {
|
||||
tvTitle.setText(getResources().getString(R.string.navigation_title, index));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
super.onChangeEnded(changeHandler, changeType);
|
||||
|
||||
setButtonsEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangeStarted(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
super.onChangeStarted(changeHandler, changeType);
|
||||
|
||||
setButtonsEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTitle() {
|
||||
return "Navigation Demos";
|
||||
}
|
||||
|
||||
private void setButtonsEnabled(boolean enabled) {
|
||||
final View view = getView();
|
||||
if (view != null) {
|
||||
view.findViewById(R.id.btn_next).setEnabled(enabled);
|
||||
view.findViewById(R.id.btn_up).setEnabled(enabled);
|
||||
view.findViewById(R.id.btn_pop_to_root).setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next) void onNextClicked() {
|
||||
getRouter().pushController(RouterTransaction.with(new NavigationDemoController(index + 1, displayUp))
|
||||
getRouter().pushController(RouterTransaction.with(new NavigationDemoController(index + 1, displayUpMode.getDisplayUpModeForChild()))
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
|
||||
+13
-6
@@ -8,9 +8,13 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.Router;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController;
|
||||
import com.bluelinelabs.conductor.support.ControllerPagerAdapter;
|
||||
import com.bluelinelabs.conductor.support.RouterPagerAdapter;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
||||
@@ -21,13 +25,16 @@ public class PagerController extends BaseController {
|
||||
@BindView(R.id.tab_layout) TabLayout tabLayout;
|
||||
@BindView(R.id.view_pager) ViewPager viewPager;
|
||||
|
||||
private final ControllerPagerAdapter pagerAdapter;
|
||||
private final RouterPagerAdapter pagerAdapter;
|
||||
|
||||
public PagerController() {
|
||||
pagerAdapter = new ControllerPagerAdapter(this, false) {
|
||||
pagerAdapter = new RouterPagerAdapter(this) {
|
||||
@Override
|
||||
public Controller getItem(int position) {
|
||||
return new ChildController(String.format("Child #%d (Swipe to see more)", position), PAGE_COLORS[position], true);
|
||||
public void configureRouter(Router router, int position) {
|
||||
if (!router.hasRootController()) {
|
||||
Controller page = new ChildController(String.format(Locale.getDefault(), "Child #%d (Swipe to see more)", position), PAGE_COLORS[position], true);
|
||||
router.setRoot(RouterTransaction.with(page));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,7 +57,7 @@ public class PagerController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(View view) {
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
viewPager.setAdapter(null);
|
||||
super.onDestroyView(view);
|
||||
}
|
||||
|
||||
+14
-12
@@ -42,7 +42,7 @@ public class ParentController extends BaseController {
|
||||
private void addChild(final int index) {
|
||||
@IdRes final int frameId = getResources().getIdentifier("child_content_" + (index + 1), "id", getActivity().getPackageName());
|
||||
final ViewGroup container = (ViewGroup)getView().findViewById(frameId);
|
||||
final Router childRouter = getChildRouter(container, null).setPopsLastView(true);
|
||||
final Router childRouter = getChildRouter(container).setPopsLastView(true);
|
||||
|
||||
if (!childRouter.hasRootController()) {
|
||||
ChildController childController = new ChildController("Child Controller #" + index, ColorUtil.getMaterialColor(getResources(), index), false);
|
||||
@@ -50,17 +50,19 @@ public class ParentController extends BaseController {
|
||||
childController.addLifecycleListener(new LifecycleListener() {
|
||||
@Override
|
||||
public void onChangeEnd(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
if (changeType == ControllerChangeType.PUSH_ENTER && !hasShownAll) {
|
||||
if (index < NUMBER_OF_CHILDREN - 1) {
|
||||
addChild(index + 1);
|
||||
} else {
|
||||
hasShownAll = true;
|
||||
}
|
||||
} else if (changeType == ControllerChangeType.POP_EXIT) {
|
||||
if (index > 0) {
|
||||
removeChild(index - 1);
|
||||
} else {
|
||||
getRouter().popController(ParentController.this);
|
||||
if (!isBeingDestroyed()) {
|
||||
if (changeType == ControllerChangeType.PUSH_ENTER && !hasShownAll) {
|
||||
if (index < NUMBER_OF_CHILDREN - 1) {
|
||||
addChild(index + 1);
|
||||
} else {
|
||||
hasShownAll = true;
|
||||
}
|
||||
} else if (changeType == ControllerChangeType.POP_EXIT) {
|
||||
if (index > 0) {
|
||||
removeChild(index - 1);
|
||||
} else {
|
||||
getRouter().popController(ParentController.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+163
@@ -0,0 +1,163 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.ActionBarProvider;
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.rxlifecycle2.ControllerEvent;
|
||||
import com.bluelinelabs.conductor.rxlifecycle2.RxController;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
|
||||
// Shamelessly borrowed from the official RxLifecycle demo by Trello and adapted for Conductor Controllers
|
||||
// instead of Activities or Fragments.
|
||||
public class RxLifecycle2Controller extends RxController {
|
||||
|
||||
private static final String TAG = "RxLifecycleController";
|
||||
|
||||
@BindView(R.id.tv_title) TextView tvTitle;
|
||||
|
||||
private Unbinder unbinder;
|
||||
private boolean hasExited;
|
||||
|
||||
public RxLifecycle2Controller() {
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose(new Action() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Disposing from constructor");
|
||||
}
|
||||
})
|
||||
.compose(this.<Long>bindUntilEvent(ControllerEvent.DESTROY))
|
||||
.subscribe(new Consumer<Long>() {
|
||||
@Override
|
||||
public void accept(Long num) {
|
||||
Log.i(TAG, "Started in constructor, running until onDestroy(): " + num);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
Log.i(TAG, "onCreateView() called");
|
||||
|
||||
View view = inflater.inflate(R.layout.controller_rxlifecycle, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
tvTitle.setText(getResources().getString(R.string.rxlifecycle_title, TAG));
|
||||
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose(new Action() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Disposing from onCreateView)");
|
||||
}
|
||||
})
|
||||
.compose(this.<Long>bindUntilEvent(ControllerEvent.DESTROY_VIEW))
|
||||
.subscribe(new Consumer<Long>() {
|
||||
@Override
|
||||
public void accept(Long num) {
|
||||
Log.i(TAG, "Started in onCreateView(), running until onDestroyView(): " + num);
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(@NonNull View view) {
|
||||
super.onAttach(view);
|
||||
|
||||
Log.i(TAG, "onAttach() called");
|
||||
|
||||
(((ActionBarProvider)getActivity()).getSupportActionBar()).setTitle("RxLifecycle2 Demo");
|
||||
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose(new Action() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Disposing from onAttach()");
|
||||
}
|
||||
})
|
||||
.compose(this.<Long>bindUntilEvent(ControllerEvent.DETACH))
|
||||
.subscribe(new Consumer<Long>() {
|
||||
@Override
|
||||
public void accept(Long num) {
|
||||
Log.i(TAG, "Started in onAttach(), running until onDetach(): " + num);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
|
||||
Log.i(TAG, "onDestroyView() called");
|
||||
|
||||
unbinder.unbind();
|
||||
unbinder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach(@NonNull View view) {
|
||||
super.onDetach(view);
|
||||
|
||||
Log.i(TAG, "onDetach() called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
Log.i(TAG, "onDestroy() called");
|
||||
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
super.onChangeEnded(changeHandler, changeType);
|
||||
|
||||
hasExited = !changeType.isEnter;
|
||||
if (isDestroyed()) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next_release_view) void onNextWithReleaseClicked() {
|
||||
setRetainViewMode(RetainViewMode.RELEASE_DETACH);
|
||||
|
||||
getRouter().pushController(RouterTransaction.with(new TextController("Logcat should now report that the observables from onAttach() and onViewBound() have been disposed of, while the constructor observable is still running."))
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next_retain_view) void onNextWithRetainClicked() {
|
||||
setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
|
||||
getRouter().pushController(RouterTransaction.with(new TextController("Logcat should now report that the observables from onAttach() has been disposed of, while the constructor and onViewBound() observables are still running."))
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
}
|
||||
+34
-12
@@ -7,30 +7,38 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.ActionBarProvider;
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController;
|
||||
import com.bluelinelabs.conductor.rxlifecycle.ControllerEvent;
|
||||
import com.bluelinelabs.conductor.rxlifecycle.RxController;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
import rx.Observable;
|
||||
import rx.functions.Action0;
|
||||
import rx.functions.Action1;
|
||||
|
||||
// Shamelessly borrowed from the official RxLifecycle demo by Trello and adapted for Conductor Controllers
|
||||
// instead of Activities or Fragments.
|
||||
public class RxLifecycleController extends BaseController {
|
||||
public class RxLifecycleController extends RxController {
|
||||
|
||||
private static final String TAG = "RxLifecycleController";
|
||||
|
||||
@BindView(R.id.tv_title) TextView tvTitle;
|
||||
|
||||
public RxLifecycleController() {
|
||||
private Unbinder unbinder;
|
||||
private boolean hasExited;
|
||||
|
||||
public RxLifecycleController() {
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnUnsubscribe(new Action0() {
|
||||
@Override
|
||||
@@ -47,10 +55,14 @@ public class RxLifecycleController extends BaseController {
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public void onViewBound(@NonNull View view) {
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
Log.i(TAG, "onCreateView() called");
|
||||
|
||||
View view = inflater.inflate(R.layout.controller_rxlifecycle, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
tvTitle.setText(getResources().getString(R.string.rxlifecycle_title, TAG));
|
||||
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
@@ -67,6 +79,8 @@ public class RxLifecycleController extends BaseController {
|
||||
Log.i(TAG, "Started in onCreateView(), running until onDestroyView(): " + num);
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,6 +89,8 @@ public class RxLifecycleController extends BaseController {
|
||||
|
||||
Log.i(TAG, "onAttach() called");
|
||||
|
||||
(((ActionBarProvider)getActivity()).getSupportActionBar()).setTitle("RxLifecycle Demo");
|
||||
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnUnsubscribe(new Action0() {
|
||||
@Override
|
||||
@@ -92,10 +108,13 @@ public class RxLifecycleController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(View view) {
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
|
||||
Log.i(TAG, "onDestroyView() called");
|
||||
|
||||
unbinder.unbind();
|
||||
unbinder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,17 +129,20 @@ public class RxLifecycleController extends BaseController {
|
||||
super.onDestroy();
|
||||
|
||||
Log.i(TAG, "onDestroy() called");
|
||||
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTitle() {
|
||||
return "RxLifecycle Demo";
|
||||
}
|
||||
protected void onChangeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
super.onChangeEnded(changeHandler, changeType);
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return inflater.inflate(R.layout.controller_rxlifecycle, container, false);
|
||||
hasExited = !changeType.isEnter;
|
||||
if (isDestroyed()) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next_release_view) void onNextWithReleaseClicked() {
|
||||
|
||||
+3
-3
@@ -6,12 +6,12 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.rxlifecycle.RxController;
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public abstract class ButterKnifeController extends RxController {
|
||||
public abstract class ButterKnifeController extends Controller {
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
||||
@@ -34,7 +34,7 @@ public abstract class ButterKnifeController extends RxController {
|
||||
protected void onViewBound(@NonNull View view) { }
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(View view) {
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
unbinder.unbind();
|
||||
unbinder = null;
|
||||
|
||||
+2
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.bluelinelabs.conductor.demo.widget;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.support.v4.view.NestedScrollingParent;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
@@ -32,6 +33,7 @@ import java.util.List;
|
||||
* Applies an elasticity factor to reduce movement as you approach the given dismiss distance.
|
||||
* Optionally also scales down content during drag.
|
||||
*/
|
||||
@TargetApi(21)
|
||||
public class ElasticDragDismissFrameLayout extends FrameLayout implements NestedScrollingParent {
|
||||
|
||||
public static abstract class ElasticDragDismissCallback {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="InconsistentLayout">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
android:textSize="22sp"
|
||||
android:padding="16dp"
|
||||
android:text="@string/drag_to_dismiss"
|
||||
android:clickable="true"
|
||||
/>
|
||||
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#88000000" >
|
||||
android:background="#88000000"
|
||||
android:clickable="true" >
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
@@ -13,6 +14,7 @@
|
||||
android:elevation="6dp"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
tools:targetApi="lollipop"
|
||||
/>
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/transition_root"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
@@ -19,6 +20,7 @@
|
||||
android:layout_marginTop="96dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:transitionName="@string/transition_tag_title"
|
||||
tools:targetApi="lollipop"
|
||||
/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
@@ -31,6 +33,7 @@
|
||||
app:elevation="0dp"
|
||||
app:pressedTranslationZ="0dp"
|
||||
android:transitionName="@string/transition_tag_dot"
|
||||
tools:targetApi="lollipop"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/transition_root"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
@@ -13,6 +14,7 @@
|
||||
android:layout_marginTop="24dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:transitionName="@string/transition_tag_title"
|
||||
tools:targetApi="lollipop"
|
||||
/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
@@ -24,6 +26,7 @@
|
||||
app:elevation="0dp"
|
||||
app:pressedTranslationZ="0dp"
|
||||
android:transitionName="@string/transition_tag_dot"
|
||||
tools:targetApi="lollipop"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -1,23 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="mdcolor_300">
|
||||
<item name="red_300" type="color">@color/red_300</item>
|
||||
<item name="light_green_300" type="color">@color/light_green_300</item>
|
||||
<item name="teal_300" type="color">@color/teal_300</item>
|
||||
<item name="pink_300" type="color">@color/pink_300</item>
|
||||
<item name="brown_300" type="color">@color/brown_300</item>
|
||||
<item name="purple_300" type="color">@color/purple_300</item>
|
||||
<item name="lime_300" type="color">@color/lime_300</item>
|
||||
<item name="blue_grey_300" type="color">@color/blue_grey_300</item>
|
||||
<item name="deep_purple_300" type="color">@color/deep_purple_300</item>
|
||||
<item name="green_300" type="color">@color/green_300</item>
|
||||
<item name="indigo_300" type="color">@color/indigo_300</item>
|
||||
<item name="yellow_300" type="color">@color/yellow_300</item>
|
||||
<item name="blue_300" type="color">@color/blue_300</item>
|
||||
<item name="orange_300" type="color">@color/orange_300</item>
|
||||
<item name="light_blue_300" type="color">@color/light_blue_300</item>
|
||||
<item name="deep_orange_300" type="color">@color/deep_orange_300</item>
|
||||
<item name="cyan_300" type="color">@color/cyan_300</item>
|
||||
<item name="grey_300" type="color">@color/grey_300</item>
|
||||
<item name="md_red_300" type="color">@color/red_300</item>
|
||||
<item name="md_light_green_300" type="color">@color/light_green_300</item>
|
||||
<item name="md_teal_300" type="color">@color/teal_300</item>
|
||||
<item name="md_pink_300" type="color">@color/pink_300</item>
|
||||
<item name="md_brown_300" type="color">@color/brown_300</item>
|
||||
<item name="md_purple_300" type="color">@color/purple_300</item>
|
||||
<item name="md_lime_300" type="color">@color/lime_300</item>
|
||||
<item name="md_blue_grey_300" type="color">@color/blue_grey_300</item>
|
||||
<item name="md_deep_purple_300" type="color">@color/deep_purple_300</item>
|
||||
<item name="md_green_300" type="color">@color/green_300</item>
|
||||
<item name="md_indigo_300" type="color">@color/indigo_300</item>
|
||||
<item name="md_yellow_300" type="color">@color/yellow_300</item>
|
||||
<item name="md_blue_300" type="color">@color/blue_300</item>
|
||||
<item name="md_orange_300" type="color">@color/orange_300</item>
|
||||
<item name="md_light_blue_300" type="color">@color/light_blue_300</item>
|
||||
<item name="md_deep_orange_300" type="color">@color/deep_orange_300</item>
|
||||
<item name="md_cyan_300" type="color">@color/cyan_300</item>
|
||||
<item name="md_grey_300" type="color">@color/grey_300</item>
|
||||
</array>
|
||||
</resources>
|
||||
+39
-20
@@ -1,30 +1,49 @@
|
||||
ext {
|
||||
minSdkVersion = 16
|
||||
compileSdkVersion = 23
|
||||
targetSdkVersion = 23
|
||||
buildToolsVersion = '23.0.2'
|
||||
compileSdkVersion = 25
|
||||
targetSdkVersion = 25
|
||||
buildToolsVersion = '24.0.3'
|
||||
|
||||
supportV4 = 'com.android.support:support-v4:23.1.1'
|
||||
supportDesign = 'com.android.support:design:23.1.1'
|
||||
supportAnnotations = 'com.android.support:support-annotations:23.1.1'
|
||||
supportAppCompat = 'com.android.support:appcompat-v7:23.1.1'
|
||||
supportVersion = '23.1.1'
|
||||
butterknifeVersion = '8.0.1'
|
||||
picassoVersion = '2.5.2'
|
||||
leakCanaryVersion = '1.4'
|
||||
rxJavaVersion = '1.2.0'
|
||||
rxJava2Version = '2.0.1'
|
||||
rxLifecycleVersion = '0.8.0'
|
||||
rxLifecycle2Version = '2.0'
|
||||
junitVersion = '4.11'
|
||||
roboelectricVersion = '3.0'
|
||||
lintVersion = '25.2.0'
|
||||
|
||||
butterknife = 'com.jakewharton:butterknife:8.0.1'
|
||||
butterknifeCompiler = 'com.jakewharton:butterknife-compiler:8.0.1'
|
||||
supportV4 = "com.android.support:support-v4:$supportVersion"
|
||||
supportDesign = "com.android.support:design:$supportVersion"
|
||||
supportAnnotations = "com.android.support:support-annotations:$supportVersion"
|
||||
supportAppCompat = "com.android.support:appcompat-v7:$supportVersion"
|
||||
|
||||
picasso = 'com.squareup.picasso:picasso:2.5.2'
|
||||
butterknife = "com.jakewharton:butterknife:$butterknifeVersion"
|
||||
butterknifeCompiler = "com.jakewharton:butterknife-compiler:$butterknifeVersion"
|
||||
|
||||
leakCanary = 'com.squareup.leakcanary:leakcanary-android:1.4'
|
||||
leakCanaryNoOp = 'com.squareup.leakcanary:leakcanary-android-no-op:1.4'
|
||||
picasso = "com.squareup.picasso:picasso:$picassoVersion"
|
||||
|
||||
rxJava = 'io.reactivex:rxjava:1.2.0'
|
||||
rxAndroid = 'io.reactivex:rxandroid:1.2.1'
|
||||
rxLifecycle = 'com.trello:rxlifecycle:0.8.0'
|
||||
rxLifecycleAndroid = 'com.trello:rxlifecycle-android:0.8.0'
|
||||
leakCanary = "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
|
||||
leakCanaryNoOp = "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
|
||||
|
||||
junit = 'junit:junit:4.11'
|
||||
roboelectric = 'org.robolectric:robolectric:3.0'
|
||||
rxJava = "io.reactivex:rxjava:$rxJavaVersion"
|
||||
rxJava2 = "io.reactivex.rxjava2:rxjava:$rxJava2Version"
|
||||
|
||||
rxLifecycle = "com.trello:rxlifecycle:$rxLifecycleVersion"
|
||||
rxLifecycleAndroid = "com.trello:rxlifecycle-android:$rxLifecycleVersion"
|
||||
|
||||
rxLifecycle2 = "com.trello.rxlifecycle2:rxlifecycle:$rxLifecycle2Version"
|
||||
rxLifecycleAndroid2 = "com.trello.rxlifecycle2:rxlifecycle-android:$rxLifecycle2Version"
|
||||
|
||||
junit = "junit:junit:$junitVersion"
|
||||
roboelectric = "org.robolectric:robolectric:$roboelectricVersion"
|
||||
|
||||
lintapi = "com.android.tools.lint:lint-api:$lintVersion"
|
||||
lintchecks = "com.android.tools.lint:lint-checks:$lintVersion"
|
||||
lint = "com.android.tools.lint:lint:$lintVersion"
|
||||
lintTests = "com.android.tools.lint:lint-tests:$lintVersion"
|
||||
|
||||
lintapi = 'com.android.tools.lint:lint-api:24.5.0'
|
||||
lintchecks = 'com.android.tools.lint:lint-checks:24.5.0'
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 65 KiB |
+1
-1
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=2.0.4-SNAPSHOT
|
||||
VERSION_NAME=2.1.1-SNAPSHOT
|
||||
VERSION_CODE=2
|
||||
GROUP=com.bluelinelabs
|
||||
|
||||
|
||||
+5
-4
@@ -1,5 +1,6 @@
|
||||
include ':conductor'
|
||||
include':conductor-support'
|
||||
include':conductor-rxlifecycle'
|
||||
include':conductor-lint'
|
||||
include':demo'
|
||||
include ':conductor-support'
|
||||
include ':conductor-rxlifecycle'
|
||||
include ':conductor-rxlifecycle2'
|
||||
include ':conductor-lint'
|
||||
include ':demo'
|
||||
|
||||
Reference in New Issue
Block a user