Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 90f21d99a5 | |||
| 641e0dc43c | |||
| 91c993b005 | |||
| 39ab4723ff | |||
| 3769e706af | |||
| 26efe8f062 | |||
| 8a890644ee | |||
| b2ffa7f7f6 | |||
| 960b931744 | |||
| 47158da05e | |||
| b9c22d267d | |||
| 46e6fac6db |
+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.2'
|
||||
compile 'com.bluelinelabs:conductor:2.0.6'
|
||||
|
||||
// If you want the components that go along with
|
||||
// Android's support libraries (currently just a PagerAdapter):
|
||||
compile 'com.bluelinelabs:conductor-support:2.0.2'
|
||||
compile 'com.bluelinelabs:conductor-support:2.0.6'
|
||||
|
||||
// If you want RxJava/RxAndroid lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.0.2'
|
||||
// If you want RxJava lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.0.6'
|
||||
|
||||
// If you want RxJava2 lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle2:2.0.6'
|
||||
```
|
||||
|
||||
SNAPSHOT:
|
||||
|
||||
```gradle
|
||||
compile 'com.bluelinelabs:conductor:2.0.3-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-support:2.0.3-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.0.3-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor:2.0.7-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-support:2.0.7-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.0.7-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle2:2.0.7-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,8 +22,8 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile rootProject.ext.rxJava
|
||||
compile rootProject.ext.rxAndroid
|
||||
compile rootProject.ext.rxLifecycle
|
||||
compile rootProject.ext.rxLifecycleAndroid
|
||||
|
||||
compile project(':conductor')
|
||||
}
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle;
|
||||
|
||||
import android.support.annotation.CheckResult;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* Interface used for RxController. Can also be used if writing your own Controller component without subclassing RxController.
|
||||
*/
|
||||
public interface ControllerLifecycleProvider {
|
||||
|
||||
/**
|
||||
* @return An observable that will have all {@link com.bluelinelabs.conductor.Controller} lifecycle events
|
||||
*/
|
||||
@NonNull
|
||||
@CheckResult
|
||||
Observable<ControllerEvent> lifecycle();
|
||||
|
||||
/**
|
||||
* Will bind the source until a specific {@link ControllerEvent} occurs.
|
||||
*
|
||||
* @param event The {@link ControllerEvent} that should cause onComplete to be called
|
||||
* @return A {@link rx.Observable.Transformer} that will call onComplete when the event occurs.
|
||||
*/
|
||||
@NonNull
|
||||
@CheckResult
|
||||
<T> Observable.Transformer<T, T> bindUntilEvent(@NonNull ControllerEvent event);
|
||||
|
||||
/**
|
||||
* Will bind the source until the next reasonable {@link ControllerEvent} occurs.
|
||||
* @return A {@link rx.Observable.Transformer} that will call onComplete when the event occurs.
|
||||
*/
|
||||
@NonNull
|
||||
@CheckResult
|
||||
<T> Observable.Transformer<T, T> bindToLifecycle();
|
||||
|
||||
}
|
||||
+5
-3
@@ -5,6 +5,8 @@ import android.support.annotation.CheckResult;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.trello.rxlifecycle.LifecycleProvider;
|
||||
import com.trello.rxlifecycle.LifecycleTransformer;
|
||||
import com.trello.rxlifecycle.RxLifecycle;
|
||||
|
||||
import rx.Observable;
|
||||
@@ -13,7 +15,7 @@ import rx.subjects.BehaviorSubject;
|
||||
/**
|
||||
* A base {@link Controller} that can be used to expose lifecycle events using RxJava
|
||||
*/
|
||||
public abstract class RxController extends Controller implements ControllerLifecycleProvider {
|
||||
public abstract class RxController extends Controller implements LifecycleProvider<ControllerEvent> {
|
||||
|
||||
private final BehaviorSubject<ControllerEvent> lifecycleSubject;
|
||||
|
||||
@@ -36,14 +38,14 @@ public abstract class RxController extends Controller implements ControllerLifec
|
||||
@Override
|
||||
@NonNull
|
||||
@CheckResult
|
||||
public final <T> Observable.Transformer<T, T> bindUntilEvent(@NonNull ControllerEvent event) {
|
||||
public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ControllerEvent event) {
|
||||
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
@CheckResult
|
||||
public final <T> Observable.Transformer<T, T> bindToLifecycle() {
|
||||
public final <T> LifecycleTransformer<T> bindToLifecycle() {
|
||||
return RxControllerLifecycle.bindController(lifecycleSubject);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ public class RxControllerLifecycle {
|
||||
|
||||
/**
|
||||
* Binds the given source to a Controller lifecycle. This is the Controller version of
|
||||
* {@link com.trello.rxlifecycle.RxLifecycle#bindFragment(Observable)}.
|
||||
* {@link com.trello.rxlifecycle.android.RxLifecycleAndroid#bindFragment(Observable)}.
|
||||
*
|
||||
* @param lifecycle the lifecycle sequence of a Controller
|
||||
* @return a reusable {@link Observable.Transformer} that unsubscribes the source during the Controller lifecycle
|
||||
|
||||
+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
|
||||
|
||||
+39
-2
@@ -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;
|
||||
@@ -18,10 +19,13 @@ 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.
|
||||
@@ -50,8 +54,9 @@ public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
}
|
||||
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(getItem(position))
|
||||
.tag(name));
|
||||
Controller controller = getItem(position);
|
||||
router.setRoot(RouterTransaction.with(controller).tag(name));
|
||||
visiblePageIds.put(position, controller.getInstanceId());
|
||||
} else {
|
||||
router.rebindIfNeeded();
|
||||
}
|
||||
@@ -69,6 +74,8 @@ public abstract class ControllerPagerAdapter extends PagerAdapter {
|
||||
savedPages.put(position, savedState);
|
||||
}
|
||||
|
||||
visiblePageIds.remove(position);
|
||||
|
||||
host.removeChildRouter(router);
|
||||
}
|
||||
|
||||
@@ -82,6 +89,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 +108,26 @@ 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, if available.
|
||||
*/
|
||||
@Nullable
|
||||
public Controller getController(int position) {
|
||||
String instanceId = visiblePageIds.get(position);
|
||||
if (instanceId != null) {
|
||||
return host.getRouter().getControllerWithInstanceId(instanceId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
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, if available.
|
||||
*/
|
||||
@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,6 +4,7 @@ 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;
|
||||
@@ -30,13 +31,13 @@ public class ActivityHostedRouter extends Router {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@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 +50,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,12 +89,12 @@ public class ActivityHostedRouter extends Router {
|
||||
return lifecycleHandler != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
List<Router> getSiblingRouters() {
|
||||
return lifecycleHandler.getRouters();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
Router getRootRouter() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -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.Router.OnControllerPushedListener;
|
||||
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.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -45,6 +45,7 @@ public abstract class Controller {
|
||||
private static final String KEY_CLASS_NAME = "Controller.className";
|
||||
private static final String KEY_VIEW_STATE = "Controller.viewState";
|
||||
private static final String KEY_CHILD_ROUTERS = "Controller.childRouters";
|
||||
private static final String KEY_CHILD_BACKSTACK = "Controller.childBackstack";
|
||||
private static final String KEY_SAVED_STATE = "Controller.savedState";
|
||||
private static final String KEY_INSTANCE_ID = "Controller.instanceId";
|
||||
private static final String KEY_TARGET_INSTANCE_ID = "Controller.target.instanceId";
|
||||
@@ -59,7 +60,7 @@ public abstract class Controller {
|
||||
|
||||
private final Bundle args;
|
||||
|
||||
private Bundle viewState;
|
||||
Bundle viewState;
|
||||
private Bundle savedInstanceState;
|
||||
private boolean isBeingDestroyed;
|
||||
private boolean destroyed;
|
||||
@@ -74,32 +75,29 @@ 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 final List<Controller> childBackstack = new LinkedList<>();
|
||||
private WeakReference<View> destroyedView;
|
||||
|
||||
private final ControllerChangeListener childRouterChangeListener = new ControllerChangeListener() {
|
||||
private final OnControllerPushedListener onControllerPushedListener = new OnControllerPushedListener() {
|
||||
@Override
|
||||
public void onChangeStarted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
|
||||
if (isPush) {
|
||||
onChildControllerPushed(to);
|
||||
}
|
||||
public void onControllerPushed(Controller controller) {
|
||||
onChildControllerPushed(controller);
|
||||
}
|
||||
|
||||
@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 +131,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 +160,48 @@ 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
|
||||
*/
|
||||
@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).
|
||||
*
|
||||
* @param container The ViewGroup that hosts the child Router
|
||||
* @param tag The router's tag
|
||||
* @param createIfNeeded If true, a router will be created if one does not yet exist. Else false 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,10 +213,12 @@ 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);
|
||||
monitorChildRouter(childRouter);
|
||||
childRouter.setHost(this, container);
|
||||
childRouters.add(childRouter);
|
||||
}
|
||||
} else if (!childRouter.hasHost()) {
|
||||
childRouter.setHost(this, container);
|
||||
monitorChildRouter(childRouter);
|
||||
@@ -193,7 +230,7 @@ public abstract class Controller {
|
||||
|
||||
public final void removeChildRouter(@NonNull Router childRouter) {
|
||||
if ((childRouter instanceof ControllerHostedRouter) && childRouters.remove(childRouter)) {
|
||||
childRouter.destroy();
|
||||
childRouter.destroy(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +258,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Return this Controller's View, if available.
|
||||
*/
|
||||
@Nullable
|
||||
public final View getView() {
|
||||
return view;
|
||||
}
|
||||
@@ -228,6 +266,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Returns the host Activity of this Controller's {@link Router}
|
||||
*/
|
||||
@Nullable
|
||||
public final Activity getActivity() {
|
||||
return router.getActivity();
|
||||
}
|
||||
@@ -235,6 +274,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Returns the Resources from the host Activity
|
||||
*/
|
||||
@Nullable
|
||||
public final Resources getResources() {
|
||||
Activity activity = getActivity();
|
||||
return activity != null ? activity.getResources() : null;
|
||||
@@ -243,6 +283,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Returns the Application Context derived from the host Activity
|
||||
*/
|
||||
@Nullable
|
||||
public final Context getApplicationContext() {
|
||||
Activity activity = getActivity();
|
||||
return activity != null ? activity.getApplicationContext() : null;
|
||||
@@ -251,6 +292,7 @@ public abstract class Controller {
|
||||
/**
|
||||
* Returns this Controller's parent Controller if it is a child Controller.
|
||||
*/
|
||||
@Nullable
|
||||
public final Controller getParentController() {
|
||||
return parentController;
|
||||
}
|
||||
@@ -259,6 +301,7 @@ 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;
|
||||
}
|
||||
@@ -269,7 +312,8 @@ public abstract class Controller {
|
||||
* @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 +330,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 +346,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.");
|
||||
}
|
||||
@@ -314,6 +359,7 @@ public abstract class Controller {
|
||||
*
|
||||
* @return This Controller's target
|
||||
*/
|
||||
@Nullable
|
||||
public final Controller getTargetController() {
|
||||
if (targetInstanceId != null) {
|
||||
return router.getRootRouter().getControllerWithInstanceId(targetInstanceId);
|
||||
@@ -327,7 +373,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 +413,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 +467,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 +476,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 +485,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 +511,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 +552,8 @@ 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();
|
||||
for (int i = childBackstack.size() - 1; i >= 0; i--) {
|
||||
Controller childController = childBackstack.get(i);
|
||||
if (childController.isAttached() && childController.getRouter().handleBack()) {
|
||||
return true;
|
||||
}
|
||||
@@ -522,7 +567,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 +578,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 +594,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 +605,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 +614,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 +622,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 +631,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 +675,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 +683,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,10 +691,14 @@ 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;
|
||||
}
|
||||
|
||||
final void setNeedsAttach() {
|
||||
needsAttach = true;
|
||||
}
|
||||
|
||||
final void prepareForHostDetach() {
|
||||
needsAttach = needsAttach || attached;
|
||||
|
||||
@@ -691,25 +743,26 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
final void activityStarted(Activity activity) {
|
||||
final void activityStarted(@NonNull Activity activity) {
|
||||
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) {
|
||||
onActivityStopped(activity);
|
||||
}
|
||||
|
||||
@@ -722,9 +775,15 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -737,20 +796,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();
|
||||
if (!attachedToUnownedParent) {
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.prepareForHostDetach();
|
||||
}
|
||||
}
|
||||
|
||||
final boolean removeViewRef = 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);
|
||||
}
|
||||
|
||||
@@ -761,7 +824,8 @@ public abstract class Controller {
|
||||
router.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDetach(this, view);
|
||||
}
|
||||
}
|
||||
@@ -777,13 +841,14 @@ 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);
|
||||
viewIsAttached = false;
|
||||
|
||||
if (isBeingDestroyed) {
|
||||
@@ -791,7 +856,8 @@ public abstract class Controller {
|
||||
}
|
||||
view = null;
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDestroyView(this);
|
||||
}
|
||||
|
||||
@@ -812,21 +878,26 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
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) {
|
||||
public void onAttached(View v) {
|
||||
if (v == view) {
|
||||
viewIsAttached = true;
|
||||
viewWasDetached = false;
|
||||
@@ -835,7 +906,7 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
public void onDetached(View v) {
|
||||
viewIsAttached = false;
|
||||
viewWasDetached = true;
|
||||
|
||||
@@ -843,17 +914,33 @@ public abstract class Controller {
|
||||
detach(v, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
view.addOnAttachStateChangeListener(onAttachStateChangeListener);
|
||||
});
|
||||
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);
|
||||
monitorChildRouter(childRouter);
|
||||
childRouter.rebindIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void performDestroy() {
|
||||
if (!destroyed) {
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preDestroy(this);
|
||||
}
|
||||
|
||||
@@ -863,7 +950,8 @@ public abstract class Controller {
|
||||
|
||||
parentController = null;
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDestroy(this);
|
||||
}
|
||||
}
|
||||
@@ -881,20 +969,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);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveViewState(@NonNull View view) {
|
||||
hasSavedViewState = true;
|
||||
|
||||
viewState = new Bundle();
|
||||
viewState = new Bundle(getClass().getClassLoader());
|
||||
|
||||
SparseArray<Parcelable> hierarchyState = new SparseArray<>();
|
||||
view.saveHierarchyState(hierarchyState);
|
||||
@@ -904,7 +992,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);
|
||||
}
|
||||
}
|
||||
@@ -914,19 +1003,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);
|
||||
}
|
||||
}
|
||||
@@ -962,10 +1042,17 @@ public abstract class Controller {
|
||||
}
|
||||
outState.putParcelableArrayList(KEY_CHILD_ROUTERS, childBundles);
|
||||
|
||||
ArrayList<String> childBackstack = new ArrayList<>();
|
||||
for (Controller controller : this.childBackstack) {
|
||||
childBackstack.add(controller.instanceId);
|
||||
}
|
||||
outState.putStringArrayList(KEY_CHILD_BACKSTACK, childBackstack);
|
||||
|
||||
Bundle savedState = new Bundle();
|
||||
onSaveInstanceState(savedState);
|
||||
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.onSaveInstanceState(this, savedState);
|
||||
}
|
||||
|
||||
@@ -976,6 +1063,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,6 +1083,14 @@ public abstract class Controller {
|
||||
childRouters.add(childRouter);
|
||||
}
|
||||
|
||||
List<String> childBackstackIds = savedInstanceState.getStringArrayList(KEY_CHILD_BACKSTACK);
|
||||
for (String controllerId : childBackstackIds) {
|
||||
Controller childController = findController(controllerId);
|
||||
if (childController != null) {
|
||||
childBackstack.add(childController);
|
||||
}
|
||||
}
|
||||
|
||||
this.savedInstanceState = savedInstanceState.getBundle(KEY_SAVED_STATE);
|
||||
performOnRestoreInstanceState();
|
||||
}
|
||||
@@ -1000,7 +1099,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);
|
||||
}
|
||||
|
||||
@@ -1008,7 +1108,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);
|
||||
@@ -1017,12 +1117,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);
|
||||
@@ -1031,15 +1132,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,27 +1160,27 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
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 monitorChildRouter(@NonNull ControllerHostedRouter childRouter) {
|
||||
childRouter.setOnControllerPushedListener(onControllerPushedListener);
|
||||
}
|
||||
|
||||
private void onChildControllerPushed(Controller controller) {
|
||||
private void onChildControllerPushed(@NonNull Controller controller) {
|
||||
if (!childBackstack.contains(controller)) {
|
||||
childBackstack.add(controller);
|
||||
controller.addLifecycleListener(new LifecycleListener() {
|
||||
@@ -1089,7 +1192,7 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
final void setParentController(Controller controller) {
|
||||
final void setParentController(@Nullable Controller controller) {
|
||||
parentController = controller;
|
||||
}
|
||||
|
||||
@@ -1100,7 +1203,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;
|
||||
@@ -1109,7 +1213,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,8 +2,10 @@ 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;
|
||||
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
|
||||
import com.bluelinelabs.conductor.internal.ClassUtils;
|
||||
@@ -25,6 +27,9 @@ 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.
|
||||
*
|
||||
@@ -34,7 +39,7 @@ public abstract class ControllerChangeHandler {
|
||||
* @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,7 +66,7 @@ public abstract class ControllerChangeHandler {
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
@@ -69,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());
|
||||
@@ -88,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);
|
||||
@@ -100,14 +127,17 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static void completePushImmediately(String controllerInstanceId) {
|
||||
static boolean completePushImmediately(@NonNull String controllerInstanceId) {
|
||||
ControllerChangeHandler changeHandler = inProgressPushHandlers.get(controllerInstanceId);
|
||||
if (changeHandler != null) {
|
||||
changeHandler.completeImmediately();
|
||||
inProgressPushHandlers.remove(controllerInstanceId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void abortPush(Controller toAbort, Controller newController, ControllerChangeHandler newChangeHandler) {
|
||||
public 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);
|
||||
@@ -115,22 +145,38 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static void executeChange(final Controller to, final Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler inHandler) {
|
||||
public static void executeChange(@Nullable final Controller to, @Nullable final Controller from, boolean isPush, @NonNull ViewGroup container, @NonNull ControllerChangeHandler inHandler) {
|
||||
executeChange(to, from, isPush, container, inHandler, new ArrayList<ControllerChangeListener>());
|
||||
}
|
||||
|
||||
public static void executeChange(final Controller to, final Controller from, final boolean isPush, final ViewGroup container, final ControllerChangeHandler inHandler, @NonNull final List<ControllerChangeListener> listeners) {
|
||||
public 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() + ")");
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -165,7 +211,14 @@ 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) {
|
||||
ViewParent fromParent = fromView.getParent();
|
||||
if (fromParent != null && fromParent instanceof ViewGroup) {
|
||||
((ViewGroup)fromParent).removeView(fromView);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -176,6 +229,10 @@ public abstract class ControllerChangeHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setForceRemoveViewOnPush(boolean force) {
|
||||
forceRemoveViewOnPush = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener interface useful for allowing external classes to be notified of change events.
|
||||
*/
|
||||
@@ -189,7 +246,7 @@ public abstract class ControllerChangeHandler {
|
||||
* @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
|
||||
@@ -200,7 +257,7 @@ public abstract class ControllerChangeHandler {
|
||||
* @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,6 +5,7 @@ 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;
|
||||
@@ -24,7 +25,7 @@ class ControllerHostedRouter extends Router {
|
||||
|
||||
ControllerHostedRouter() { }
|
||||
|
||||
ControllerHostedRouter(int hostId, String tag) {
|
||||
ControllerHostedRouter(int hostId, @Nullable String tag) {
|
||||
this.hostId = hostId;
|
||||
this.tag = tag;
|
||||
}
|
||||
@@ -47,7 +48,8 @@ class ControllerHostedRouter extends Router {
|
||||
removeChangeListener((ControllerChangeListener)container);
|
||||
}
|
||||
|
||||
for (Controller controller : destroyingControllers) {
|
||||
final List<Controller> controllersToDestroy = new ArrayList<>(destroyingControllers);
|
||||
for (Controller controller : controllersToDestroy) {
|
||||
if (controller.getView() != null) {
|
||||
controller.detach(controller.getView(), true);
|
||||
}
|
||||
@@ -70,25 +72,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);
|
||||
}
|
||||
@@ -102,42 +104,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);
|
||||
}
|
||||
@@ -149,7 +151,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);
|
||||
@@ -157,7 +159,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);
|
||||
@@ -165,7 +167,7 @@ class ControllerHostedRouter extends Router {
|
||||
}
|
||||
|
||||
@Override
|
||||
void setControllerRouter(Controller controller) {
|
||||
void setControllerRouter(@NonNull Controller controller) {
|
||||
super.setControllerRouter(controller);
|
||||
controller.setParentController(hostController);
|
||||
}
|
||||
@@ -174,11 +176,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());
|
||||
@@ -186,7 +189,7 @@ class ControllerHostedRouter extends Router {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @NonNull
|
||||
Router getRootRouter() {
|
||||
if (hostController != null && hostController.getRouter() != null) {
|
||||
return hostController.getRouter().getRootRouter();
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A simple controller subclass that changes the onCreateView signature to include a saved view state parameter.
|
||||
* This is necessary for some third party libraries like Google Maps, which require passing in a saved state
|
||||
* bundle at the time of creation.
|
||||
*/
|
||||
abstract public class RestoreViewOnCreateController extends Controller {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the controller is ready to display its view. A valid view must be returned. The standard body
|
||||
* for this method will be {@code return inflater.inflate(R.layout.my_layout, container, false);}, plus
|
||||
* any binding and state restoration code.
|
||||
*
|
||||
* @param inflater The LayoutInflater that should be used to inflate views
|
||||
* @param container The parent view that this Controller's view will eventually be attached to.
|
||||
* 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.
|
||||
*/
|
||||
@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;
|
||||
@@ -31,6 +33,7 @@ public abstract class Router {
|
||||
private static final String KEY_POPS_LAST_VIEW = "Router.popsLastView";
|
||||
|
||||
protected final Backstack backstack = new Backstack();
|
||||
private OnControllerPushedListener onControllerPushedListener;
|
||||
private final List<ControllerChangeListener> changeListeners = new ArrayList<>();
|
||||
final List<Controller> destroyingControllers = new ArrayList<>();
|
||||
|
||||
@@ -41,6 +44,7 @@ public abstract class Router {
|
||||
/**
|
||||
* Returns this Router's host Activity
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Activity getActivity();
|
||||
|
||||
/**
|
||||
@@ -51,7 +55,7 @@ public abstract class Router {
|
||||
* @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
|
||||
@@ -62,7 +66,7 @@ public abstract class Router {
|
||||
* @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 +79,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 +98,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 +113,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 +146,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,21 +159,37 @@ 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()) {
|
||||
trackDestroyingController(backstack.pop());
|
||||
}
|
||||
|
||||
final ControllerChangeHandler handler = transaction.pushChangeHandler();
|
||||
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.controller, true, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pushToBackstack(transaction);
|
||||
performControllerChange(transaction, topTransaction, true);
|
||||
|
||||
if (handler != null) {
|
||||
handler.setForceRemoveViewOnPush(true);
|
||||
}
|
||||
performControllerChange(transaction.pushChangeHandler(handler), topTransaction, true);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
void destroy(boolean popViews) {
|
||||
popsLastView = true;
|
||||
List<RouterTransaction> poppedControllers = backstack.popAll();
|
||||
|
||||
if (poppedControllers.size() > 0) {
|
||||
if (popViews && poppedControllers.size() > 0) {
|
||||
trackDestroyingControllers(poppedControllers);
|
||||
|
||||
performControllerChange(null, poppedControllers.get(0).controller, false, poppedControllers.get(0).popChangeHandler());
|
||||
@@ -176,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;
|
||||
@@ -186,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);
|
||||
}
|
||||
@@ -196,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 {
|
||||
@@ -211,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);
|
||||
}
|
||||
@@ -222,7 +256,8 @@ public abstract class Router {
|
||||
* @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);
|
||||
@@ -238,30 +273,11 @@ 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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,7 +286,8 @@ public abstract class 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) {
|
||||
@@ -286,7 +303,8 @@ public abstract class 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;
|
||||
@@ -305,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();
|
||||
@@ -319,11 +338,18 @@ public abstract class Router {
|
||||
* using the passed {@link ControllerChangeHandler}
|
||||
*
|
||||
* @param newBackstack The new backstack
|
||||
* @param changeHandler An optional change handler to be used to handle the transition
|
||||
* @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());
|
||||
|
||||
backstack.setBackstack(newBackstack);
|
||||
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.onAttachedToRouter();
|
||||
}
|
||||
|
||||
removeAllExceptVisibleAndUnowned();
|
||||
|
||||
if (newBackstack.size() > 0) {
|
||||
@@ -342,29 +368,28 @@ public abstract class Router {
|
||||
}
|
||||
|
||||
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);
|
||||
performControllerChange(newVisibleTransactions.get(0).controller, rootController, true, changeHandler);
|
||||
|
||||
for (int i = oldVisibleTransactions.size() - 1; i > 0; i--) {
|
||||
RouterTransaction transaction = oldVisibleTransactions.get(i);
|
||||
performControllerChange(null, transaction.controller, true, handler);
|
||||
ControllerChangeHandler localHandler = changeHandler != null ? changeHandler.copy() : new SimpleSwapChangeHandler();
|
||||
localHandler.setForceRemoveViewOnPush(true);
|
||||
performControllerChange(null, transaction.controller, true, localHandler);
|
||||
}
|
||||
|
||||
for (int i = 1; i < newVisibleTransactions.size(); i++) {
|
||||
RouterTransaction transaction = newVisibleTransactions.get(i);
|
||||
handler = transaction.pushChangeHandler() != null ? transaction.pushChangeHandler(): new SimpleSwapChangeHandler();
|
||||
performControllerChange(transaction.controller, newVisibleTransactions.get(i - 1).controller, true, handler);
|
||||
performControllerChange(transaction.controller, newVisibleTransactions.get(i - 1).controller, true, transaction.pushChangeHandler());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.onAttachedToRouter();
|
||||
if (onControllerPushedListener != null) {
|
||||
for (RouterTransaction transaction : newBackstack) {
|
||||
onControllerPushedListener.onControllerPushed(transaction.controller);
|
||||
}
|
||||
}
|
||||
|
||||
backstack.setBackstack(newBackstack);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -379,7 +404,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);
|
||||
}
|
||||
@@ -390,13 +415,14 @@ 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()) {
|
||||
@@ -408,14 +434,14 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -425,7 +451,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);
|
||||
|
||||
@@ -435,7 +461,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);
|
||||
|
||||
@@ -445,7 +471,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);
|
||||
|
||||
@@ -455,7 +481,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
public void onActivityDestroyed(@NonNull Activity activity) {
|
||||
prepareForContainerRemoval();
|
||||
changeListeners.clear();
|
||||
|
||||
@@ -481,12 +507,14 @@ public abstract class Router {
|
||||
|
||||
public void prepareForHostDetach() {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
ControllerChangeHandler.completePushImmediately(transaction.controller.getInstanceId());
|
||||
if (ControllerChangeHandler.completePushImmediately(transaction.controller.getInstanceId())) {
|
||||
transaction.controller.setNeedsAttach();
|
||||
}
|
||||
transaction.controller.prepareForHostDetach();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveInstanceState(Bundle outState) {
|
||||
public void saveInstanceState(@NonNull Bundle outState) {
|
||||
prepareForHostDetach();
|
||||
|
||||
Bundle backstackState = new Bundle();
|
||||
@@ -496,7 +524,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);
|
||||
@@ -507,7 +535,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);
|
||||
|
||||
@@ -517,7 +545,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);
|
||||
|
||||
@@ -527,7 +555,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;
|
||||
@@ -542,7 +570,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);
|
||||
@@ -556,12 +584,17 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
final void setOnControllerPushedListener(OnControllerPushedListener listener) {
|
||||
onControllerPushedListener = listener;
|
||||
}
|
||||
|
||||
void prepareForContainerRemoval() {
|
||||
if (container != null) {
|
||||
container.setOnHierarchyChangeListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
final List<Controller> getControllers() {
|
||||
List<Controller> controllers = new ArrayList<>();
|
||||
|
||||
@@ -573,6 +606,7 @@ public abstract class Router {
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public final Boolean handleRequestedPermission(@NonNull String permission) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (transaction.controller.didRequestPermission(permission)) {
|
||||
@@ -582,7 +616,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();
|
||||
}
|
||||
@@ -594,7 +628,7 @@ public abstract class Router {
|
||||
} else if (from != null) {
|
||||
changeHandler = from.popChangeHandler();
|
||||
} else {
|
||||
changeHandler = new SimpleSwapChangeHandler();
|
||||
changeHandler = null;
|
||||
}
|
||||
|
||||
Controller toController = to != null ? to.controller : null;
|
||||
@@ -603,7 +637,7 @@ public abstract class Router {
|
||||
performControllerChange(toController, fromController, isPush, changeHandler);
|
||||
}
|
||||
|
||||
private void performControllerChange(final Controller to, final Controller from, boolean isPush, @NonNull ControllerChangeHandler changeHandler) {
|
||||
private void performControllerChange(@Nullable final Controller to, @Nullable final Controller from, boolean isPush, @Nullable ControllerChangeHandler changeHandler) {
|
||||
if (to != null) {
|
||||
setControllerRouter(to);
|
||||
} else if (backstack.size() == 0 && !popsLastView) {
|
||||
@@ -615,11 +649,15 @@ public abstract class Router {
|
||||
ControllerChangeHandler.executeChange(to, from, isPush, container, changeHandler, changeListeners);
|
||||
}
|
||||
|
||||
void pushToBackstack(@NonNull RouterTransaction entry) {
|
||||
private void pushToBackstack(@NonNull RouterTransaction entry) {
|
||||
backstack.push(entry);
|
||||
|
||||
if (onControllerPushedListener != null) {
|
||||
onControllerPushedListener.onControllerPushed(entry.controller);
|
||||
}
|
||||
}
|
||||
|
||||
private void trackDestroyingController(RouterTransaction transaction) {
|
||||
private void trackDestroyingController(@NonNull RouterTransaction transaction) {
|
||||
if (!transaction.controller.isDestroyed()) {
|
||||
destroyingControllers.add(transaction.controller);
|
||||
|
||||
@@ -632,7 +670,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
private void trackDestroyingControllers(List<RouterTransaction> transactions) {
|
||||
private void trackDestroyingControllers(@NonNull List<RouterTransaction> transactions) {
|
||||
for (RouterTransaction transaction : transactions) {
|
||||
trackDestroyingController(transaction);
|
||||
}
|
||||
@@ -662,7 +700,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
private void addRouterViewsToList(Router router, List<View> list) {
|
||||
private void addRouterViewsToList(@NonNull Router router, @NonNull List<View> list) {
|
||||
for (Controller controller : router.getControllers()) {
|
||||
if (controller.getView() != null) {
|
||||
list.add(controller.getView());
|
||||
@@ -674,7 +712,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();
|
||||
@@ -689,18 +727,22 @@ public abstract class Router {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
void setControllerRouter(Controller controller) {
|
||||
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();
|
||||
|
||||
interface OnControllerPushedListener {
|
||||
void onControllerPushed(Controller controller);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Metadata used for adding {@link Controller}s to a {@link Router}.
|
||||
@@ -21,6 +22,7 @@ public class RouterTransaction {
|
||||
private ControllerChangeHandler popControllerChangeHandler;
|
||||
private boolean attachedToRouter;
|
||||
|
||||
@NonNull
|
||||
public static RouterTransaction with(@NonNull Controller controller) {
|
||||
return new RouterTransaction(controller);
|
||||
}
|
||||
@@ -41,15 +43,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 +63,7 @@ public class RouterTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ControllerChangeHandler pushChangeHandler() {
|
||||
ControllerChangeHandler handler = controller.getOverriddenPushHandler();
|
||||
if (handler == null) {
|
||||
@@ -66,7 +72,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 +82,7 @@ public class RouterTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ControllerChangeHandler popChangeHandler() {
|
||||
ControllerChangeHandler handler = controller.getOverriddenPopHandler();
|
||||
if (handler == null) {
|
||||
@@ -83,7 +91,8 @@ public class RouterTransaction {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public RouterTransaction popChangeHandler(ControllerChangeHandler handler) {
|
||||
@NonNull
|
||||
public RouterTransaction popChangeHandler(@Nullable ControllerChangeHandler handler) {
|
||||
if (!attachedToRouter) {
|
||||
popControllerChangeHandler = handler;
|
||||
return this;
|
||||
@@ -95,6 +104,7 @@ public class RouterTransaction {
|
||||
/**
|
||||
* Used to serialize this transaction into a Bundle
|
||||
*/
|
||||
@NonNull
|
||||
public Bundle saveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
|
||||
|
||||
+35
-20
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +99,8 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
* @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,23 @@ 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 = 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,25 +173,22 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
container.removeView(from);
|
||||
}
|
||||
|
||||
changeListener.onChangeCompleted();
|
||||
animator.removeListener(this);
|
||||
animator = null;
|
||||
complete(changeListener, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (from != null && (!isPush || removesFromViewOnPush) && !canceled) {
|
||||
container.removeView(from);
|
||||
if (!canceled && animator != null) {
|
||||
if (from != null && (!isPush || removesFromViewOnPush)) {
|
||||
container.removeView(from);
|
||||
}
|
||||
|
||||
complete(changeListener, this);
|
||||
|
||||
if (isPush && from != null) {
|
||||
resetFromView(from);
|
||||
}
|
||||
}
|
||||
|
||||
changeListener.onChangeCompleted();
|
||||
animator.removeListener(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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-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;
|
||||
|
||||
/**
|
||||
* An {@link AnimatorChangeHandler} that will cross fade two views
|
||||
*/
|
||||
@@ -26,8 +29,8 @@ 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));
|
||||
@@ -44,4 +47,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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-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;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
@@ -53,4 +56,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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+51
-4
@@ -2,7 +2,9 @@ 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;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
@@ -11,7 +13,7 @@ import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
/**
|
||||
* A {@link ControllerChangeHandler} that will instantly swap Views with no animations or transitions.
|
||||
*/
|
||||
public class SimpleSwapChangeHandler extends ControllerChangeHandler {
|
||||
public class SimpleSwapChangeHandler extends ControllerChangeHandler implements OnAttachStateChangeListener {
|
||||
|
||||
private static final String KEY_REMOVES_FROM_ON_PUSH = "SimpleSwapChangeHandler.removesFromViewOnPush";
|
||||
|
||||
@@ -19,6 +21,9 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
private boolean canceled;
|
||||
|
||||
private ViewGroup container;
|
||||
private ControllerChangeCompletedListener changeListener;
|
||||
|
||||
public SimpleSwapChangeHandler() {
|
||||
this(true);
|
||||
}
|
||||
@@ -40,14 +45,25 @@ public class SimpleSwapChangeHandler 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull ViewGroup container, View from, View to, boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
public void completeImmediately() {
|
||||
if (changeListener != null) {
|
||||
changeListener.onChangeCompleted();
|
||||
changeListener = null;
|
||||
|
||||
container.removeOnAttachStateChangeListener(this);
|
||||
container = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
@@ -58,11 +74,42 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
changeListener.onChangeCompleted();
|
||||
if (container.getWindowToken() != null) {
|
||||
changeListener.onChangeCompleted();
|
||||
} else {
|
||||
this.changeListener = changeListener;
|
||||
this.container = container;
|
||||
container.addOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removesFromViewOnPush() {
|
||||
return removesFromViewOnPush;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(@NonNull View v) {
|
||||
v.removeOnAttachStateChangeListener(this);
|
||||
|
||||
if (changeListener != null) {
|
||||
changeListener.onChangeCompleted();
|
||||
changeListener = null;
|
||||
container = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull View v) { }
|
||||
|
||||
@Override @NonNull
|
||||
public ControllerChangeHandler copy() {
|
||||
return new SimpleSwapChangeHandler(removesFromViewOnPush());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReusable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -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;
|
||||
@@ -29,17 +30,17 @@ public abstract class TransitionChangeHandler extends ControllerChangeHandler {
|
||||
* @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,109 @@
|
||||
package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class ViewAttachHandler {
|
||||
|
||||
public interface ViewAttachListener {
|
||||
void onAttached(View view);
|
||||
void onDetached(View view);
|
||||
}
|
||||
|
||||
private interface ChildAttachListener {
|
||||
void onAttached();
|
||||
}
|
||||
|
||||
private ViewAttachListener attachListener;
|
||||
private OnAttachStateChangeListener rootOnAttachStateChangeListener = new OnAttachStateChangeListener() {
|
||||
boolean rootAttached = false;
|
||||
boolean childrenAttached = false;
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(final View v) {
|
||||
if (rootAttached) {
|
||||
return;
|
||||
}
|
||||
|
||||
rootAttached = true;
|
||||
listenForDeepestChildAttach(v, new ChildAttachListener() {
|
||||
@Override
|
||||
public void onAttached() {
|
||||
childrenAttached = true;
|
||||
attachListener.onAttached(v);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
rootAttached = false;
|
||||
if (childrenAttached) {
|
||||
childrenAttached = false;
|
||||
attachListener.onDetached(v);
|
||||
}
|
||||
}
|
||||
};
|
||||
private OnAttachStateChangeListener childOnAttachStateChangeListener;
|
||||
|
||||
public ViewAttachHandler(ViewAttachListener attachListener) {
|
||||
this.attachListener = attachListener;
|
||||
}
|
||||
|
||||
public void listenForAttach(final View view) {
|
||||
view.addOnAttachStateChangeListener(rootOnAttachStateChangeListener);
|
||||
}
|
||||
|
||||
public void unregisterAttachListener(View view) {
|
||||
view.removeOnAttachStateChangeListener(rootOnAttachStateChangeListener);
|
||||
|
||||
if (view instanceof ViewGroup) {
|
||||
findDeepestChild((ViewGroup)view).removeOnAttachStateChangeListener(childOnAttachStateChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.util.ActivityController;
|
||||
|
||||
public class ActivityProxy {
|
||||
|
||||
private ActivityController<TestActivity> activityController;
|
||||
private AttachFakingFrameLayout view;
|
||||
|
||||
public ActivityProxy() {
|
||||
activityController = Robolectric.buildActivity(TestActivity.class);
|
||||
|
||||
@IdRes int containerId = 4;
|
||||
view = new AttachFakingFrameLayout(activityController.get());
|
||||
view.setId(containerId);
|
||||
}
|
||||
|
||||
public ActivityProxy create(Bundle savedInstanceState) {
|
||||
activityController.create(savedInstanceState);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy start() {
|
||||
activityController.start();
|
||||
view.setAttached(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy resume() {
|
||||
activityController.resume();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy pause() {
|
||||
activityController.pause();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy saveInstanceState(Bundle outState) {
|
||||
activityController.saveInstanceState(outState);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy stop() {
|
||||
activityController.stop();
|
||||
view.setAttached(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy destroy() {
|
||||
activityController.destroy();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivityProxy rotate() {
|
||||
getActivity().isChangingConfigurations = true;
|
||||
getActivity().recreate();
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestActivity getActivity() {
|
||||
return activityController.get();
|
||||
}
|
||||
|
||||
public AttachFakingFrameLayout getView() {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
|
||||
public class AttachFakingFrameLayout extends FrameLayout {
|
||||
|
||||
final IBinder fakeWindowToken = new IBinder() {
|
||||
@Override
|
||||
public String getInterfaceDescriptor() throws RemoteException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pingBinder() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBinderAlive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IInterface queryLocalInterface(String descriptor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, String[] args) throws RemoteException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private boolean reportAttached;
|
||||
|
||||
public AttachFakingFrameLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public AttachFakingFrameLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public AttachFakingFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IBinder getWindowToken() {
|
||||
return reportAttached ? fakeWindowToken : null;
|
||||
}
|
||||
|
||||
public void setAttached(boolean attached) {
|
||||
setAttached(attached, true);
|
||||
}
|
||||
|
||||
public void setAttached(boolean attached, boolean reportToViewUtils) {
|
||||
if (reportAttached != attached) {
|
||||
reportAttached = attached;
|
||||
if (reportToViewUtils) {
|
||||
ViewUtils.reportAttached(this, attached);
|
||||
}
|
||||
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
ViewUtils.reportAttached(getChildAt(i), attached);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAdded(View child) {
|
||||
if (reportAttached) {
|
||||
ViewUtils.reportAttached(child, true);
|
||||
}
|
||||
super.onViewAdded(child);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRemoved(View child) {
|
||||
ViewUtils.reportAttached(child, false);
|
||||
super.onViewRemoved(child);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -119,9 +119,9 @@ public class CallState implements Parcelable {
|
||||
"\n restoreInstanceStateCalls=" + restoreInstanceStateCalls +
|
||||
"\n saveViewStateCalls=" + saveViewStateCalls +
|
||||
"\n restoreViewStateCalls=" + restoreViewStateCalls +
|
||||
"\n onActivityResultCalls= " + onActivityResultCalls +
|
||||
"\n onRequestPermissionsResultCalls= " + onRequestPermissionsResultCalls +
|
||||
"\n createOptionsMenuCalls= " + createOptionsMenuCalls +
|
||||
"\n onActivityResultCalls=" + onActivityResultCalls +
|
||||
"\n onRequestPermissionsResultCalls=" + onRequestPermissionsResultCalls +
|
||||
"\n createOptionsMenuCalls=" + createOptionsMenuCalls +
|
||||
"}\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
import com.bluelinelabs.conductor.MockChangeHandler.ChangeHandlerListener;
|
||||
@@ -14,28 +12,26 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ActivityController;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ControllerLifecycleTests {
|
||||
|
||||
private ActivityController<TestActivity> activityController;
|
||||
private Router router;
|
||||
|
||||
private ActivityProxy activityProxy;
|
||||
private CallState currentCallState;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
activityController = Robolectric.buildActivity(TestActivity.class).create(savedInstanceState).start();
|
||||
public void createActivityController(Bundle savedInstanceState, boolean includeStartAndResume) {
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState);
|
||||
|
||||
@IdRes int containerId = 4;
|
||||
FrameLayout routerContainer = new FrameLayout(activityController.get());
|
||||
routerContainer.setId(containerId);
|
||||
if (includeStartAndResume) {
|
||||
activityProxy.start().resume();
|
||||
}
|
||||
|
||||
router = Conductor.attachRouter(activityController.get(), routerContainer, savedInstanceState);
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
@@ -43,7 +39,7 @@ public class ControllerLifecycleTests {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createActivityController(null);
|
||||
createActivityController(null, true);
|
||||
|
||||
currentCallState = new CallState();
|
||||
}
|
||||
@@ -82,18 +78,20 @@ public class ControllerLifecycleTests {
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.pause();
|
||||
activityProxy.getActivity().isDestroying = true;
|
||||
activityProxy.pause();
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.stop();
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.destroy();
|
||||
activityProxy.stop();
|
||||
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.destroy();
|
||||
|
||||
expectedCallState.destroyCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
@@ -112,33 +110,32 @@ public class ControllerLifecycleTests {
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.get().isChangingConfigurations = true;
|
||||
activityProxy.getActivity().isChangingConfigurations = true;
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
activityController.saveInstanceState(bundle);
|
||||
activityProxy.saveInstanceState(bundle);
|
||||
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
expectedCallState.saveInstanceStateCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.pause();
|
||||
activityProxy.pause();
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.stop();
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.destroy();
|
||||
activityProxy.stop();
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
createActivityController(bundle);
|
||||
activityProxy.destroy();
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
createActivityController(bundle, false);
|
||||
controller = (TestController)router.getControllerWithTag("root");
|
||||
|
||||
expectedCallState.restoreInstanceStateCalls++;
|
||||
expectedCallState.restoreViewStateCalls++;
|
||||
expectedCallState.changeStartCalls++;
|
||||
expectedCallState.changeEndCalls++;
|
||||
expectedCallState.createViewCalls++;
|
||||
|
||||
// Lifecycle listener isn't attached during restore, grab the current views from the controller for this stuff...
|
||||
@@ -147,10 +144,19 @@ public class ControllerLifecycleTests {
|
||||
currentCallState.changeStartCalls = controller.currentCallState.changeStartCalls;
|
||||
currentCallState.changeEndCalls = controller.currentCallState.changeEndCalls;
|
||||
currentCallState.createViewCalls = controller.currentCallState.createViewCalls;
|
||||
currentCallState.attachCalls = controller.currentCallState.attachCalls;
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.resume();
|
||||
activityProxy.start().resume();
|
||||
currentCallState.changeEndCalls = controller.currentCallState.changeEndCalls;
|
||||
currentCallState.attachCalls = controller.currentCallState.attachCalls;
|
||||
expectedCallState.changeEndCalls++;
|
||||
expectedCallState.attachCalls++;
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.resume();
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@@ -167,16 +173,16 @@ public class ControllerLifecycleTests {
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.pause();
|
||||
activityProxy.pause();
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
activityController.saveInstanceState(bundle);
|
||||
activityProxy.saveInstanceState(bundle);
|
||||
|
||||
expectedCallState.saveInstanceStateCalls++;
|
||||
expectedCallState.saveViewStateCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityController.resume();
|
||||
activityProxy.resume();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -377,8 +383,8 @@ public class ControllerLifecycleTests {
|
||||
});
|
||||
|
||||
router.pushController(RouterTransaction.with(testController)
|
||||
.pushChangeHandler(new MockChangeHandler())
|
||||
.popChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler())
|
||||
.popChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
router.popController(testController);
|
||||
|
||||
@@ -393,7 +399,7 @@ public class ControllerLifecycleTests {
|
||||
public void testChildLifecycle() {
|
||||
Controller parent = new TestController();
|
||||
router.pushController(RouterTransaction.with(parent)
|
||||
.pushChangeHandler(new MockChangeHandler()));
|
||||
.pushChangeHandler(MockChangeHandler.defaultHandler()));
|
||||
|
||||
TestController child = new TestController();
|
||||
attachLifecycleListener(child);
|
||||
@@ -402,7 +408,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))
|
||||
@@ -419,8 +425,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);
|
||||
@@ -429,7 +435,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))
|
||||
@@ -439,11 +445,15 @@ 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() {
|
||||
expectedCallState.changeStartCalls++;
|
||||
@@ -466,7 +476,7 @@ 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() {
|
||||
expectedCallState.changeStartCalls++;
|
||||
|
||||
@@ -3,10 +3,8 @@ package com.bluelinelabs.conductor;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller.RetainViewMode;
|
||||
|
||||
@@ -14,26 +12,19 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ActivityController;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ControllerTests {
|
||||
|
||||
private ActivityController<TestActivity> activityController;
|
||||
private ActivityProxy activityProxy;
|
||||
private Router router;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
activityController = Robolectric.buildActivity(TestActivity.class).create(savedInstanceState).start();
|
||||
|
||||
@IdRes int containerId = 4;
|
||||
FrameLayout routerContainer = new FrameLayout(activityController.get());
|
||||
routerContainer.setId(containerId);
|
||||
|
||||
router = Conductor.attachRouter(activityController.get(), routerContainer, savedInstanceState);
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
@@ -47,24 +38,25 @@ 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 FrameLayout(router.getActivity()));
|
||||
View view = controller.inflate(router.container);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
ViewUtils.setAttached(view, true);
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
ViewUtils.setAttached(view, false);
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertNull(controller.getView());
|
||||
|
||||
// Test View getting retained w/ RETAIN_DETACH
|
||||
controller.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
view = controller.inflate(new FrameLayout(router.getActivity()));
|
||||
view = controller.inflate(router.container);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
ViewUtils.setAttached(view, true);
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
ViewUtils.setAttached(view, false);
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertNotNull(controller.getView());
|
||||
|
||||
// Ensure re-setting RELEASE_DETACH releases
|
||||
@@ -78,7 +70,6 @@ public class ControllerTests {
|
||||
CallState expectedCallState = new CallState(true);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
ViewUtils.setAttached(controller.getView(), true);
|
||||
|
||||
// Ensure that calling onActivityResult w/o requesting a result doesn't do anything
|
||||
router.onActivityResult(1, Activity.RESULT_OK, null);
|
||||
@@ -103,10 +94,8 @@ public class ControllerTests {
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
ViewUtils.setAttached(parent.getView(), true);
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null)
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
ViewUtils.setAttached(child.getView(), true);
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
CallState parentExpectedCallState = new CallState(true);
|
||||
@@ -139,7 +128,6 @@ public class ControllerTests {
|
||||
CallState expectedCallState = new CallState(true);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
ViewUtils.setAttached(controller.getView(), true);
|
||||
|
||||
// Ensure that calling handleRequestedPermission w/o requesting a result doesn't do anything
|
||||
router.onRequestPermissionsResult("anotherId", 1, requestedPermissions, new int[] {1});
|
||||
@@ -163,10 +151,8 @@ public class ControllerTests {
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
ViewUtils.setAttached(parent.getView(), true);
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null)
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
ViewUtils.setAttached(child.getView(), true);
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
CallState parentExpectedCallState = new CallState(true);
|
||||
@@ -193,7 +179,6 @@ public class ControllerTests {
|
||||
CallState expectedCallState = new CallState(true);
|
||||
|
||||
router.pushController(RouterTransaction.with(controller));
|
||||
ViewUtils.setAttached(controller.getView(), true);
|
||||
|
||||
// Ensure that calling onCreateOptionsMenu w/o declaring that we have one doesn't do anything
|
||||
router.onCreateOptionsMenu(null, null);
|
||||
@@ -230,10 +215,8 @@ public class ControllerTests {
|
||||
TestController child = new TestController();
|
||||
|
||||
router.pushController(RouterTransaction.with(parent));
|
||||
ViewUtils.setAttached(parent.getView(), true);
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID), null)
|
||||
parent.getChildRouter((ViewGroup)parent.getView().findViewById(TestController.VIEW_ID))
|
||||
.setRoot(RouterTransaction.with(child));
|
||||
ViewUtils.setAttached(child.getView(), true);
|
||||
|
||||
CallState childExpectedCallState = new CallState(true);
|
||||
CallState parentExpectedCallState = new CallState(true);
|
||||
@@ -284,7 +267,8 @@ public class ControllerTests {
|
||||
Assert.assertNull(child1.getParentController());
|
||||
Assert.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());
|
||||
@@ -294,7 +278,7 @@ public class ControllerTests {
|
||||
Assert.assertEquals(parent, child1.getParentController());
|
||||
Assert.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());
|
||||
@@ -336,8 +320,8 @@ public class ControllerTests {
|
||||
Assert.assertNull(child1.getParentController());
|
||||
Assert.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));
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
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() { }
|
||||
@@ -14,13 +16,32 @@ public class MockChangeHandler extends ControllerChangeHandler {
|
||||
}
|
||||
|
||||
final ChangeHandlerListener listener;
|
||||
boolean removesFromViewOnPush;
|
||||
|
||||
public MockChangeHandler() {
|
||||
this(new ChangeHandlerListener() { });
|
||||
public static MockChangeHandler defaultHandler() {
|
||||
return new MockChangeHandler(true, null);
|
||||
}
|
||||
|
||||
public MockChangeHandler(@NonNull ChangeHandlerListener listener) {
|
||||
this.listener = listener;
|
||||
public static MockChangeHandler noRemoveViewOnPushHandler() {
|
||||
return new MockChangeHandler(false, null);
|
||||
}
|
||||
|
||||
public static MockChangeHandler listeningChangeHandler(@NonNull ChangeHandlerListener listener) {
|
||||
return new MockChangeHandler(true , listener);
|
||||
}
|
||||
|
||||
public MockChangeHandler() {
|
||||
listener = null;
|
||||
}
|
||||
|
||||
private MockChangeHandler(boolean removesFromViewOnPush, ChangeHandlerListener listener) {
|
||||
this.removesFromViewOnPush = removesFromViewOnPush;
|
||||
|
||||
if (listener == null) {
|
||||
this.listener = new ChangeHandlerListener() { };
|
||||
} else {
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -29,23 +50,17 @@ public class MockChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
if (isPush) {
|
||||
container.addView(to);
|
||||
ViewUtils.setAttached(to, true);
|
||||
|
||||
listener.didAttachOrDetach();
|
||||
|
||||
if (from != null) {
|
||||
if (removesFromViewOnPush && from != null) {
|
||||
container.removeView(from);
|
||||
ViewUtils.setAttached(from, false);
|
||||
}
|
||||
} else {
|
||||
container.removeView(from);
|
||||
ViewUtils.setAttached(from, false);
|
||||
|
||||
listener.didAttachOrDetach();
|
||||
|
||||
if (to != null) {
|
||||
container.addView(to);
|
||||
ViewUtils.setAttached(to, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,4 +69,31 @@ public class MockChangeHandler extends ControllerChangeHandler {
|
||||
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);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ControllerChangeHandler copy() {
|
||||
return new MockChangeHandler(removesFromViewOnPush, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReusable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,25 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ActivityController;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ReattachCaseTests {
|
||||
|
||||
private ActivityController<TestActivity> activityController;
|
||||
private ActivityProxy activityProxy;
|
||||
private Router router;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
activityController = Robolectric.buildActivity(TestActivity.class).create(savedInstanceState).start();
|
||||
|
||||
@IdRes int containerId = 4;
|
||||
FrameLayout routerContainer = new FrameLayout(activityController.get());
|
||||
routerContainer.setId(containerId);
|
||||
|
||||
router = Conductor.attachRouter(activityController.get(), routerContainer, savedInstanceState);
|
||||
activityProxy = new ActivityProxy().create(savedInstanceState).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
@@ -45,8 +36,8 @@ 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());
|
||||
@@ -57,13 +48,14 @@ public class ReattachCaseTests {
|
||||
Assert.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());
|
||||
|
||||
rotateDevice();
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
@@ -76,13 +68,13 @@ 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()));
|
||||
|
||||
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());
|
||||
@@ -95,14 +87,15 @@ public class ReattachCaseTests {
|
||||
Assert.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());
|
||||
|
||||
rotateDevice();
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertFalse(childController.isAttached());
|
||||
@@ -117,28 +110,29 @@ 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());
|
||||
|
||||
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());
|
||||
|
||||
rotateDevice();
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
@@ -165,22 +159,22 @@ 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());
|
||||
|
||||
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());
|
||||
@@ -194,14 +188,15 @@ public class ReattachCaseTests {
|
||||
|
||||
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());
|
||||
|
||||
rotateDevice();
|
||||
activityProxy.rotate();
|
||||
router.rebindIfNeeded();
|
||||
|
||||
Assert.assertFalse(controllerA.isAttached());
|
||||
Assert.assertTrue(controllerB.isAttached());
|
||||
@@ -211,8 +206,8 @@ public class ReattachCaseTests {
|
||||
|
||||
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());
|
||||
@@ -232,18 +227,8 @@ public class ReattachCaseTests {
|
||||
}
|
||||
|
||||
private void sleepWakeDevice() {
|
||||
activityController.saveInstanceState(new Bundle()).pause();
|
||||
activityController.resume();
|
||||
}
|
||||
|
||||
private void rotateDevice() {
|
||||
@IdRes int containerId = 4;
|
||||
FrameLayout routerContainer = new FrameLayout(activityController.get());
|
||||
routerContainer.setId(containerId);
|
||||
|
||||
activityController.get().isChangingConfigurations = true;
|
||||
activityController.get().recreate();
|
||||
router.rebindIfNeeded();
|
||||
activityProxy.saveInstanceState(new Bundle()).pause();
|
||||
activityProxy.resume();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class RouterTests {
|
||||
@@ -19,8 +18,8 @@ public class RouterTests {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Activity activity = Robolectric.buildActivity(TestActivity.class).create().get();
|
||||
router = Conductor.attachRouter(activity, new FrameLayout(activity), null);
|
||||
ActivityProxy activityProxy = new ActivityProxy().create(null).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -174,4 +173,149 @@ public class RouterTests {
|
||||
Assert.assertEquals(controller3, router.getControllerWithTag(controller3Tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBackstack() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(middleTransaction);
|
||||
backstack.add(topTransaction);
|
||||
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewSetBackstack() {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
|
||||
Assert.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);
|
||||
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewSetBackstackWithNoRemoveViewOnPush() {
|
||||
RouterTransaction oldRootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction oldTopTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
router.setRoot(oldRootTransaction);
|
||||
router.pushController(oldTopTransaction);
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
|
||||
Assert.assertTrue(oldRootTransaction.controller.isAttached());
|
||||
Assert.assertTrue(oldTopTransaction.controller.isAttached());
|
||||
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction middleTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(middleTransaction);
|
||||
backstack.add(topTransaction);
|
||||
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.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));
|
||||
|
||||
Assert.assertFalse(oldRootTransaction.controller.isAttached());
|
||||
Assert.assertFalse(oldTopTransaction.controller.isAttached());
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached());
|
||||
Assert.assertTrue(middleTransaction.controller.isAttached());
|
||||
Assert.assertTrue(topTransaction.controller.isAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceTopController() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController());
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(topTransaction);
|
||||
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
|
||||
RouterTransaction newTopTransaction = RouterTransaction.with(new TestController());
|
||||
router.replaceTopController(newTopTransaction);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
|
||||
fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(newTopTransaction, fetchedBackstack.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceTopControllerWithNoRemoveViewOnPush() {
|
||||
RouterTransaction rootTransaction = RouterTransaction.with(new TestController());
|
||||
RouterTransaction topTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
|
||||
List<RouterTransaction> backstack = new ArrayList<>();
|
||||
backstack.add(rootTransaction);
|
||||
backstack.add(topTransaction);
|
||||
|
||||
router.setBackstack(backstack, null);
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached());
|
||||
Assert.assertTrue(topTransaction.controller.isAttached());
|
||||
|
||||
List<RouterTransaction> fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(topTransaction, fetchedBackstack.get(1));
|
||||
|
||||
RouterTransaction newTopTransaction = RouterTransaction.with(new TestController()).pushChangeHandler(MockChangeHandler.noRemoveViewOnPushHandler());
|
||||
router.replaceTopController(newTopTransaction);
|
||||
newTopTransaction.pushChangeHandler().completeImmediately();
|
||||
|
||||
Assert.assertEquals(2, router.getBackstackSize());
|
||||
|
||||
fetchedBackstack = router.getBackstack();
|
||||
Assert.assertEquals(rootTransaction, fetchedBackstack.get(0));
|
||||
Assert.assertEquals(newTopTransaction, fetchedBackstack.get(1));
|
||||
|
||||
Assert.assertTrue(rootTransaction.controller.isAttached());
|
||||
Assert.assertFalse(topTransaction.controller.isAttached());
|
||||
Assert.assertTrue(newTopTransaction.controller.isAttached());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ActivityController;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class TargetControllerTests {
|
||||
|
||||
private ActivityController<TestActivity> activityController;
|
||||
private Router router;
|
||||
|
||||
public void createActivityController(Bundle savedInstanceState) {
|
||||
activityController = Robolectric.buildActivity(TestActivity.class).create(savedInstanceState).start();
|
||||
|
||||
@IdRes int containerId = 4;
|
||||
FrameLayout routerContainer = new FrameLayout(activityController.get());
|
||||
routerContainer.setId(containerId);
|
||||
|
||||
router = Conductor.attachRouter(activityController.get(), routerContainer, savedInstanceState);
|
||||
ActivityProxy activityProxy = new ActivityProxy().create(savedInstanceState).start().resume();
|
||||
router = Conductor.attachRouter(activityProxy.getActivity(), activityProxy.getView(), savedInstanceState);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new TestController()));
|
||||
}
|
||||
@@ -48,14 +38,14 @@ public class TargetControllerTests {
|
||||
Assert.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());
|
||||
@@ -70,15 +60,15 @@ public class TargetControllerTests {
|
||||
Assert.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());
|
||||
@@ -93,15 +83,15 @@ public class TargetControllerTests {
|
||||
Assert.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());
|
||||
|
||||
@@ -5,10 +5,15 @@ import android.app.Activity;
|
||||
public class TestActivity extends Activity {
|
||||
|
||||
public boolean isChangingConfigurations = false;
|
||||
public boolean isDestroying = false;
|
||||
|
||||
@Override
|
||||
public boolean isChangingConfigurations() {
|
||||
return isChangingConfigurations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return isDestroying || super.isDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class TestController extends Controller {
|
||||
@Override
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
currentCallState.createViewCalls++;
|
||||
FrameLayout view = new FrameLayout(inflater.getContext());
|
||||
FrameLayout view = new AttachFakingFrameLayout(inflater.getContext());
|
||||
view.setId(VIEW_ID);
|
||||
|
||||
FrameLayout childContainer1 = new FrameLayout(inflater.getContext());
|
||||
@@ -68,7 +68,7 @@ public class TestController extends Controller {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(View view) {
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
currentCallState.destroyViewCalls++;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
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 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;
|
||||
|
||||
@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);
|
||||
|
||||
Assert.assertEquals(0, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertEquals(2, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleViewGroupAttachDetach() {
|
||||
View view = new LinearLayout(activity);
|
||||
viewAttachHandler.listenForAttach(view);
|
||||
|
||||
Assert.assertEquals(0, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true);
|
||||
Assert.assertEquals(2, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedViewGroupAttachDetach() {
|
||||
ViewGroup view = new LinearLayout(activity);
|
||||
View child = new LinearLayout(activity);
|
||||
view.addView(child);
|
||||
viewAttachHandler.listenForAttach(view);
|
||||
|
||||
Assert.assertEquals(0, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true, false);
|
||||
Assert.assertEquals(0, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(child, true, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true, false);
|
||||
ViewUtils.reportAttached(child, true, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(0, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, false, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, false, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(view, true, false);
|
||||
Assert.assertEquals(1, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
|
||||
ViewUtils.reportAttached(child, true, false);
|
||||
Assert.assertEquals(2, viewAttachListener.attaches);
|
||||
Assert.assertEquals(1, viewAttachListener.detaches);
|
||||
}
|
||||
|
||||
private static class CountingViewAttachListener implements ViewAttachListener {
|
||||
int attaches;
|
||||
int detaches;
|
||||
|
||||
@Override
|
||||
public void onAttached(View view) {
|
||||
attaches++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetached(View view) {
|
||||
detaches++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.bluelinelabs.conductor;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@@ -9,9 +10,30 @@ import java.util.List;
|
||||
|
||||
public class ViewUtils {
|
||||
|
||||
public static void setAttached(View view, boolean attached) {
|
||||
Object listenerInfo = ReflectionHelpers.callInstanceMethod(view, "getListenerInfo");
|
||||
List<OnAttachStateChangeListener> listeners = ReflectionHelpers.getField(listenerInfo, "mOnAttachStateChangeListeners");
|
||||
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);
|
||||
}
|
||||
|
||||
List<OnAttachStateChangeListener> listeners = getAttachStateListeners(view);
|
||||
|
||||
// Add, then remove an OnAttachStateChangeListener to initialize the attachStateListeners variable inside a view
|
||||
if (listeners == null) {
|
||||
OnAttachStateChangeListener tmpListener = new OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) { }
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) { }
|
||||
};
|
||||
view.addOnAttachStateChangeListener(tmpListener);
|
||||
view.removeOnAttachStateChangeListener(tmpListener);
|
||||
listeners = getAttachStateListeners(view);
|
||||
}
|
||||
|
||||
for (OnAttachStateChangeListener listener : listeners) {
|
||||
if (attached) {
|
||||
@@ -20,6 +42,20 @@ public class ViewUtils {
|
||||
listener.onViewDetachedFromWindow(view);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
Object listenerInfo = ReflectionHelpers.callInstanceMethod(view, "getListenerInfo");
|
||||
return ReflectionHelpers.getField(listenerInfo, "mOnAttachStateChangeListeners");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ 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);
|
||||
|
||||
+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();
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ 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) {
|
||||
|
||||
+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()));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController;
|
||||
import com.bluelinelabs.conductor.support.ControllerPagerAdapter;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
||||
public class PagerController extends BaseController {
|
||||
@@ -27,7 +29,7 @@ public class PagerController extends BaseController {
|
||||
pagerAdapter = new ControllerPagerAdapter(this, false) {
|
||||
@Override
|
||||
public Controller getItem(int position) {
|
||||
return new ChildController(String.format("Child #%d (Swipe to see more)", position), PAGE_COLORS[position], true);
|
||||
return new ChildController(String.format(Locale.getDefault(), "Child #%d (Swipe to see more)", position), PAGE_COLORS[position], true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,7 +52,7 @@ public class PagerController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(View view) {
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
viewPager.setAdapter(null);
|
||||
super.onDestroyView(view);
|
||||
}
|
||||
|
||||
+21
-9
@@ -16,10 +16,13 @@ import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController;
|
||||
import com.bluelinelabs.conductor.demo.util.ColorUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ParentController extends BaseController {
|
||||
|
||||
private static final int NUMBER_OF_CHILDREN = 5;
|
||||
private boolean finishing;
|
||||
private boolean hasShownAll;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@@ -39,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);
|
||||
@@ -47,13 +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 && index < NUMBER_OF_CHILDREN - 1) {
|
||||
addChild(index + 1);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +75,10 @@ public class ParentController extends BaseController {
|
||||
}
|
||||
|
||||
private void removeChild(int index) {
|
||||
removeChildRouter(getChildRouters().get(index));
|
||||
List<Router> childRouters = getChildRouters();
|
||||
if (index < childRouters.size()) {
|
||||
removeChildRouter(childRouters.get(index));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
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
|
||||
|
||||
@@ -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
-19
@@ -1,29 +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.1.0'
|
||||
rxAndroid = 'io.reactivex:rxandroid:1.1.0'
|
||||
rxLifecycle = 'com.trello:rxlifecycle:0.6.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'
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=2.0.3-SNAPSHOT
|
||||
VERSION_NAME=2.0.7-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