├── navi ├── .gitignore ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── trello │ │ │ └── navi2 │ │ │ ├── Listener.java │ │ │ ├── internal │ │ │ ├── Constants.java │ │ │ ├── HandledEvents.java │ │ │ └── NaviEmitter.java │ │ │ ├── model │ │ │ ├── ViewCreated.java │ │ │ ├── ActivityResult.java │ │ │ ├── BundleBundle.java │ │ │ └── RequestPermissionsResult.java │ │ │ ├── rx │ │ │ ├── RxNavi.java │ │ │ └── NaviOnSubscribe.java │ │ │ ├── NaviComponent.java │ │ │ ├── component │ │ │ ├── NaviFragment.java │ │ │ ├── NaviDialogFragment.java │ │ │ ├── support │ │ │ │ ├── NaviDialogFragment.java │ │ │ │ ├── NaviFragment.java │ │ │ │ ├── NaviAppCompatDialogFragment.java │ │ │ │ └── NaviAppCompatActivity.java │ │ │ └── NaviActivity.java │ │ │ └── Event.java │ └── test │ │ └── java │ │ └── com │ │ └── trello │ │ └── navi2 │ │ ├── TestUtils.java │ │ ├── EventHandlingTest.java │ │ ├── rx │ │ ├── RxNaviAllEventTest.java │ │ ├── RxNaviFragmentTest.java │ │ └── RxNaviActivityTest.java │ │ ├── AllEventTest.java │ │ ├── AddRemoveTest.java │ │ ├── NullBundleTest.java │ │ ├── ConcurrencyTest.java │ │ ├── NaviFragmentTest.java │ │ └── NaviActivityTest.java ├── gradle.properties └── build.gradle ├── sample ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ └── strings.xml │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ └── layout │ │ │ └── main.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── trello │ │ └── navi2 │ │ └── sample │ │ └── MainActivity.java └── build.gradle ├── settings.gradle ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── artifacts.gradle └── gradle-mvn-push.gradle ├── gradle.properties ├── .gitignore ├── .travis.yml ├── gradlew.bat ├── README.md ├── CHANGELOG.md ├── gradlew └── LICENSE /navi/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':navi' 2 | include ':sample' 3 | -------------------------------------------------------------------------------- /navi/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /navi/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Navi 2 | POM_DESCRIPTION=Navi 3 | POM_ARTIFACT_ID=navi 4 | POM_PACKAGING=aar -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Navi 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trello-archive/navi/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trello-archive/navi/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trello-archive/navi/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trello-archive/navi/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trello-archive/navi/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trello-archive/navi/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.trello.navi2 2 | VERSION_NAME=2.1.0-SNAPSHOT 3 | 4 | POM_URL=https://github.com/trello/navi 5 | POM_SCM_URL=https://github.com/trello/navi 6 | POM_SCM_CONNECTION=scm:git:https://github.com/trello/navi.git 7 | POM_SCM_DEV_CONNECTION=scm:git:git@github.com:trello/navi.git 8 | 9 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 10 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 11 | POM_LICENCE_DIST=repo 12 | 13 | POM_DEVELOPER_ID=dlew 14 | POM_DEVELOPER_NAME=Dan Lew -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | 28 | # Ignored repo build directory 29 | repo/ 30 | 31 | # IntelliJ files 32 | *.iml 33 | *.idea 34 | 35 | # Mac OS 36 | .DS_STORE -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | - android-28 8 | - extra-android-m2repository 9 | 10 | jdk: oraclejdk8 11 | 12 | notifications: 13 | email: false 14 | 15 | sudo: false 16 | 17 | cache: 18 | directories: 19 | - $HOME/.gradle 20 | 21 | before_install: 22 | # Install SDK license so Android Gradle plugin can install deps. 23 | - mkdir "$ANDROID_HOME/licenses" || true 24 | - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" 25 | 26 | script: ./gradlew build test -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | 6 | defaultConfig { 7 | applicationId "com.trello.navi2.sample" 8 | minSdkVersion rootProject.ext.minSdkVersion 9 | targetSdkVersion rootProject.ext.targetSdkVersion 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | } 14 | 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | 20 | dependencies { 21 | implementation project(':navi') 22 | implementation rootProject.ext.supportAppCompat 23 | implementation rootProject.ext.rxJava 24 | implementation rootProject.ext.rxAndroid 25 | } 26 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/Listener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import androidx.annotation.NonNull; 18 | 19 | /** 20 | * Listener callback. 21 | * 22 | * @param the callback type; can be Void in cases where event has no metadata 23 | */ 24 | public interface Listener { 25 | void call(@NonNull T t); 26 | } 27 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/internal/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.internal; 16 | 17 | final class Constants { 18 | 19 | /** 20 | * Acts as a signal for events that have no data associated with them. 21 | * 22 | * We reuse a single Object to avoid any extra allocations. 23 | */ 24 | static final Object SIGNAL = new Object(); 25 | 26 | private Constants() { 27 | throw new AssertionError("No instances!"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /navi/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | 6 | defaultConfig { 7 | minSdkVersion rootProject.ext.minSdkVersion 8 | } 9 | 10 | lintOptions { 11 | textReport true 12 | textOutput 'stdout' 13 | } 14 | 15 | // TODO replace with https://issuetracker.google.com/issues/72050365 once released. 16 | libraryVariants.all { 17 | it.generateBuildConfig.enabled = false 18 | } 19 | } 20 | 21 | repositories { 22 | google() 23 | jcenter() 24 | } 25 | 26 | dependencies { 27 | implementation rootProject.ext.supportAnnotations 28 | 29 | annotationProcessor rootProject.ext.autoValue 30 | compileOnly rootProject.ext.autoValueAnnotations 31 | 32 | // Optional dependencies, depending on if your project uses them 33 | compileOnly rootProject.ext.rxJava 34 | compileOnly rootProject.ext.supportAppCompat 35 | 36 | testImplementation rootProject.ext.rxJava 37 | testImplementation rootProject.ext.junit 38 | testImplementation rootProject.ext.mockito 39 | } 40 | 41 | apply from: "$rootDir/gradle/artifacts.gradle" 42 | apply from: "$rootDir/gradle/gradle-mvn-push.gradle" 43 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/model/ViewCreated.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.model; 16 | 17 | import android.os.Bundle; 18 | import android.view.View; 19 | 20 | import com.google.auto.value.AutoValue; 21 | 22 | import androidx.annotation.NonNull; 23 | import androidx.annotation.Nullable; 24 | 25 | @AutoValue public abstract class ViewCreated { 26 | 27 | public static ViewCreated create(@NonNull View view, @Nullable Bundle bundle) { 28 | return new AutoValue_ViewCreated(view, bundle); 29 | } 30 | 31 | @NonNull public abstract View view(); 32 | 33 | @Nullable 34 | public abstract Bundle bundle(); 35 | } 36 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/model/ActivityResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.model; 16 | 17 | import android.content.Intent; 18 | 19 | import com.google.auto.value.AutoValue; 20 | 21 | import androidx.annotation.Nullable; 22 | 23 | @AutoValue public abstract class ActivityResult { 24 | 25 | public static ActivityResult create(int requestCode, int resultCode, @Nullable Intent data) { 26 | return new AutoValue_ActivityResult(requestCode, resultCode, data); 27 | } 28 | 29 | public abstract int requestCode(); 30 | 31 | public abstract int resultCode(); 32 | 33 | @Nullable public abstract Intent data(); 34 | } 35 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/model/BundleBundle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.model; 16 | 17 | import android.os.Bundle; 18 | import android.os.PersistableBundle; 19 | 20 | import com.google.auto.value.AutoValue; 21 | 22 | import androidx.annotation.Nullable; 23 | 24 | @AutoValue public abstract class BundleBundle { 25 | 26 | public static BundleBundle create(@Nullable Bundle bundle, 27 | @Nullable PersistableBundle persistableBundle) { 28 | return new AutoValue_BundleBundle(bundle, persistableBundle); 29 | } 30 | 31 | @Nullable public abstract Bundle bundle(); 32 | 33 | @Nullable public abstract PersistableBundle persistableBundle(); 34 | } 35 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/rx/RxNavi.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.rx; 16 | 17 | import com.trello.navi2.Event; 18 | import com.trello.navi2.NaviComponent; 19 | 20 | import androidx.annotation.CheckResult; 21 | import androidx.annotation.NonNull; 22 | import io.reactivex.Observable; 23 | 24 | public final class RxNavi { 25 | 26 | @CheckResult @NonNull 27 | public static Observable observe(@NonNull NaviComponent component, @NonNull Event event) { 28 | if (component == null) throw new IllegalArgumentException("component == null"); 29 | if (event == null) throw new IllegalArgumentException("event == null"); 30 | return Observable.create(new NaviOnSubscribe<>(component, event)); 31 | } 32 | 33 | private RxNavi() { 34 | throw new AssertionError("No instances!"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/TestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import android.os.Build; 18 | import java.lang.reflect.Field; 19 | import java.lang.reflect.Modifier; 20 | 21 | public class TestUtils { 22 | 23 | // This horrible hack is used while mockableAndroidJar isn't working properly 24 | public static void setSdkInt(int value) { 25 | try { 26 | Field field = Build.VERSION.class.getField("SDK_INT"); 27 | field.setAccessible(true); 28 | 29 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 30 | modifiersField.setAccessible(true); 31 | modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 32 | 33 | field.setInt(null, value); 34 | } catch (Exception e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/model/RequestPermissionsResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.model; 16 | 17 | import com.google.auto.value.AutoValue; 18 | 19 | import java.util.Arrays; 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | import androidx.annotation.NonNull; 24 | 25 | @AutoValue public abstract class RequestPermissionsResult { 26 | 27 | public static RequestPermissionsResult create(int requestCode, @NonNull String[] permissions, 28 | @NonNull int[] grantResults) { 29 | return new AutoValue_RequestPermissionsResult(requestCode, 30 | Collections.unmodifiableList(Arrays.asList(permissions)), grantResults); 31 | } 32 | 33 | public abstract int requestCode(); 34 | 35 | @NonNull public abstract List permissions(); 36 | 37 | @SuppressWarnings("mutable") 38 | @NonNull public abstract int[] grantResults(); 39 | } 40 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/NaviComponent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import androidx.annotation.NonNull; 18 | 19 | /** 20 | * Represents an Android component (Activity, Fragment) that can have listeners. 21 | */ 22 | public interface NaviComponent { 23 | 24 | /** 25 | * Determines whether this component can handle particular events. 26 | * 27 | * For example, Activities do not handle Event.CREATE_VIEW since they do not have that step. 28 | * 29 | * @param events the events to check 30 | * @return true if all events can be handled 31 | */ 32 | boolean handlesEvents(Event... events); 33 | 34 | /** 35 | * Adds a listener to this component. 36 | * 37 | * @param event an Event 38 | * @param listener the listener for that event 39 | * @param the callback type for the event 40 | * @throws IllegalArgumentException if this component cannot handle the event 41 | */ 42 | void addListener(@NonNull Event event, @NonNull Listener listener); 43 | 44 | /** 45 | * Removes a listener from this component. 46 | * 47 | * @param the callback type for the event 48 | * @param listener the listener for that event 49 | */ 50 | void removeListener(@NonNull Listener listener); 51 | } 52 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/rx/NaviOnSubscribe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.rx; 16 | 17 | import com.trello.navi2.Event; 18 | import com.trello.navi2.Listener; 19 | import com.trello.navi2.NaviComponent; 20 | 21 | import java.util.concurrent.atomic.AtomicBoolean; 22 | 23 | import androidx.annotation.NonNull; 24 | import io.reactivex.ObservableEmitter; 25 | import io.reactivex.ObservableOnSubscribe; 26 | import io.reactivex.disposables.Disposable; 27 | 28 | final class NaviOnSubscribe implements ObservableOnSubscribe{ 29 | 30 | final NaviComponent component; 31 | 32 | final Event event; 33 | 34 | NaviOnSubscribe(NaviComponent component, Event event) { 35 | this.component = component; 36 | this.event = event; 37 | } 38 | 39 | @Override public void subscribe(final ObservableEmitter emitter) { 40 | EmitterListener listener = new EmitterListener(emitter); 41 | emitter.setDisposable(listener); 42 | component.addListener(event, listener); 43 | } 44 | 45 | class EmitterListener extends AtomicBoolean implements Listener, Disposable { 46 | final ObservableEmitter emitter; 47 | 48 | public EmitterListener(ObservableEmitter emitter) { 49 | this.emitter = emitter; 50 | } 51 | 52 | @Override public void call(@NonNull T t) { 53 | emitter.onNext(t); 54 | } 55 | 56 | @Override public void dispose() { 57 | if (compareAndSet(false, true)) { 58 | component.removeListener(this); 59 | } 60 | } 61 | 62 | @Override public boolean isDisposed() { 63 | return get(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/EventHandlingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import com.trello.navi2.internal.NaviEmitter; 18 | import org.junit.Rule; 19 | import org.junit.Test; 20 | import org.junit.rules.ExpectedException; 21 | 22 | import static junit.framework.Assert.assertFalse; 23 | import static junit.framework.Assert.assertTrue; 24 | import static org.mockito.Mockito.mock; 25 | 26 | public class EventHandlingTest { 27 | 28 | @Rule public final ExpectedException exception = ExpectedException.none(); 29 | 30 | @Test public void handlesEventsNone() { 31 | NaviComponent component = NaviEmitter.createActivityEmitter(); 32 | assertTrue(component.handlesEvents()); 33 | } 34 | 35 | @Test public void handlesEventsSingle() { 36 | NaviComponent component = NaviEmitter.createActivityEmitter(); 37 | assertTrue(component.handlesEvents(Event.CREATE)); 38 | assertFalse(component.handlesEvents(Event.CREATE_VIEW)); 39 | } 40 | 41 | @Test public void handlesEventsMultiple() { 42 | NaviComponent component = NaviEmitter.createActivityEmitter(); 43 | assertTrue(component.handlesEvents(Event.CREATE, Event.START, Event.RESUME)); 44 | assertFalse(component.handlesEvents(Event.ATTACH, Event.CREATE_VIEW)); 45 | assertFalse(component.handlesEvents(Event.CREATE, Event.CREATE_VIEW)); 46 | } 47 | 48 | @Test public void throwOnAddUnsupportedListener() { 49 | final NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 50 | exception.expect(IllegalArgumentException.class); 51 | emitter.addListener(Event.DETACH, mock(Listener.class)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/internal/HandledEvents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.internal; 16 | 17 | import com.trello.navi2.Event; 18 | import java.util.Arrays; 19 | import java.util.List; 20 | 21 | /** 22 | * A place to store a common list of handled events by activities and fragments 23 | */ 24 | final class HandledEvents { 25 | 26 | static final List> ACTIVITY_EVENTS = 27 | Arrays.asList( 28 | Event.CREATE, 29 | Event.CREATE_PERSISTABLE, 30 | Event.START, 31 | Event.POST_CREATE, 32 | Event.POST_CREATE_PERSISTABLE, 33 | Event.RESUME, 34 | Event.PAUSE, 35 | Event.STOP, 36 | Event.DESTROY, 37 | Event.RESTART, 38 | Event.SAVE_INSTANCE_STATE, 39 | Event.SAVE_INSTANCE_STATE_PERSISTABLE, 40 | Event.RESTORE_INSTANCE_STATE, 41 | Event.RESTORE_INSTANCE_STATE_PERSISTABLE, 42 | Event.NEW_INTENT, 43 | Event.BACK_PRESSED, 44 | Event.ATTACHED_TO_WINDOW, 45 | Event.DETACHED_FROM_WINDOW, 46 | Event.CONFIGURATION_CHANGED, 47 | Event.ACTIVITY_RESULT, 48 | Event.REQUEST_PERMISSIONS_RESULT 49 | ); 50 | 51 | static final List> FRAGMENT_EVENTS = 52 | Arrays.asList( 53 | Event.ATTACH, 54 | Event.CREATE, 55 | Event.CREATE_VIEW, 56 | Event.VIEW_CREATED, 57 | Event.ACTIVITY_CREATED, 58 | Event.VIEW_STATE_RESTORED, 59 | Event.START, 60 | Event.RESUME, 61 | Event.PAUSE, 62 | Event.STOP, 63 | Event.DESTROY_VIEW, 64 | Event.DESTROY, 65 | Event.DETACH, 66 | Event.SAVE_INSTANCE_STATE, 67 | Event.CONFIGURATION_CHANGED, 68 | Event.ACTIVITY_RESULT, 69 | Event.REQUEST_PERMISSIONS_RESULT 70 | ); 71 | 72 | private HandledEvents() { 73 | throw new AssertionError("No instances!"); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/rx/RxNaviAllEventTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.rx; 16 | 17 | import android.os.Bundle; 18 | import android.os.PersistableBundle; 19 | import com.trello.navi2.Event; 20 | import com.trello.navi2.Event.Type; 21 | import com.trello.navi2.internal.NaviEmitter; 22 | import io.reactivex.observers.TestObserver; 23 | import org.junit.Test; 24 | 25 | import static org.mockito.Mockito.mock; 26 | 27 | public final class RxNaviAllEventTest { 28 | 29 | private final NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 30 | 31 | // Test event without listener params works 32 | @Test public void observeAllStart() { 33 | TestObserver testObserver = RxNavi.observe(emitter, Event.ALL).test(); 34 | testObserver.assertNoValues(); 35 | 36 | emitter.onStart(); 37 | testObserver.dispose(); 38 | emitter.onStart(); 39 | 40 | testObserver.assertValue(Type.START); 41 | testObserver.assertNotTerminated(); 42 | } 43 | 44 | // Test event with listener params works 45 | @Test public void observeAllCreate() { 46 | TestObserver testObserver = RxNavi.observe(emitter, Event.ALL).test(); 47 | testObserver.assertNoValues(); 48 | 49 | Bundle bundle = new Bundle(); 50 | emitter.onCreate(bundle); 51 | testObserver.dispose(); 52 | emitter.onCreate(bundle); 53 | 54 | testObserver.assertValue(Type.CREATE); 55 | testObserver.assertNotTerminated(); 56 | } 57 | 58 | // Test persistable Activities 59 | @Test public void observeAllCreatePersistable() { 60 | TestObserver testObserver = RxNavi.observe(emitter, Event.ALL).test(); 61 | testObserver.assertNoValues(); 62 | 63 | Bundle bundle = new Bundle(); 64 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 65 | emitter.onCreate(bundle); 66 | emitter.onCreate(bundle, persistableBundle); 67 | testObserver.dispose(); 68 | emitter.onCreate(bundle); 69 | emitter.onCreate(bundle, persistableBundle); 70 | 71 | testObserver.assertValues(Type.CREATE, Type.CREATE_PERSISTABLE); 72 | testObserver.assertNotTerminated(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/AllEventTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import android.os.Bundle; 18 | import android.os.PersistableBundle; 19 | import com.trello.navi2.Event.Type; 20 | import com.trello.navi2.internal.NaviEmitter; 21 | import org.junit.After; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.mockito.Mock; 25 | import org.mockito.MockitoAnnotations; 26 | 27 | import static org.mockito.Mockito.mock; 28 | import static org.mockito.Mockito.verify; 29 | import static org.mockito.Mockito.verifyNoMoreInteractions; 30 | 31 | public final class AllEventTest { 32 | 33 | private final NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 34 | 35 | @Mock Listener listener; 36 | 37 | @Before 38 | public void setUp() { 39 | MockitoAnnotations.initMocks(this); 40 | } 41 | 42 | @After 43 | public void tearDown() { 44 | verifyNoMoreInteractions(listener); 45 | } 46 | 47 | // Test event without listener params works 48 | @Test public void startAllListener() { 49 | emitter.addListener(Event.ALL, listener); 50 | 51 | emitter.onStart(); 52 | verify(listener).call(Type.START); 53 | 54 | emitter.removeListener(listener); 55 | emitter.onStart(); 56 | } 57 | 58 | // Test event with listener params works 59 | @Test public void createAllListener() { 60 | emitter.addListener(Event.ALL, listener); 61 | 62 | Bundle bundle = new Bundle(); 63 | emitter.onCreate(bundle); 64 | verify(listener).call(Type.CREATE); 65 | 66 | emitter.removeListener(listener); 67 | emitter.onCreate(bundle); 68 | } 69 | 70 | // Test persistable Activities 71 | @Test public void createPersistableListener() { 72 | emitter.addListener(Event.ALL, listener); 73 | 74 | Bundle bundle = new Bundle(); 75 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 76 | emitter.onCreate(bundle); 77 | emitter.onCreate(bundle, persistableBundle); 78 | verify(listener).call(Type.CREATE); 79 | verify(listener).call(Type.CREATE_PERSISTABLE); 80 | 81 | emitter.removeListener(listener); 82 | emitter.onCreate(bundle, persistableBundle); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /sample/src/main/java/com/trello/navi2/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.sample; 16 | 17 | import android.os.Bundle; 18 | import android.widget.TextView; 19 | import com.trello.navi2.Event; 20 | import com.trello.navi2.NaviComponent; 21 | import com.trello.navi2.component.support.NaviAppCompatActivity; 22 | import com.trello.navi2.rx.RxNavi; 23 | import io.reactivex.Observable; 24 | import io.reactivex.android.schedulers.AndroidSchedulers; 25 | import io.reactivex.functions.Consumer; 26 | import io.reactivex.functions.Function; 27 | import java.util.concurrent.TimeUnit; 28 | 29 | /** 30 | * Tiny sample. 31 | * 32 | * Don't take this too seriously. This is just a fraction of what could be done with Navi. 33 | */ 34 | public class MainActivity extends NaviAppCompatActivity { 35 | 36 | // This demonstrates we don't necessarily need a reference to the Activity itself in order 37 | // to hook into its lifecycle; the NaviActivity could be provided by anyone. 38 | private final NaviComponent naviComponent = this; 39 | 40 | TextView counter; 41 | 42 | public MainActivity() { 43 | // Instead of using onCreate, we can use Observables 44 | RxNavi.observe(naviComponent, Event.CREATE).subscribe(new Consumer() { 45 | @Override public void accept(Bundle bundle) throws Exception { 46 | setContentView(R.layout.main); 47 | counter = (TextView) findViewById(R.id.counter); 48 | } 49 | }); 50 | 51 | // Counter that operates on screen only while resumed; automatically ends itself on destroy 52 | RxNavi.observe(naviComponent, Event.RESUME) 53 | .flatMap(new Function>() { 54 | @Override public Observable apply(Object ignore) throws Exception { 55 | return Observable.interval(1, TimeUnit.SECONDS) 56 | .takeUntil(RxNavi.observe(naviComponent, Event.PAUSE)); 57 | } 58 | }) 59 | .takeUntil(RxNavi.observe(naviComponent, Event.DESTROY)) 60 | .startWith(-1L) 61 | .observeOn(AndroidSchedulers.mainThread()) 62 | .subscribe(new Consumer() { 63 | @Override public void accept(Long count) throws Exception { 64 | counter.setText("Num seconds resumed: " + (count + 1)); 65 | } 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/AddRemoveTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import android.os.Bundle; 18 | import com.trello.navi2.internal.NaviEmitter; 19 | import org.junit.Rule; 20 | import org.junit.Test; 21 | import org.junit.rules.ExpectedException; 22 | 23 | import static org.mockito.ArgumentMatchers.any; 24 | import static org.mockito.Mockito.mock; 25 | import static org.mockito.Mockito.verify; 26 | import static org.mockito.Mockito.verifyNoMoreInteractions; 27 | 28 | public class AddRemoveTest { 29 | 30 | @Rule public final ExpectedException exception = ExpectedException.none(); 31 | 32 | @Test public void add() { 33 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 34 | Listener listener = mock(Listener.class); 35 | emitter.addListener(Event.START, listener); 36 | emitter.onStart(); 37 | verify(listener).call(any()); 38 | } 39 | 40 | // Allowed, but idempotent 41 | @Test public void doubleAdd() { 42 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 43 | Listener listener = mock(Listener.class); 44 | emitter.addListener(Event.START, listener); 45 | emitter.addListener(Event.START, listener); 46 | emitter.onStart(); 47 | verify(listener).call(any()); 48 | } 49 | 50 | // Not allowed 51 | @Test public void throwsOnMultiAdd() { 52 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 53 | Listener listener = mock(Listener.class); 54 | emitter.addListener(Event.CREATE, listener); 55 | exception.expect(IllegalStateException.class); 56 | emitter.addListener(Event.SAVE_INSTANCE_STATE, listener); 57 | } 58 | 59 | @Test public void remove() { 60 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 61 | Listener listener = mock(Listener.class); 62 | emitter.addListener(Event.START, listener); 63 | emitter.removeListener(listener); 64 | emitter.onStart(); 65 | verifyNoMoreInteractions(listener); 66 | } 67 | 68 | // Dumb, but allowed 69 | @Test public void doubleRemove() { 70 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 71 | Listener listener = mock(Listener.class); 72 | emitter.addListener(Event.START, listener); 73 | emitter.removeListener(listener); 74 | emitter.removeListener(listener); 75 | emitter.onStart(); 76 | verifyNoMoreInteractions(listener); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Navi 2 | 3 | *Hey, listen!* 4 | 5 | Adds listeners for `Activity` and `Fragment`. 6 | 7 | ## Deprecated 8 | 9 | The navi library is deprecated in favor of [lifecycle-aware components](https://developer.android.com/topic/libraries/architecture/lifecycle). No more development will be taking place. 10 | 11 | ## Why? 12 | 13 | In a word: **composition**. 14 | 15 | **For applications**, you currently have to tie a lot of your functionality directly to each `Activity` and `Fragment`. The potential for code reuse is low. Testing is difficult. 16 | 17 | **For libraries**, if you want to interact with the `Activity` or `Fragment` at all, good luck. You either have to leave brittle instructions on how to properly implement the library, or you provide your own `Activity`/`Fragment`. Two libraries providing their own components are difficult (or impossible) to use together. 18 | 19 | With Navi, you can avoid all these problems. Applications can decouple your code from the underlying `Activity` or `Fragment`. Libraries using Navi can write real plugins instead of brittle/coupled solutions. 20 | 21 | ## Usage 22 | 23 | The `NaviComponent` interface is the basis for everything; you can add/remove listeners for 24 | any specific callbacks that exist on `Activity` and `Fragment`: 25 | 26 | ```java 27 | naviComponent.addListener(Event.CREATE, new Listener() { 28 | @Override public void call(Bundle bundle) { 29 | setContentView(R.layout.main); 30 | } 31 | }); 32 | ``` 33 | 34 | You will either need to implement the `NaviComponent` interface yourself, or if you're able, you 35 | can save time by using one of the default implementations provided (in the form of `NaviActivity`, 36 | `NaviAppCompatActivity`, `NaviFragment` and `NaviDialogFragment`). This flexibility allows you to 37 | integrate Navi even if you're already being forced to use a different base `Activity` or `Fragment`. 38 | 39 | Since RxJava is the bees knees, it also provides Rx bindings for all listeners via `RxNavi`. Simply pass your `NaviComponent` to them and it'll do the 40 | rest. For example, you could use it to set the content view instead of overriding `onCreate()`: 41 | 42 | ```java 43 | RxNavi.observe(naviComponent, Event.CREATE) 44 | .subscribe(bundle -> setContentView(R.layout.main)); 45 | ``` 46 | 47 | ## Installation 48 | 49 | ```gradle 50 | compile 'com.trello.navi2:navi:2.1.0' 51 | ``` 52 | 53 | ## License 54 | 55 | Copyright (C) 2018 Trello 56 | 57 | Licensed under the Apache License, Version 2.0 (the "License"); 58 | you may not use this file except in compliance with the License. 59 | You may obtain a copy of the License at 60 | 61 | http://www.apache.org/licenses/LICENSE-2.0 62 | 63 | Unless required by applicable law or agreed to in writing, software 64 | distributed under the License is distributed on an "AS IS" BASIS, 65 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 66 | See the License for the specific language governing permissions and 67 | limitations under the License. 68 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/NullBundleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import android.os.Bundle; 18 | import com.trello.navi2.internal.NaviEmitter; 19 | import org.junit.Test; 20 | 21 | import static org.mockito.ArgumentMatchers.any; 22 | import static org.mockito.Mockito.mock; 23 | import static org.mockito.Mockito.verify; 24 | 25 | public class NullBundleTest { 26 | 27 | @Test public void activityCreatedWithNullBundle() { 28 | NaviEmitter emitter = NaviEmitter.createFragmentEmitter(); 29 | Listener listener = mock(Listener.class); 30 | emitter.addListener(Event.ACTIVITY_CREATED, listener); 31 | emitter.onActivityCreated(null); 32 | verify(listener).call(any(Bundle.class)); 33 | } 34 | 35 | @Test public void createWithNullBundle() { 36 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 37 | Listener listener = mock(Listener.class); 38 | emitter.addListener(Event.CREATE, listener); 39 | emitter.onCreate(null); 40 | verify(listener).call(any(Bundle.class)); 41 | } 42 | 43 | @Test public void createViewWithNullBundle() { 44 | NaviEmitter emitter = NaviEmitter.createFragmentEmitter(); 45 | Listener listener = mock(Listener.class); 46 | emitter.addListener(Event.CREATE_VIEW, listener); 47 | emitter.onCreateView(null); 48 | verify(listener).call(any(Bundle.class)); 49 | } 50 | 51 | @Test public void postCreateWithNullBundle() { 52 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 53 | Listener listener = mock(Listener.class); 54 | emitter.addListener(Event.POST_CREATE, listener); 55 | emitter.onPostCreate(null); 56 | verify(listener).call(any(Bundle.class)); 57 | } 58 | 59 | @Test public void restoreInstanceStateWithNullBundle() { 60 | NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 61 | Listener listener = mock(Listener.class); 62 | emitter.addListener(Event.RESTORE_INSTANCE_STATE, listener); 63 | emitter.onRestoreInstanceState(null); 64 | verify(listener).call(any(Bundle.class)); 65 | } 66 | 67 | @Test public void viewStateRestoredWithNullBundle() { 68 | NaviEmitter emitter = NaviEmitter.createFragmentEmitter(); 69 | Listener listener = mock(Listener.class); 70 | emitter.addListener(Event.VIEW_STATE_RESTORED, listener); 71 | emitter.onViewStateRestored(null); 72 | verify(listener).call(any(Bundle.class)); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /gradle/artifacts.gradle: -------------------------------------------------------------------------------- 1 | if (project.plugins.hasPlugin('com.android.library')) { 2 | android.libraryVariants.all { variant -> 3 | Task javadocTask = task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) { 4 | group = 'artifact' 5 | description "Generates Javadoc for $variant.name" 6 | 7 | // Source files from the variant 8 | source = variant.javaCompiler.source 9 | 10 | // Classpath from the variant + android.jar 11 | String androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar" 12 | classpath = variant.javaCompiler.classpath + files(androidJar) 13 | 14 | // The Android online reference doesn't include package-list, so we have to use the local one 15 | String packageListRef = "${android.sdkDirectory}/docs/reference/" 16 | options.linksOffline 'http://d.android.com/reference/', packageListRef 17 | 18 | // Additional links for any RxJava references 19 | options.links 'http://reactivex.io/RxJava/javadoc/' 20 | 21 | // Exclude generated files 22 | exclude '**/BuildConfig.java' 23 | exclude '**/R.java' 24 | 25 | // Output to a unique javadoc folder per variant 26 | destinationDir = new File(project.docsDir, "javadoc-$variant.name") 27 | } 28 | 29 | // For official releasese, don't prefix the name so the artifact is published correctly 30 | // (Can't seem to modify it for publishing, for whatever reason...) 31 | String classifierPrefix = (variant.name == 'release') ? '' : "$variant.name-" 32 | 33 | Task javadocJarTask = task("generate${variant.name.capitalize()}JavadocJar", type: Jar, dependsOn: javadocTask) { 34 | group = 'artifact' 35 | description = "Generates Javadoc jar for $variant.name" 36 | 37 | classifier = "${classifierPrefix}javadoc" 38 | from javadocTask.destinationDir 39 | } 40 | 41 | Task sourcesJarTask = task("generate${variant.name.capitalize()}SourcesJar", type: Jar) { 42 | group = 'artifact' 43 | description = "Generates sources jar for $variant.name" 44 | 45 | classifier = "${classifierPrefix}sources" 46 | from variant.javaCompiler.source 47 | } 48 | 49 | if (variant.name == 'release') { 50 | // There's a lot of "magic" around the archives configuration; easier 51 | // just to embrace it rather than try to configure around it 52 | artifacts { 53 | archives javadocJarTask, sourcesJarTask 54 | } 55 | } 56 | else { 57 | // Create a configuration we can publish from for each variant 58 | String configurationName = "archives${variant.name.capitalize()}" 59 | configurations.create(configurationName) 60 | artifacts.add configurationName, javadocJarTask 61 | artifacts.add configurationName, sourcesJarTask 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /gradle/gradle-mvn-push.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Chris Banes 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'maven' 18 | apply plugin: 'signing' 19 | 20 | def isReleaseBuild() { 21 | return VERSION_NAME.contains("SNAPSHOT") == false 22 | } 23 | 24 | def getRepositoryUsername() { 25 | return hasProperty('SONATYPE_NEXUS_USERNAME') ? SONATYPE_NEXUS_USERNAME : "" 26 | } 27 | 28 | def getRepositoryPassword() { 29 | return hasProperty('SONATYPE_NEXUS_PASSWORD') ? SONATYPE_NEXUS_PASSWORD : "" 30 | } 31 | 32 | afterEvaluate { project -> 33 | uploadArchives { 34 | repositories { 35 | mavenDeployer { 36 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 37 | 38 | pom.groupId = GROUP 39 | pom.artifactId = POM_ARTIFACT_ID 40 | pom.version = VERSION_NAME 41 | 42 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { 43 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 44 | } 45 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { 46 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 47 | } 48 | 49 | pom.project { 50 | name POM_NAME 51 | packaging POM_PACKAGING 52 | description POM_DESCRIPTION 53 | url POM_URL 54 | 55 | scm { 56 | url POM_SCM_URL 57 | connection POM_SCM_CONNECTION 58 | developerConnection POM_SCM_DEV_CONNECTION 59 | } 60 | 61 | licenses { 62 | license { 63 | name POM_LICENCE_NAME 64 | url POM_LICENCE_URL 65 | distribution POM_LICENCE_DIST 66 | } 67 | } 68 | 69 | developers { 70 | developer { 71 | id POM_DEVELOPER_ID 72 | name POM_DEVELOPER_NAME 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | 80 | signing { 81 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } 82 | sign configurations.archives 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2.1.0 (2018-10-25) 4 | 5 | **Notice: As of this release, the navi library is deprecated in favor of [lifecycle-aware components](https://developer.android.com/topic/libraries/architecture/lifecycle). No more development will be taking place.** 6 | 7 | * [#103](https://github.com/trello/navi/pull/103) Switched to AndroidX libraries 8 | 9 | ## 2.0.1 (2018-05-20) 10 | 11 | * [#93](https://github.com/trello/navi/pull/93) Make NaviAppCompatDialogFragment extend from AppCompatDialogFragment 12 | * [#96](https://github.com/trello/navi/pull/96) Fail early on null component or event 13 | * [#97](https://github.com/trello/navi/pull/97) Remove unnecessary throws Exception in NaviOnSubscribe 14 | * [#98](https://github.com/trello/navi/pull/98) Disable BuildConfig generation 15 | 16 | ## 2.0 (2016-11-21) 17 | 18 | This major revision was made to support RxJava 2. Navi 2.0 lives in a new namespace and package 19 | names so that it can work side-by-side with Navi 1.0 (while transitioning). 20 | 21 | The one major behavior change to be aware of is that, since RxJava 2 does not allow nulls, Navi 22 | no longer emits nulls either. This means that any former `Void` types are now `Object` types 23 | (where the `Object` is just a signal). There were also cases of null `Bundles` that are now replaced 24 | by empty `Bundles`. 25 | 26 | * [#79](https://github.com/trello/navi/pull/79) Made all base `Activities`/`Fragments` abstract 27 | * [#77](https://github.com/trello/navi/pull/77) Switch to using RxJava 2.0 28 | * [#76](https://github.com/trello/navi/pull/76) Avoid using null 29 | * [#75](https://github.com/trello/navi/pull/75) Use AutoValue for models (which changed the method signature of `RequestPermissionsResult.permissions()`) 30 | * [#74](https://github.com/trello/navi/pull/74) Change signature of `NaviEmitter.onViewCreated()` to match the rest of the API 31 | * [#73](https://github.com/trello/navi/pull/73) Bumped version to 2.0 and use com.trello.navi2 32 | 33 | ## 1.0 (2016-08-09) 34 | 35 | First and (hopefully) final release of 1.x branch! 36 | 37 | This release marks the start of maintenance mode for RxJava 1 support. Future work will be devoted 38 | to supporting RxJava 2. Important bugs may be squashed but new features will have to be 39 | extraordinarily compelling in order to be added. 40 | 41 | ## 0.2.2 (2016-08-09) 42 | 43 | * [#62](https://github.com/trello/navi/pull/62) Added `Event.POST_CREATE` and `Event.POST_CREATE_PERSISTABLE` 44 | 45 | ## 0.2.1 (2016-07-05) 46 | 47 | * [#57](https://github.com/trello/navi/pull/57) Added `Event.VIEW_CREATED` for `Fragments` 48 | * [#54](https://github.com/trello/navi/pull/54) Use `final` modifier for interface implementations 49 | * [#53](https://github.com/trello/navi/pull/53) Add `@CallSuper` annotation on component classes 50 | 51 | ## 0.2.0 (2016-02-27) 52 | 53 | There are a few method signature and behavior changes, so upgrade carefully. 54 | 55 | * [#47](https://github.com/trello/navi/pull/47) Added `Type.CREATE_PERSISTABLE`, `Type.SAVE_INSTANCE_STATE_PERSISTABLE` and `Type.RESTORE_INSTANCE_STATE_PERSISTABLE` so that the `ALL` tracker can distinguish between events. 56 | 57 | Also avoided calling `CREATE`, `SAVE_INSTANCE_STATE` and `RESTORE_INSTANCE_STATE` too often in persistable `Activities`. 58 | 59 | * [#46](https://github.com/trello/navi/pull/46) Destruction events now emit before their super() calls. 60 | * [#41](https://github.com/trello/navi/pull/41) Removed unnecessary `Event` parameter from `NaviComponent.removeListener()`. 61 | * [#39](https://github.com/trello/navi/pull/39) Added `NaviAppCompatDialogFragment`. 62 | 63 | ## 0.1.3 (2015-12-03) 64 | 65 | * [#24](https://github.com/trello/navi/pull/24) Converted hasEvent() -> handlesEvents() 66 | 67 | ## 0.1.2 (2015-11-25) 68 | 69 | * [#20](https://github.com/trello/navi/pull/20) Added `Event.ALL` for listening to all events 70 | 71 | ## 0.1.1 (2015-11-09) 72 | 73 | * [#16](https://github.com/trello/navi/pull/16) Fixed concurrency problems with add/removing listeners while emitting an event 74 | 75 | ## 0.1.0 (2015-11-04) 76 | 77 | Initial release! -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/component/NaviFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.component; 16 | 17 | import android.app.Activity; 18 | import android.app.Fragment; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.content.res.Configuration; 22 | import android.os.Bundle; 23 | import android.view.LayoutInflater; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | 27 | import com.trello.navi2.Event; 28 | import com.trello.navi2.Listener; 29 | import com.trello.navi2.NaviComponent; 30 | import com.trello.navi2.internal.NaviEmitter; 31 | 32 | import androidx.annotation.CallSuper; 33 | import androidx.annotation.NonNull; 34 | import androidx.annotation.Nullable; 35 | 36 | public abstract class NaviFragment extends Fragment implements NaviComponent { 37 | 38 | private final NaviEmitter base = NaviEmitter.createFragmentEmitter(); 39 | 40 | @Override public final boolean handlesEvents(Event... events) { 41 | return base.handlesEvents(events); 42 | } 43 | 44 | @Override public final void addListener(@NonNull Event event, @NonNull Listener listener) { 45 | base.addListener(event, listener); 46 | } 47 | 48 | @Override public final void removeListener(@NonNull Listener listener) { 49 | base.removeListener(listener); 50 | } 51 | 52 | @Override @CallSuper public void onAttach(Activity activity) { 53 | super.onAttach(activity); 54 | base.onAttach(activity); 55 | } 56 | 57 | @Override @CallSuper public void onAttach(Context context) { 58 | super.onAttach(context); 59 | base.onAttach(context); 60 | } 61 | 62 | @Override @CallSuper public void onCreate(Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | base.onCreate(savedInstanceState); 65 | } 66 | 67 | @Nullable @Override @CallSuper public View onCreateView(LayoutInflater inflater, ViewGroup container, 68 | Bundle savedInstanceState) { 69 | base.onCreateView(savedInstanceState); 70 | return super.onCreateView(inflater, container, savedInstanceState); 71 | } 72 | 73 | @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 74 | base.onViewCreated(view, savedInstanceState); 75 | super.onViewCreated(view, savedInstanceState); 76 | } 77 | 78 | @Override @CallSuper public void onActivityCreated(Bundle savedInstanceState) { 79 | super.onActivityCreated(savedInstanceState); 80 | base.onActivityCreated(savedInstanceState); 81 | } 82 | 83 | @Override @CallSuper public void onViewStateRestored(Bundle savedInstanceState) { 84 | super.onViewStateRestored(savedInstanceState); 85 | base.onViewStateRestored(savedInstanceState); 86 | } 87 | 88 | @Override @CallSuper public void onStart() { 89 | super.onStart(); 90 | base.onStart(); 91 | } 92 | 93 | @Override @CallSuper public void onResume() { 94 | super.onResume(); 95 | base.onResume(); 96 | } 97 | 98 | @Override @CallSuper public void onPause() { 99 | base.onPause(); 100 | super.onPause(); 101 | } 102 | 103 | @Override @CallSuper public void onStop() { 104 | base.onStop(); 105 | super.onStop(); 106 | } 107 | 108 | @Override @CallSuper public void onDestroyView() { 109 | base.onDestroyView(); 110 | super.onDestroyView(); 111 | } 112 | 113 | @Override @CallSuper public void onDestroy() { 114 | base.onDestroy(); 115 | super.onDestroy(); 116 | } 117 | 118 | @Override @CallSuper public void onDetach() { 119 | base.onDetach(); 120 | super.onDetach(); 121 | } 122 | 123 | @Override @CallSuper public void onSaveInstanceState(Bundle outState) { 124 | super.onSaveInstanceState(outState); 125 | base.onSaveInstanceState(outState); 126 | } 127 | 128 | @Override @CallSuper public void onConfigurationChanged(Configuration newConfig) { 129 | super.onConfigurationChanged(newConfig); 130 | base.onConfigurationChanged(newConfig); 131 | } 132 | 133 | @Override @CallSuper public void onActivityResult(int requestCode, int resultCode, Intent data) { 134 | super.onActivityResult(requestCode, resultCode, data); 135 | base.onActivityResult(requestCode, resultCode, data); 136 | } 137 | 138 | @Override @CallSuper public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 139 | @NonNull int[] grantResults) { 140 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 141 | base.onRequestPermissionsResult(requestCode, permissions, grantResults); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/component/NaviDialogFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.component; 16 | 17 | import android.app.Activity; 18 | import android.app.DialogFragment; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.content.res.Configuration; 22 | import android.os.Bundle; 23 | import android.view.LayoutInflater; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | 27 | import com.trello.navi2.Event; 28 | import com.trello.navi2.Listener; 29 | import com.trello.navi2.NaviComponent; 30 | import com.trello.navi2.internal.NaviEmitter; 31 | 32 | import androidx.annotation.CallSuper; 33 | import androidx.annotation.NonNull; 34 | import androidx.annotation.Nullable; 35 | 36 | public abstract class NaviDialogFragment extends DialogFragment implements NaviComponent { 37 | 38 | private final NaviEmitter base = NaviEmitter.createFragmentEmitter(); 39 | 40 | @Override public final boolean handlesEvents(Event... events) { 41 | return base.handlesEvents(events); 42 | } 43 | 44 | @Override public final void addListener(@NonNull Event event, @NonNull Listener listener) { 45 | base.addListener(event, listener); 46 | } 47 | 48 | @Override public final void removeListener(@NonNull Listener listener) { 49 | base.removeListener(listener); 50 | } 51 | 52 | @Override @CallSuper public void onAttach(Activity activity) { 53 | super.onAttach(activity); 54 | base.onAttach(activity); 55 | } 56 | 57 | @Override @CallSuper public void onAttach(Context context) { 58 | super.onAttach(context); 59 | base.onAttach(context); 60 | } 61 | 62 | @Override @CallSuper public void onCreate(Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | base.onCreate(savedInstanceState); 65 | } 66 | 67 | @Nullable @Override @CallSuper public View onCreateView(LayoutInflater inflater, ViewGroup container, 68 | Bundle savedInstanceState) { 69 | base.onCreateView(savedInstanceState); 70 | return super.onCreateView(inflater, container, savedInstanceState); 71 | } 72 | 73 | @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 74 | base.onViewCreated(view, savedInstanceState); 75 | super.onViewCreated(view, savedInstanceState); 76 | } 77 | 78 | @Override @CallSuper public void onActivityCreated(Bundle savedInstanceState) { 79 | super.onActivityCreated(savedInstanceState); 80 | base.onActivityCreated(savedInstanceState); 81 | } 82 | 83 | @Override @CallSuper public void onViewStateRestored(Bundle savedInstanceState) { 84 | super.onViewStateRestored(savedInstanceState); 85 | base.onViewStateRestored(savedInstanceState); 86 | } 87 | 88 | @Override @CallSuper public void onStart() { 89 | super.onStart(); 90 | base.onStart(); 91 | } 92 | 93 | @Override @CallSuper public void onResume() { 94 | super.onResume(); 95 | base.onResume(); 96 | } 97 | 98 | @Override @CallSuper public void onPause() { 99 | base.onPause(); 100 | super.onPause(); 101 | } 102 | 103 | @Override @CallSuper public void onStop() { 104 | base.onStop(); 105 | super.onStop(); 106 | } 107 | 108 | @Override @CallSuper public void onDestroyView() { 109 | base.onDestroyView(); 110 | super.onDestroyView(); 111 | } 112 | 113 | @Override @CallSuper public void onDestroy() { 114 | base.onDestroy(); 115 | super.onDestroy(); 116 | } 117 | 118 | @Override @CallSuper public void onDetach() { 119 | base.onDetach(); 120 | super.onDetach(); 121 | } 122 | 123 | @Override @CallSuper public void onSaveInstanceState(Bundle outState) { 124 | super.onSaveInstanceState(outState); 125 | base.onSaveInstanceState(outState); 126 | } 127 | 128 | @Override @CallSuper public void onConfigurationChanged(Configuration newConfig) { 129 | super.onConfigurationChanged(newConfig); 130 | base.onConfigurationChanged(newConfig); 131 | } 132 | 133 | @Override @CallSuper public void onActivityResult(int requestCode, int resultCode, Intent data) { 134 | super.onActivityResult(requestCode, resultCode, data); 135 | base.onActivityResult(requestCode, resultCode, data); 136 | } 137 | 138 | @Override @CallSuper public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 139 | @NonNull int[] grantResults) { 140 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 141 | base.onRequestPermissionsResult(requestCode, permissions, grantResults); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/component/support/NaviDialogFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.component.support; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.content.res.Configuration; 21 | import android.os.Bundle; 22 | import android.view.LayoutInflater; 23 | import android.view.View; 24 | import android.view.ViewGroup; 25 | 26 | import com.trello.navi2.Event; 27 | import com.trello.navi2.Listener; 28 | import com.trello.navi2.NaviComponent; 29 | import com.trello.navi2.internal.NaviEmitter; 30 | 31 | import androidx.annotation.CallSuper; 32 | import androidx.annotation.NonNull; 33 | import androidx.annotation.Nullable; 34 | import androidx.fragment.app.DialogFragment; 35 | 36 | public abstract class NaviDialogFragment extends DialogFragment implements NaviComponent { 37 | 38 | private final NaviEmitter base = NaviEmitter.createFragmentEmitter(); 39 | 40 | @Override public final boolean handlesEvents(Event... events) { 41 | return base.handlesEvents(events); 42 | } 43 | 44 | @Override public final void addListener(@NonNull Event event, @NonNull Listener listener) { 45 | base.addListener(event, listener); 46 | } 47 | 48 | @Override public final void removeListener(@NonNull Listener listener) { 49 | base.removeListener(listener); 50 | } 51 | 52 | @Override @CallSuper public void onAttach(Activity activity) { 53 | super.onAttach(activity); 54 | base.onAttach(activity); 55 | } 56 | 57 | @Override @CallSuper public void onAttach(Context context) { 58 | super.onAttach(context); 59 | base.onAttach(context); 60 | } 61 | 62 | @Override @CallSuper public void onCreate(Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | base.onCreate(savedInstanceState); 65 | } 66 | 67 | @Nullable @Override @CallSuper public View onCreateView(LayoutInflater inflater, ViewGroup container, 68 | Bundle savedInstanceState) { 69 | base.onCreateView(savedInstanceState); 70 | return super.onCreateView(inflater, container, savedInstanceState); 71 | } 72 | 73 | @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 74 | base.onViewCreated(view, savedInstanceState); 75 | super.onViewCreated(view, savedInstanceState); 76 | } 77 | 78 | @Override @CallSuper public void onActivityCreated(Bundle savedInstanceState) { 79 | super.onActivityCreated(savedInstanceState); 80 | base.onActivityCreated(savedInstanceState); 81 | } 82 | 83 | @Override @CallSuper public void onViewStateRestored(Bundle savedInstanceState) { 84 | super.onViewStateRestored(savedInstanceState); 85 | base.onViewStateRestored(savedInstanceState); 86 | } 87 | 88 | @Override @CallSuper public void onStart() { 89 | super.onStart(); 90 | base.onStart(); 91 | } 92 | 93 | @Override @CallSuper public void onResume() { 94 | super.onResume(); 95 | base.onResume(); 96 | } 97 | 98 | @Override @CallSuper public void onPause() { 99 | base.onPause(); 100 | super.onPause(); 101 | } 102 | 103 | @Override @CallSuper public void onStop() { 104 | base.onStop(); 105 | super.onStop(); 106 | } 107 | 108 | @Override @CallSuper public void onDestroyView() { 109 | base.onDestroyView(); 110 | super.onDestroyView(); 111 | } 112 | 113 | @Override @CallSuper public void onDestroy() { 114 | base.onDestroy(); 115 | super.onDestroy(); 116 | } 117 | 118 | @Override @CallSuper public void onDetach() { 119 | base.onDetach(); 120 | super.onDetach(); 121 | } 122 | 123 | @Override @CallSuper public void onSaveInstanceState(Bundle outState) { 124 | super.onSaveInstanceState(outState); 125 | base.onSaveInstanceState(outState); 126 | } 127 | 128 | @Override @CallSuper public void onConfigurationChanged(Configuration newConfig) { 129 | super.onConfigurationChanged(newConfig); 130 | base.onConfigurationChanged(newConfig); 131 | } 132 | 133 | @Override @CallSuper public void onActivityResult(int requestCode, int resultCode, Intent data) { 134 | super.onActivityResult(requestCode, resultCode, data); 135 | base.onActivityResult(requestCode, resultCode, data); 136 | } 137 | 138 | @Override @CallSuper public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 139 | @NonNull int[] grantResults) { 140 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 141 | base.onRequestPermissionsResult(requestCode, permissions, grantResults); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/component/support/NaviFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.component.support; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.content.res.Configuration; 21 | import android.os.Bundle; 22 | import android.view.LayoutInflater; 23 | import android.view.View; 24 | import android.view.ViewGroup; 25 | 26 | import com.trello.navi2.Event; 27 | import com.trello.navi2.Listener; 28 | import com.trello.navi2.NaviComponent; 29 | import com.trello.navi2.internal.NaviEmitter; 30 | 31 | import androidx.annotation.CallSuper; 32 | import androidx.annotation.NonNull; 33 | import androidx.annotation.Nullable; 34 | import androidx.fragment.app.Fragment; 35 | 36 | public abstract class NaviFragment extends Fragment implements NaviComponent { 37 | 38 | private final NaviEmitter base = NaviEmitter.createFragmentEmitter(); 39 | 40 | @Override public final boolean handlesEvents(Event... events) { 41 | return base.handlesEvents(events); 42 | } 43 | 44 | @Override public final void addListener(@NonNull Event event, @NonNull Listener listener) { 45 | base.addListener(event, listener); 46 | } 47 | 48 | @Override public final void removeListener(@NonNull Listener listener) { 49 | base.removeListener(listener); 50 | } 51 | 52 | @Override @CallSuper public void onAttach(Activity activity) { 53 | super.onAttach(activity); 54 | base.onAttach(activity); 55 | } 56 | 57 | @Override @CallSuper public void onAttach(Context context) { 58 | super.onAttach(context); 59 | base.onAttach(context); 60 | } 61 | 62 | @Override @CallSuper public void onCreate(Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | base.onCreate(savedInstanceState); 65 | } 66 | 67 | @Nullable @Override @CallSuper public View onCreateView(LayoutInflater inflater, ViewGroup container, 68 | Bundle savedInstanceState) { 69 | base.onCreateView(savedInstanceState); 70 | return super.onCreateView(inflater, container, savedInstanceState); 71 | } 72 | 73 | @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 74 | base.onViewCreated(view, savedInstanceState); 75 | super.onViewCreated(view, savedInstanceState); 76 | } 77 | 78 | @Override @CallSuper public void onActivityCreated(Bundle savedInstanceState) { 79 | super.onActivityCreated(savedInstanceState); 80 | base.onActivityCreated(savedInstanceState); 81 | } 82 | 83 | @Override @CallSuper public void onViewStateRestored(Bundle savedInstanceState) { 84 | super.onViewStateRestored(savedInstanceState); 85 | base.onViewStateRestored(savedInstanceState); 86 | } 87 | 88 | @Override @CallSuper public void onStart() { 89 | super.onStart(); 90 | base.onStart(); 91 | } 92 | 93 | @Override @CallSuper public void onResume() { 94 | super.onResume(); 95 | base.onResume(); 96 | } 97 | 98 | @Override @CallSuper public void onPause() { 99 | base.onPause(); 100 | super.onPause(); 101 | } 102 | 103 | @Override @CallSuper public void onStop() { 104 | base.onStop(); 105 | super.onStop(); 106 | } 107 | 108 | @Override @CallSuper public void onDestroyView() { 109 | base.onDestroyView(); 110 | super.onDestroyView(); 111 | } 112 | 113 | @Override @CallSuper public void onDestroy() { 114 | base.onDestroy(); 115 | super.onDestroy(); 116 | } 117 | 118 | @Override @CallSuper public void onDetach() { 119 | base.onDetach(); 120 | super.onDetach(); 121 | } 122 | 123 | @Override @CallSuper public void onSaveInstanceState(Bundle outState) { 124 | super.onSaveInstanceState(outState); 125 | base.onSaveInstanceState(outState); 126 | } 127 | 128 | @Override @CallSuper public void onConfigurationChanged(Configuration newConfig) { 129 | super.onConfigurationChanged(newConfig); 130 | base.onConfigurationChanged(newConfig); 131 | } 132 | 133 | @Override @CallSuper public void onActivityResult(int requestCode, int resultCode, Intent data) { 134 | super.onActivityResult(requestCode, resultCode, data); 135 | base.onActivityResult(requestCode, resultCode, data); 136 | } 137 | 138 | @Override @CallSuper public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 139 | @NonNull int[] grantResults) { 140 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 141 | base.onRequestPermissionsResult(requestCode, permissions, grantResults); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/component/support/NaviAppCompatDialogFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.component.support; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.content.res.Configuration; 21 | import android.os.Bundle; 22 | import android.view.LayoutInflater; 23 | import android.view.View; 24 | import android.view.ViewGroup; 25 | 26 | import com.trello.navi2.Event; 27 | import com.trello.navi2.Listener; 28 | import com.trello.navi2.NaviComponent; 29 | import com.trello.navi2.internal.NaviEmitter; 30 | 31 | import androidx.annotation.CallSuper; 32 | import androidx.annotation.NonNull; 33 | import androidx.annotation.Nullable; 34 | import androidx.appcompat.app.AppCompatDialogFragment; 35 | 36 | public abstract class NaviAppCompatDialogFragment extends AppCompatDialogFragment implements NaviComponent { 37 | 38 | private final NaviEmitter base = NaviEmitter.createFragmentEmitter(); 39 | 40 | @Override public final boolean handlesEvents(Event... events) { 41 | return base.handlesEvents(events); 42 | } 43 | 44 | @Override public final void addListener(@NonNull Event event, @NonNull Listener listener) { 45 | base.addListener(event, listener); 46 | } 47 | 48 | @Override public final void removeListener(@NonNull Listener listener) { 49 | base.removeListener(listener); 50 | } 51 | 52 | @Override @CallSuper public void onAttach(Activity activity) { 53 | super.onAttach(activity); 54 | base.onAttach(activity); 55 | } 56 | 57 | @Override @CallSuper public void onAttach(Context context) { 58 | super.onAttach(context); 59 | base.onAttach(context); 60 | } 61 | 62 | @Override @CallSuper public void onCreate(Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | base.onCreate(savedInstanceState); 65 | } 66 | 67 | @Nullable @Override @CallSuper public View onCreateView(LayoutInflater inflater, ViewGroup container, 68 | Bundle savedInstanceState) { 69 | base.onCreateView(savedInstanceState); 70 | return super.onCreateView(inflater, container, savedInstanceState); 71 | } 72 | 73 | @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 74 | base.onViewCreated(view, savedInstanceState); 75 | super.onViewCreated(view, savedInstanceState); 76 | } 77 | 78 | @Override @CallSuper public void onActivityCreated(Bundle savedInstanceState) { 79 | super.onActivityCreated(savedInstanceState); 80 | base.onActivityCreated(savedInstanceState); 81 | } 82 | 83 | @Override @CallSuper public void onViewStateRestored(Bundle savedInstanceState) { 84 | super.onViewStateRestored(savedInstanceState); 85 | base.onViewStateRestored(savedInstanceState); 86 | } 87 | 88 | @Override @CallSuper public void onStart() { 89 | super.onStart(); 90 | base.onStart(); 91 | } 92 | 93 | @Override @CallSuper public void onResume() { 94 | super.onResume(); 95 | base.onResume(); 96 | } 97 | 98 | @Override @CallSuper public void onPause() { 99 | base.onPause(); 100 | super.onPause(); 101 | } 102 | 103 | @Override @CallSuper public void onStop() { 104 | base.onStop(); 105 | super.onStop(); 106 | } 107 | 108 | @Override @CallSuper public void onDestroyView() { 109 | base.onDestroyView(); 110 | super.onDestroyView(); 111 | } 112 | 113 | @Override @CallSuper public void onDestroy() { 114 | base.onDestroy(); 115 | super.onDestroy(); 116 | } 117 | 118 | @Override @CallSuper public void onDetach() { 119 | base.onDetach(); 120 | super.onDetach(); 121 | } 122 | 123 | @Override @CallSuper public void onSaveInstanceState(Bundle outState) { 124 | super.onSaveInstanceState(outState); 125 | base.onSaveInstanceState(outState); 126 | } 127 | 128 | @Override @CallSuper public void onConfigurationChanged(Configuration newConfig) { 129 | super.onConfigurationChanged(newConfig); 130 | base.onConfigurationChanged(newConfig); 131 | } 132 | 133 | @Override @CallSuper public void onActivityResult(int requestCode, int resultCode, Intent data) { 134 | super.onActivityResult(requestCode, resultCode, data); 135 | base.onActivityResult(requestCode, resultCode, data); 136 | } 137 | 138 | @Override @CallSuper public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 139 | @NonNull int[] grantResults) { 140 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 141 | base.onRequestPermissionsResult(requestCode, permissions, grantResults); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/component/NaviActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.component; 16 | 17 | import android.app.Activity; 18 | import android.content.Intent; 19 | import android.content.res.Configuration; 20 | import android.os.Bundle; 21 | import android.os.PersistableBundle; 22 | 23 | import com.trello.navi2.Event; 24 | import com.trello.navi2.Listener; 25 | import com.trello.navi2.NaviComponent; 26 | import com.trello.navi2.internal.NaviEmitter; 27 | 28 | import androidx.annotation.CallSuper; 29 | import androidx.annotation.NonNull; 30 | 31 | public abstract class NaviActivity extends Activity implements NaviComponent { 32 | 33 | private final NaviEmitter base = NaviEmitter.createActivityEmitter(); 34 | 35 | @Override public final boolean handlesEvents(Event... events) { 36 | return base.handlesEvents(events); 37 | } 38 | 39 | @Override public final void addListener(@NonNull Event event, @NonNull Listener listener) { 40 | base.addListener(event, listener); 41 | } 42 | 43 | @Override public final void removeListener(@NonNull Listener listener) { 44 | base.removeListener(listener); 45 | } 46 | 47 | @Override @CallSuper protected void onCreate(Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | base.onCreate(savedInstanceState); 50 | } 51 | 52 | @Override @CallSuper public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) { 53 | super.onCreate(savedInstanceState, persistentState); 54 | base.onCreate(savedInstanceState, persistentState); 55 | } 56 | 57 | @Override @CallSuper protected void onStart() { 58 | super.onStart(); 59 | base.onStart(); 60 | } 61 | 62 | @Override @CallSuper protected void onPostCreate(Bundle savedInstanceState) { 63 | super.onPostCreate(savedInstanceState); 64 | base.onPostCreate(savedInstanceState); 65 | } 66 | 67 | @Override @CallSuper public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) { 68 | super.onPostCreate(savedInstanceState, persistentState); 69 | base.onPostCreate(savedInstanceState, persistentState); 70 | } 71 | 72 | @Override @CallSuper protected void onResume() { 73 | super.onResume(); 74 | base.onResume(); 75 | } 76 | 77 | @Override @CallSuper protected void onPause() { 78 | base.onPause(); 79 | super.onPause(); 80 | } 81 | 82 | @Override @CallSuper protected void onStop() { 83 | base.onStop(); 84 | super.onStop(); 85 | } 86 | 87 | @Override @CallSuper protected void onDestroy() { 88 | base.onDestroy(); 89 | super.onDestroy(); 90 | } 91 | 92 | @Override @CallSuper protected void onRestart() { 93 | super.onRestart(); 94 | base.onRestart(); 95 | } 96 | 97 | @Override @CallSuper protected void onSaveInstanceState(Bundle outState) { 98 | super.onSaveInstanceState(outState); 99 | base.onSaveInstanceState(outState); 100 | } 101 | 102 | @Override @CallSuper public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { 103 | super.onSaveInstanceState(outState, outPersistentState); 104 | base.onSaveInstanceState(outState, outPersistentState); 105 | } 106 | 107 | @Override @CallSuper protected void onRestoreInstanceState(Bundle savedInstanceState) { 108 | super.onRestoreInstanceState(savedInstanceState); 109 | base.onRestoreInstanceState(savedInstanceState); 110 | } 111 | 112 | @Override @CallSuper public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) { 113 | super.onRestoreInstanceState(savedInstanceState, persistentState); 114 | base.onRestoreInstanceState(savedInstanceState, persistentState); 115 | } 116 | 117 | @Override @CallSuper protected void onNewIntent(Intent intent) { 118 | super.onNewIntent(intent); 119 | base.onNewIntent(intent); 120 | } 121 | 122 | @Override @CallSuper public void onBackPressed() { 123 | super.onBackPressed(); 124 | base.onBackPressed(); 125 | } 126 | 127 | @Override @CallSuper public void onAttachedToWindow() { 128 | super.onAttachedToWindow(); 129 | base.onAttachedToWindow(); 130 | } 131 | 132 | @Override @CallSuper public void onDetachedFromWindow() { 133 | super.onDetachedFromWindow(); 134 | base.onDetachedFromWindow(); 135 | } 136 | 137 | @Override @CallSuper public void onConfigurationChanged(Configuration newConfig) { 138 | super.onConfigurationChanged(newConfig); 139 | base.onConfigurationChanged(newConfig); 140 | } 141 | 142 | @Override @CallSuper protected void onActivityResult(int requestCode, int resultCode, Intent data) { 143 | super.onActivityResult(requestCode, resultCode, data); 144 | base.onActivityResult(requestCode, resultCode, data); 145 | } 146 | 147 | @Override @CallSuper public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 148 | @NonNull int[] grantResults) { 149 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 150 | base.onRequestPermissionsResult(requestCode, permissions, grantResults); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/component/support/NaviAppCompatActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.component.support; 16 | 17 | import android.content.Intent; 18 | import android.content.res.Configuration; 19 | import android.os.Bundle; 20 | import android.os.PersistableBundle; 21 | 22 | import com.trello.navi2.Event; 23 | import com.trello.navi2.Listener; 24 | import com.trello.navi2.NaviComponent; 25 | import com.trello.navi2.internal.NaviEmitter; 26 | 27 | import androidx.annotation.CallSuper; 28 | import androidx.annotation.NonNull; 29 | import androidx.annotation.Nullable; 30 | import androidx.appcompat.app.AppCompatActivity; 31 | 32 | public abstract class NaviAppCompatActivity extends AppCompatActivity implements NaviComponent { 33 | 34 | private final NaviEmitter base = NaviEmitter.createActivityEmitter(); 35 | 36 | @Override public final boolean handlesEvents(Event... events) { 37 | return base.handlesEvents(events); 38 | } 39 | 40 | @Override public final void addListener(@NonNull Event event, @NonNull Listener listener) { 41 | base.addListener(event, listener); 42 | } 43 | 44 | @Override public final void removeListener(@NonNull Listener listener) { 45 | base.removeListener(listener); 46 | } 47 | 48 | @Override @CallSuper protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | base.onCreate(savedInstanceState); 51 | } 52 | 53 | @Override @CallSuper public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) { 54 | super.onCreate(savedInstanceState, persistentState); 55 | base.onCreate(savedInstanceState, persistentState); 56 | } 57 | 58 | @Override @CallSuper protected void onStart() { 59 | super.onStart(); 60 | base.onStart(); 61 | } 62 | 63 | @Override @CallSuper protected void onPostCreate(@Nullable Bundle savedInstanceState) { 64 | super.onPostCreate(savedInstanceState); 65 | base.onPostCreate(savedInstanceState); 66 | } 67 | 68 | @Override @CallSuper public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) { 69 | super.onPostCreate(savedInstanceState, persistentState); 70 | base.onPostCreate(savedInstanceState, persistentState); 71 | } 72 | 73 | @Override @CallSuper protected void onResume() { 74 | super.onResume(); 75 | base.onResume(); 76 | } 77 | 78 | @Override @CallSuper protected void onPause() { 79 | base.onPause(); 80 | super.onPause(); 81 | } 82 | 83 | @Override @CallSuper protected void onStop() { 84 | base.onStop(); 85 | super.onStop(); 86 | } 87 | 88 | @Override @CallSuper protected void onDestroy() { 89 | base.onDestroy(); 90 | super.onDestroy(); 91 | } 92 | 93 | @Override @CallSuper protected void onRestart() { 94 | super.onRestart(); 95 | base.onRestart(); 96 | } 97 | 98 | @Override @CallSuper protected void onSaveInstanceState(Bundle outState) { 99 | super.onSaveInstanceState(outState); 100 | base.onSaveInstanceState(outState); 101 | } 102 | 103 | @Override @CallSuper public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { 104 | super.onSaveInstanceState(outState, outPersistentState); 105 | base.onSaveInstanceState(outState, outPersistentState); 106 | } 107 | 108 | @Override @CallSuper protected void onRestoreInstanceState(Bundle savedInstanceState) { 109 | super.onRestoreInstanceState(savedInstanceState); 110 | base.onRestoreInstanceState(savedInstanceState); 111 | } 112 | 113 | @Override @CallSuper public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) { 114 | super.onRestoreInstanceState(savedInstanceState, persistentState); 115 | base.onRestoreInstanceState(savedInstanceState, persistentState); 116 | } 117 | 118 | @Override @CallSuper protected void onNewIntent(Intent intent) { 119 | super.onNewIntent(intent); 120 | base.onNewIntent(intent); 121 | } 122 | 123 | @Override @CallSuper public void onBackPressed() { 124 | super.onBackPressed(); 125 | base.onBackPressed(); 126 | } 127 | 128 | @Override @CallSuper public void onAttachedToWindow() { 129 | super.onAttachedToWindow(); 130 | base.onAttachedToWindow(); 131 | } 132 | 133 | @Override @CallSuper public void onDetachedFromWindow() { 134 | super.onDetachedFromWindow(); 135 | base.onDetachedFromWindow(); 136 | } 137 | 138 | @Override @CallSuper public void onConfigurationChanged(Configuration newConfig) { 139 | super.onConfigurationChanged(newConfig); 140 | base.onConfigurationChanged(newConfig); 141 | } 142 | 143 | @Override @CallSuper protected void onActivityResult(int requestCode, int resultCode, Intent data) { 144 | super.onActivityResult(requestCode, resultCode, data); 145 | base.onActivityResult(requestCode, resultCode, data); 146 | } 147 | 148 | @Override @CallSuper public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 149 | @NonNull int[] grantResults) { 150 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 151 | base.onRequestPermissionsResult(requestCode, permissions, grantResults); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/ConcurrencyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import com.trello.navi2.Event.Type; 18 | import com.trello.navi2.internal.NaviEmitter; 19 | 20 | import org.junit.Test; 21 | 22 | import androidx.annotation.NonNull; 23 | 24 | import static org.mockito.ArgumentMatchers.any; 25 | import static org.mockito.Mockito.mock; 26 | import static org.mockito.Mockito.spy; 27 | import static org.mockito.Mockito.verify; 28 | import static org.mockito.Mockito.verifyZeroInteractions; 29 | 30 | public final class ConcurrencyTest { 31 | 32 | private final NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 33 | 34 | // Verify that we can handle a listener removing itself due to an event occurring 35 | @Test public void handleInnerRemovals() { 36 | final Listener listener1 = spy(new Listener() { 37 | @Override public void call(@NonNull Object __) { 38 | emitter.removeListener(this); 39 | } 40 | }); 41 | final Listener listener2 = spy(new Listener() { 42 | @Override public void call(@NonNull Object __) { 43 | emitter.removeListener(this); 44 | } 45 | }); 46 | 47 | emitter.addListener(Event.RESUME, listener1); 48 | emitter.addListener(Event.RESUME, listener2); 49 | emitter.onResume(); 50 | verify(listener1).call(any()); 51 | verify(listener2).call(any()); 52 | } 53 | 54 | // Verify that listeners added while emitting an item do not also get the current emission 55 | // (since they were not registered at the time of the event). 56 | @Test public void addDuringEmit() { 57 | final Listener addedDuringEmit = mock(Listener.class); 58 | final Listener listener = spy(new Listener() { 59 | @Override public void call(@NonNull Object __) { 60 | emitter.addListener(Event.RESUME, addedDuringEmit); 61 | } 62 | }); 63 | 64 | emitter.addListener(Event.RESUME, listener); 65 | emitter.onResume(); 66 | 67 | verify(listener).call(any()); 68 | verifyZeroInteractions(addedDuringEmit); 69 | } 70 | 71 | // Verify that adding an ALL listener during emission 72 | // doesn't cause it to get the current emission 73 | @Test public void addAllDuringEmit() { 74 | final Listener addedDuringEmit = mock(Listener.class); 75 | final Listener listener = spy(new Listener() { 76 | @Override public void call(@NonNull Object aVoid) { 77 | emitter.addListener(Event.ALL, addedDuringEmit); 78 | } 79 | }); 80 | 81 | emitter.addListener(Event.RESUME, listener); 82 | emitter.onResume(); 83 | 84 | verify(listener).call(any()); 85 | verifyZeroInteractions(addedDuringEmit); 86 | } 87 | 88 | // Verify that adding a listener during an ALL emission 89 | // doesn't cause it to get the current emission 90 | @Test public void addDuringEmitAll() { 91 | final Listener addedDuringEmit = mock(Listener.class); 92 | final Listener listener = spy(new Listener() { 93 | @Override public void call(@NonNull Type type) { 94 | emitter.addListener(Event.RESUME, addedDuringEmit); 95 | } 96 | }); 97 | 98 | emitter.addListener(Event.ALL, listener); 99 | emitter.onResume(); 100 | 101 | verify(listener).call(Type.RESUME); 102 | verifyZeroInteractions(addedDuringEmit); 103 | } 104 | 105 | // Verify that listeners removed while emitting an event still receive it (since they were 106 | // registered at the time of the event). 107 | @Test public void removeDuringEmit() { 108 | final Listener removedDuringEmit = mock(Listener.class); 109 | final Listener listener = spy(new Listener() { 110 | @Override public void call(@NonNull Object __) { 111 | emitter.removeListener(removedDuringEmit); 112 | } 113 | }); 114 | 115 | emitter.addListener(Event.RESUME, listener); 116 | emitter.addListener(Event.RESUME, removedDuringEmit); 117 | emitter.onResume(); 118 | 119 | verify(listener).call(any()); 120 | verify(removedDuringEmit).call(any()); 121 | } 122 | 123 | // Verify that removing an ALL listener during emission 124 | // doesn't cause it to lose the current emission 125 | @Test public void removeAllDuringEmit() { 126 | final Listener removedDuringEmit = mock(Listener.class); 127 | final Listener listener = spy(new Listener() { 128 | @Override public void call(@NonNull Object __) { 129 | emitter.removeListener(removedDuringEmit); 130 | } 131 | }); 132 | 133 | emitter.addListener(Event.RESUME, listener); 134 | emitter.addListener(Event.ALL, removedDuringEmit); 135 | emitter.onResume(); 136 | 137 | verify(listener).call(any()); 138 | verify(removedDuringEmit).call(Type.RESUME); 139 | } 140 | 141 | // Verify that removing a listener during an ALL emission 142 | // doesn't cause it to lose the current emission 143 | @Test public void removeDuringEmitAll() { 144 | final Listener removedDuringEmit = mock(Listener.class); 145 | final Listener listener = spy(new Listener() { 146 | @Override public void call(@NonNull Type type) { 147 | emitter.removeListener(removedDuringEmit); 148 | } 149 | }); 150 | 151 | emitter.addListener(Event.ALL, listener); 152 | emitter.addListener(Event.RESUME, removedDuringEmit); 153 | emitter.onResume(); 154 | 155 | verify(listener).call(Type.RESUME); 156 | verify(removedDuringEmit).call(any()); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/rx/RxNaviFragmentTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.rx; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.content.res.Configuration; 21 | import android.os.Bundle; 22 | import com.trello.navi2.Event; 23 | import com.trello.navi2.internal.NaviEmitter; 24 | import com.trello.navi2.model.ActivityResult; 25 | import com.trello.navi2.model.RequestPermissionsResult; 26 | import io.reactivex.observers.TestObserver; 27 | import org.junit.Test; 28 | 29 | import static com.trello.navi2.TestUtils.setSdkInt; 30 | import static org.mockito.Mockito.mock; 31 | 32 | public final class RxNaviFragmentTest { 33 | 34 | private final NaviEmitter emitter = NaviEmitter.createFragmentEmitter(); 35 | 36 | @Test public void observeAttach() { 37 | setSdkInt(21); 38 | 39 | TestObserver testObserver = RxNavi.observe(emitter, Event.ATTACH).test(); 40 | testObserver.assertNoValues(); 41 | 42 | Activity activity = mock(Activity.class); 43 | emitter.onAttach(activity); 44 | testObserver.dispose(); 45 | emitter.onAttach(activity); 46 | 47 | testObserver.assertValue(activity); 48 | testObserver.assertNotTerminated(); 49 | } 50 | 51 | @Test public void observeAttachApi23() { 52 | setSdkInt(23); 53 | 54 | TestObserver testObserver = RxNavi.observe(emitter, Event.ATTACH).test(); 55 | testObserver.assertNoValues(); 56 | 57 | Context context = mock(Context.class); 58 | emitter.onAttach(context); 59 | testObserver.dispose(); 60 | emitter.onAttach(context); 61 | 62 | testObserver.assertValue(context); 63 | testObserver.assertNotTerminated(); 64 | } 65 | 66 | @Test public void observeCreate() { 67 | TestObserver testObserver = RxNavi.observe(emitter, Event.CREATE).test(); 68 | testObserver.assertNoValues(); 69 | 70 | Bundle bundle = new Bundle(); 71 | emitter.onCreate(bundle); 72 | testObserver.dispose(); 73 | emitter.onCreate(bundle); 74 | 75 | testObserver.assertValue(bundle); 76 | testObserver.assertNotTerminated(); 77 | } 78 | 79 | @Test public void observeCreateView() { 80 | TestObserver testObserver = RxNavi.observe(emitter, Event.CREATE_VIEW).test(); 81 | testObserver.assertNoValues(); 82 | 83 | Bundle bundle = new Bundle(); 84 | emitter.onCreateView(bundle); 85 | testObserver.dispose(); 86 | emitter.onCreateView(bundle); 87 | 88 | testObserver.assertValue(bundle); 89 | testObserver.assertNotTerminated(); 90 | } 91 | 92 | @Test public void observeActivityCreated() { 93 | TestObserver testObserver = RxNavi.observe(emitter, Event.ACTIVITY_CREATED).test(); 94 | testObserver.assertNoValues(); 95 | 96 | Bundle bundle = new Bundle(); 97 | emitter.onActivityCreated(bundle); 98 | testObserver.dispose(); 99 | emitter.onActivityCreated(bundle); 100 | 101 | testObserver.assertValue(bundle); 102 | testObserver.assertNotTerminated(); 103 | } 104 | 105 | @Test public void observeViewStateRestored() { 106 | TestObserver testObserver = RxNavi.observe(emitter, Event.VIEW_STATE_RESTORED).test(); 107 | testObserver.assertNoValues(); 108 | 109 | Bundle bundle = new Bundle(); 110 | emitter.onViewStateRestored(bundle); 111 | testObserver.dispose(); 112 | emitter.onViewStateRestored(bundle); 113 | 114 | testObserver.assertValue(bundle); 115 | testObserver.assertNotTerminated(); 116 | } 117 | 118 | @Test public void observeStart() { 119 | TestObserver testObserver = RxNavi.observe(emitter, Event.START).test(); 120 | testObserver.assertNoValues(); 121 | 122 | emitter.onStart(); 123 | testObserver.dispose(); 124 | emitter.onStart(); 125 | 126 | testObserver.assertValueCount(1); 127 | testObserver.assertNotTerminated(); 128 | } 129 | 130 | @Test public void observeResume() { 131 | TestObserver testObserver = RxNavi.observe(emitter, Event.RESUME).test(); 132 | testObserver.assertNoValues(); 133 | 134 | emitter.onResume(); 135 | testObserver.dispose(); 136 | emitter.onResume(); 137 | 138 | testObserver.assertValueCount(1); 139 | testObserver.assertNotTerminated(); 140 | } 141 | 142 | @Test public void observePause() { 143 | TestObserver testObserver = RxNavi.observe(emitter, Event.PAUSE).test(); 144 | testObserver.assertNoValues(); 145 | 146 | emitter.onPause(); 147 | testObserver.dispose(); 148 | emitter.onPause(); 149 | 150 | testObserver.assertValueCount(1); 151 | testObserver.assertNotTerminated(); 152 | } 153 | 154 | @Test public void observeStop() { 155 | TestObserver testObserver = RxNavi.observe(emitter, Event.STOP).test(); 156 | testObserver.assertNoValues(); 157 | 158 | emitter.onStop(); 159 | testObserver.dispose(); 160 | emitter.onStop(); 161 | 162 | testObserver.assertValueCount(1); 163 | testObserver.assertNotTerminated(); 164 | } 165 | 166 | @Test public void observeDestroyView() { 167 | TestObserver testObserver = RxNavi.observe(emitter, Event.DESTROY_VIEW).test(); 168 | testObserver.assertNoValues(); 169 | 170 | emitter.onDestroyView(); 171 | testObserver.dispose(); 172 | emitter.onDestroyView(); 173 | 174 | testObserver.assertValueCount(1); 175 | testObserver.assertNotTerminated(); 176 | } 177 | 178 | @Test public void observeDestroy() { 179 | TestObserver testObserver = RxNavi.observe(emitter, Event.DESTROY).test(); 180 | testObserver.assertNoValues(); 181 | 182 | emitter.onDestroy(); 183 | testObserver.dispose(); 184 | emitter.onDestroy(); 185 | 186 | testObserver.assertValueCount(1); 187 | testObserver.assertNotTerminated(); 188 | } 189 | 190 | @Test public void observeDetach() { 191 | TestObserver testObserver = RxNavi.observe(emitter, Event.DETACH).test(); 192 | testObserver.assertNoValues(); 193 | 194 | emitter.onDetach(); 195 | testObserver.dispose(); 196 | emitter.onDetach(); 197 | 198 | testObserver.assertValueCount(1); 199 | testObserver.assertNotTerminated(); 200 | } 201 | 202 | @Test public void observeSaveInstanceState() { 203 | TestObserver testObserver = RxNavi.observe(emitter, Event.SAVE_INSTANCE_STATE).test(); 204 | testObserver.assertNoValues(); 205 | 206 | Bundle bundle = new Bundle(); 207 | emitter.onSaveInstanceState(bundle); 208 | testObserver.dispose(); 209 | emitter.onSaveInstanceState(bundle); 210 | 211 | testObserver.assertValue(bundle); 212 | testObserver.assertNotTerminated(); 213 | } 214 | 215 | @Test public void observeConfigurationChanged() { 216 | TestObserver testObserver = 217 | RxNavi.observe(emitter, Event.CONFIGURATION_CHANGED).test(); 218 | testObserver.assertNoValues(); 219 | 220 | Configuration configuration = mock(Configuration.class); 221 | emitter.onConfigurationChanged(configuration); 222 | testObserver.dispose(); 223 | emitter.onConfigurationChanged(configuration); 224 | 225 | testObserver.assertValue(configuration); 226 | testObserver.assertNotTerminated(); 227 | } 228 | 229 | @Test public void observeActivityResult() { 230 | TestObserver testObserver = 231 | RxNavi.observe(emitter, Event.ACTIVITY_RESULT).test(); 232 | testObserver.assertNoValues(); 233 | 234 | int requestCode = 1; 235 | int resultCode = Activity.RESULT_OK; 236 | Intent data = new Intent(); 237 | emitter.onActivityResult(requestCode, resultCode, data); 238 | testObserver.dispose(); 239 | emitter.onActivityResult(requestCode, resultCode, data); 240 | 241 | testObserver.assertValue(ActivityResult.create(requestCode, resultCode, data)); 242 | testObserver.assertNotTerminated(); 243 | } 244 | 245 | @Test public void observeRequestPermissionsResult() { 246 | TestObserver testObserver = 247 | RxNavi.observe(emitter, Event.REQUEST_PERMISSIONS_RESULT).test(); 248 | testObserver.assertNoValues(); 249 | 250 | int requestCode = 1; 251 | String[] permissions = new String[0]; 252 | int[] grantResults = new int[0]; 253 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 254 | testObserver.dispose(); 255 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 256 | 257 | testObserver.assertValue( 258 | RequestPermissionsResult.create(requestCode, permissions, grantResults)); 259 | testObserver.assertNotTerminated(); 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/internal/NaviEmitter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.internal; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.content.res.Configuration; 21 | import android.os.Build; 22 | import android.os.Bundle; 23 | import android.os.PersistableBundle; 24 | import android.view.View; 25 | 26 | import com.trello.navi2.Event; 27 | import com.trello.navi2.Event.Type; 28 | import com.trello.navi2.Listener; 29 | import com.trello.navi2.NaviComponent; 30 | import com.trello.navi2.model.ActivityResult; 31 | import com.trello.navi2.model.BundleBundle; 32 | import com.trello.navi2.model.RequestPermissionsResult; 33 | import com.trello.navi2.model.ViewCreated; 34 | 35 | import java.util.Collection; 36 | import java.util.Collections; 37 | import java.util.HashSet; 38 | import java.util.Iterator; 39 | import java.util.List; 40 | import java.util.Map; 41 | import java.util.Set; 42 | import java.util.concurrent.ConcurrentHashMap; 43 | import java.util.concurrent.CopyOnWriteArrayList; 44 | 45 | import androidx.annotation.NonNull; 46 | import androidx.annotation.Nullable; 47 | 48 | import static com.trello.navi2.internal.Constants.SIGNAL; 49 | 50 | /** 51 | * Emitter of Navi events which contains all the actual logic 52 | * 53 | * This makes it easier to port {@link NaviComponent} to Activities and Fragments 54 | * without duplicating quite as much code. 55 | */ 56 | public final class NaviEmitter implements NaviComponent { 57 | 58 | private final Set> handledEvents; 59 | 60 | private final Map, List> listenerMap; 61 | 62 | // Only used for fast removal of listeners 63 | private final Map> eventMap; 64 | 65 | public NaviEmitter(@NonNull Collection> handledEvents) { 66 | this.handledEvents = Collections.unmodifiableSet(new HashSet<>(handledEvents)); 67 | this.listenerMap = new ConcurrentHashMap<>(); 68 | this.eventMap = new ConcurrentHashMap<>(); 69 | } 70 | 71 | public static NaviEmitter createActivityEmitter() { 72 | return new NaviEmitter(HandledEvents.ACTIVITY_EVENTS); 73 | } 74 | 75 | public static NaviEmitter createFragmentEmitter() { 76 | return new NaviEmitter(HandledEvents.FRAGMENT_EVENTS); 77 | } 78 | 79 | @Override public final boolean handlesEvents(Event... events) { 80 | for (int a = 0; a < events.length; a++) { 81 | Event event = events[a]; 82 | if (event != Event.ALL && !handledEvents.contains(event)) { 83 | return false; 84 | } 85 | } 86 | 87 | return true; 88 | } 89 | 90 | @Override 91 | public final void addListener(@NonNull Event event, @NonNull Listener listener) { 92 | if (!handlesEvents(event)) { 93 | throw new IllegalArgumentException("This component cannot handle event " + event); 94 | } 95 | 96 | // Check that we're not adding the same listener in multiple places 97 | // For the same event, it's idempotent; for different events, it's an error 98 | if (eventMap.containsKey(listener)) { 99 | final Event otherEvent = eventMap.get(listener); 100 | if (!event.equals(otherEvent)) { 101 | throw new IllegalStateException( 102 | "Cannot use the same listener for two events! e1: " + event + " e2: " + otherEvent); 103 | } 104 | return; 105 | } 106 | 107 | eventMap.put(listener, event); 108 | 109 | if (!listenerMap.containsKey(event)) { 110 | listenerMap.put(event, new CopyOnWriteArrayList()); 111 | } 112 | 113 | List listeners = listenerMap.get(event); 114 | listeners.add(listener); 115 | } 116 | 117 | @Override public final void removeListener(@NonNull Listener listener) { 118 | final Event event = eventMap.remove(listener); 119 | if (event != null && listenerMap.containsKey(event)) { 120 | listenerMap.get(event).remove(listener); 121 | } 122 | } 123 | 124 | private void emitEvent(@NonNull Event event) { 125 | emitEvent(event, SIGNAL); 126 | } 127 | 128 | private void emitEvent(@NonNull Event event, @NonNull T data) { 129 | // We gather listener iterators all at once so adding/removing listeners during emission 130 | // doesn't change the listener list. 131 | final List listeners = listenerMap.get(event); 132 | final Iterator listenersIterator = 133 | listeners != null ? listeners.listIterator() : null; 134 | 135 | final List allListeners = listenerMap.get(Event.ALL); 136 | final Iterator allListenersIterator = 137 | allListeners != null ? allListeners.iterator() : null; 138 | 139 | if (allListenersIterator != null) { 140 | final Type type = event.type(); 141 | while (allListenersIterator.hasNext()) { 142 | allListenersIterator.next().call(type); 143 | } 144 | } 145 | 146 | if (listeners != null) { 147 | while (listenersIterator.hasNext()) { 148 | listenersIterator.next().call(data); 149 | } 150 | } 151 | } 152 | 153 | //////////////////////////////////////////////////////////////////////////// 154 | // Events 155 | 156 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 157 | emitEvent(Event.ACTIVITY_CREATED, 158 | savedInstanceState != null ? savedInstanceState : new Bundle()); 159 | } 160 | 161 | public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 162 | emitEvent(Event.ACTIVITY_RESULT, ActivityResult.create(requestCode, resultCode, data)); 163 | } 164 | 165 | public void onAttach(@NonNull Activity activity) { 166 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 167 | emitEvent(Event.ATTACH, activity); 168 | } 169 | } 170 | 171 | public void onAttach(@NonNull Context context) { 172 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 173 | emitEvent(Event.ATTACH, context); 174 | } 175 | } 176 | 177 | public void onAttachedToWindow() { 178 | emitEvent(Event.ATTACHED_TO_WINDOW); 179 | } 180 | 181 | public void onBackPressed() { 182 | emitEvent(Event.BACK_PRESSED); 183 | } 184 | 185 | public void onConfigurationChanged(@NonNull Configuration newConfig) { 186 | emitEvent(Event.CONFIGURATION_CHANGED, newConfig); 187 | } 188 | 189 | public void onCreate(@Nullable Bundle savedInstanceState) { 190 | emitEvent(Event.CREATE, savedInstanceState != null ? savedInstanceState : new Bundle()); 191 | } 192 | 193 | public void onCreate(@Nullable Bundle savedInstanceState, 194 | @Nullable PersistableBundle persistentState) { 195 | emitEvent(Event.CREATE_PERSISTABLE, BundleBundle.create(savedInstanceState, persistentState)); 196 | } 197 | 198 | public void onCreateView(@Nullable Bundle savedInstanceState) { 199 | emitEvent(Event.CREATE_VIEW, savedInstanceState != null ? savedInstanceState : new Bundle()); 200 | } 201 | 202 | public void onViewCreated(@NonNull View view, @Nullable Bundle bundle) { 203 | emitEvent(Event.VIEW_CREATED, ViewCreated.create(view, bundle)); 204 | } 205 | 206 | public void onDestroy() { 207 | emitEvent(Event.DESTROY); 208 | } 209 | 210 | public void onDestroyView() { 211 | emitEvent(Event.DESTROY_VIEW); 212 | } 213 | 214 | public void onDetach() { 215 | emitEvent(Event.DETACH); 216 | } 217 | 218 | public void onDetachedFromWindow() { 219 | emitEvent(Event.DETACHED_FROM_WINDOW); 220 | } 221 | 222 | public void onNewIntent(@NonNull Intent intent) { 223 | emitEvent(Event.NEW_INTENT, intent); 224 | } 225 | 226 | public void onPause() { 227 | emitEvent(Event.PAUSE); 228 | } 229 | 230 | public void onPostCreate(@Nullable Bundle savedInstanceState) { 231 | emitEvent(Event.POST_CREATE, savedInstanceState != null ? savedInstanceState : new Bundle()); 232 | } 233 | 234 | public void onPostCreate(@Nullable Bundle savedInstanceState, 235 | @Nullable PersistableBundle persistentState) { 236 | emitEvent(Event.POST_CREATE_PERSISTABLE, 237 | BundleBundle.create(savedInstanceState, persistentState)); 238 | } 239 | 240 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 241 | @NonNull int[] grantResults) { 242 | emitEvent(Event.REQUEST_PERMISSIONS_RESULT, 243 | RequestPermissionsResult.create(requestCode, permissions, grantResults)); 244 | } 245 | 246 | public void onRestart() { 247 | emitEvent(Event.RESTART); 248 | } 249 | 250 | public void onRestoreInstanceState(@Nullable Bundle savedInstanceState) { 251 | emitEvent(Event.RESTORE_INSTANCE_STATE, 252 | savedInstanceState != null ? savedInstanceState : new Bundle()); 253 | } 254 | 255 | public void onRestoreInstanceState(@Nullable Bundle savedInstanceState, 256 | @Nullable PersistableBundle persistentState) { 257 | emitEvent(Event.RESTORE_INSTANCE_STATE_PERSISTABLE, 258 | BundleBundle.create(savedInstanceState, persistentState)); 259 | } 260 | 261 | public void onResume() { 262 | emitEvent(Event.RESUME); 263 | } 264 | 265 | public void onSaveInstanceState(@NonNull Bundle outState) { 266 | emitEvent(Event.SAVE_INSTANCE_STATE, outState); 267 | } 268 | 269 | public void onSaveInstanceState(@NonNull Bundle outState, 270 | @NonNull PersistableBundle outPersistentState) { 271 | emitEvent(Event.SAVE_INSTANCE_STATE_PERSISTABLE, 272 | BundleBundle.create(outState, outPersistentState)); 273 | } 274 | 275 | public void onStart() { 276 | emitEvent(Event.START); 277 | } 278 | 279 | public void onStop() { 280 | emitEvent(Event.STOP); 281 | } 282 | 283 | public void onViewStateRestored(@Nullable Bundle savedInstanceState) { 284 | emitEvent(Event.VIEW_STATE_RESTORED, 285 | savedInstanceState != null ? savedInstanceState : new Bundle()); 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /navi/src/main/java/com/trello/navi2/Event.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import android.app.Activity; 18 | import android.app.Fragment; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.content.res.Configuration; 22 | import android.os.Bundle; 23 | import android.os.PersistableBundle; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | import android.view.ViewGroup; 27 | 28 | import com.trello.navi2.model.ActivityResult; 29 | import com.trello.navi2.model.BundleBundle; 30 | import com.trello.navi2.model.RequestPermissionsResult; 31 | import com.trello.navi2.model.ViewCreated; 32 | 33 | import androidx.annotation.NonNull; 34 | 35 | /** 36 | * Represents an event that can be listened to in an Activity or Fragment. 37 | * 38 | * Comes with a set of predefined events. 39 | * 40 | * Events will vary in their timing in relation to the normally-required super() call. Generally, 41 | * component creation ({@code onCreate()}, {@code onStart()}, etc.) is emitted *after* 42 | * their super calls are made. Component destruction ({@code onPause()}, {@code onStop()}, etc.) 43 | * are called *before* their super calls are made. Events that are neither are called *after* 44 | * their super calls. 45 | * 46 | * @param the callback type for the event. If Object, then the value is just a signal and has 47 | * no contents. 48 | */ 49 | public final class Event { 50 | 51 | /** 52 | * Emits all events (though without any extra data). 53 | */ 54 | public static final Event ALL = new Event<>(Type.ALL, Type.class); 55 | 56 | /** 57 | * Emits {@link Activity#onCreate(Bundle)} and {@link Fragment#onCreate(Bundle)}. Emitted after 58 | * super(). 59 | */ 60 | public static final Event CREATE = new Event<>(Type.CREATE, Bundle.class); 61 | 62 | /** 63 | * Emits {@link Activity#onCreate(Bundle, PersistableBundle)}. Emitted after super(). 64 | */ 65 | public static final Event CREATE_PERSISTABLE = 66 | new Event<>(Type.CREATE_PERSISTABLE, BundleBundle.class); 67 | 68 | /** 69 | * Emits {@link Activity#onStart()} and {@link Fragment#onStart()}. Emitted after super(). 70 | */ 71 | public static final Event START = new Event<>(Type.START, Object.class); 72 | 73 | /** 74 | * Emits {@link Activity#onPostCreate(Bundle)}. Emitted after super(). 75 | */ 76 | public static final Event POST_CREATE = new Event<>(Type.POST_CREATE, Bundle.class); 77 | 78 | /** 79 | * Emits {@link Activity#onCreate(Bundle, PersistableBundle)}. Emitted after super(). 80 | */ 81 | public static final Event POST_CREATE_PERSISTABLE = 82 | new Event<>(Type.POST_CREATE_PERSISTABLE, BundleBundle.class); 83 | 84 | /** 85 | * Emits {@link Activity#onResume()} and {@link Fragment#onResume()}. Emitted after super(). 86 | */ 87 | public static final Event RESUME = new Event<>(Type.RESUME, Object.class); 88 | 89 | /** 90 | * Emits {@link Activity#onPause()} and {@link Fragment#onPause()}. Emitted before super(). 91 | */ 92 | public static final Event PAUSE = new Event<>(Type.PAUSE, Object.class); 93 | 94 | /** 95 | * Emits {@link Activity#onStop()} and {@link Fragment#onStop()}. Emitted before super(). 96 | */ 97 | public static final Event STOP = new Event<>(Type.STOP, Object.class); 98 | 99 | /** 100 | * Emits {@link Activity#onDestroy()} and {@link Fragment#onDestroy()}. Emitted before super(). 101 | */ 102 | public static final Event DESTROY = new Event<>(Type.DESTROY, Object.class); 103 | 104 | /** 105 | * Emits {@link Activity#onSaveInstanceState(Bundle)} and 106 | * {@link Fragment#onSaveInstanceState(Bundle)}. Emitted after super(). 107 | */ 108 | public static final Event SAVE_INSTANCE_STATE = 109 | new Event<>(Type.SAVE_INSTANCE_STATE, Bundle.class); 110 | 111 | /** 112 | * Emits {@link Activity#onSaveInstanceState(Bundle, PersistableBundle)}. Emitted after super(). 113 | */ 114 | public static final Event SAVE_INSTANCE_STATE_PERSISTABLE = 115 | new Event<>(Type.SAVE_INSTANCE_STATE_PERSISTABLE, BundleBundle.class); 116 | 117 | /** 118 | * Emits {@link Activity#onConfigurationChanged(Configuration)} and 119 | * {@link Fragment#onConfigurationChanged(Configuration)}. Emitted after super(). 120 | */ 121 | public static final Event CONFIGURATION_CHANGED = 122 | new Event<>(Type.CONFIGURATION_CHANGED, Configuration.class); 123 | 124 | /** 125 | * Emits {@link Activity#onActivityResult(int, int, Intent)} and 126 | * {@link Fragment#onActivityResult(int, int, Intent)}. Emitted after super(). 127 | */ 128 | public static final Event ACTIVITY_RESULT = 129 | new Event<>(Type.ACTIVITY_RESULT, ActivityResult.class); 130 | 131 | /** 132 | * Emits {@link Activity#onRequestPermissionsResult(int, String[], int[])} and 133 | * {@link Fragment#onRequestPermissionsResult(int, String[], int[])}. Emitted after super(). 134 | */ 135 | public static final Event REQUEST_PERMISSIONS_RESULT = 136 | new Event<>(Type.REQUEST_PERMISSIONS_RESULT, RequestPermissionsResult.class); 137 | 138 | /** 139 | * Emits {@link Activity#onRestart()}. Emitted after super(). 140 | */ 141 | public static final Event RESTART = new Event<>(Type.RESTART, Object.class); 142 | 143 | /** 144 | * Emits {@link Activity#onRestoreInstanceState(Bundle)}. Emitted after super(). 145 | */ 146 | public static final Event RESTORE_INSTANCE_STATE = 147 | new Event<>(Type.RESTORE_INSTANCE_STATE, Bundle.class); 148 | 149 | /** 150 | * Emits {@link Activity#onRestoreInstanceState(Bundle, PersistableBundle)}. Emitted after 151 | * super(). 152 | */ 153 | public static final Event RESTORE_INSTANCE_STATE_PERSISTABLE = 154 | new Event<>(Type.RESTORE_INSTANCE_STATE_PERSISTABLE, BundleBundle.class); 155 | 156 | /** 157 | * Emits {@link Activity#onNewIntent(Intent)}. Emitted after super(). 158 | */ 159 | public static final Event NEW_INTENT = new Event<>(Type.NEW_INTENT, Intent.class); 160 | 161 | /** 162 | * Emits {@link Activity#onBackPressed()}. Emitted after super(). 163 | */ 164 | public static final Event BACK_PRESSED = new Event<>(Type.BACK_PRESSED, Object.class); 165 | 166 | /** 167 | * Emits {@link Activity#onAttachedToWindow()}. Emitted after super(). 168 | */ 169 | public static final Event ATTACHED_TO_WINDOW = 170 | new Event<>(Type.ATTACHED_TO_WINDOW, Object.class); 171 | 172 | /** 173 | * Emits {@link Activity#onDetachedFromWindow()}. Emitted after super(). 174 | */ 175 | public static final Event DETACHED_FROM_WINDOW = 176 | new Event<>(Type.DETACHED_FROM_WINDOW, Object.class); 177 | 178 | /** 179 | * Emits {@link Fragment#onAttach(Context)}. Emitted after super(). 180 | */ 181 | public static final Event ATTACH = new Event<>(Type.ATTACH, Context.class); 182 | 183 | /** 184 | * Emits {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}. Emitted after super(). 185 | */ 186 | public static final Event CREATE_VIEW = new Event<>(Type.CREATE_VIEW, Bundle.class); 187 | 188 | /** 189 | * Emits {@link Fragment#onViewCreated(View, Bundle)} ()}. Emitted before super(). 190 | */ 191 | public static final Event VIEW_CREATED = new Event<>(Type.VIEW_CREATED, ViewCreated.class); 192 | 193 | /** 194 | * Emits {@link Fragment#onActivityCreated(Bundle)}. Emitted after super(). 195 | */ 196 | public static final Event ACTIVITY_CREATED = 197 | new Event<>(Type.ACTIVITY_CREATED, Bundle.class); 198 | 199 | /** 200 | * Emits {@link Fragment#onViewStateRestored(Bundle)}. Emitted after super(). 201 | */ 202 | public static final Event VIEW_STATE_RESTORED = 203 | new Event<>(Type.VIEW_STATE_RESTORED, Bundle.class); 204 | 205 | /** 206 | * Emits {@link Fragment#onDestroyView()}. Emitted before super(). 207 | */ 208 | public static final Event DESTROY_VIEW = new Event<>(Type.DESTROY_VIEW, Object.class); 209 | 210 | /** 211 | * Emits {@link Fragment#onDetach()}. Emitted before super(). 212 | */ 213 | public static final Event DETACH = new Event<>(Type.DETACH, Object.class); 214 | 215 | private final Type eventType; 216 | 217 | private final Class callbackType; 218 | 219 | // This is purposefully hidden so that we can control available events 220 | private Event(@NonNull Type eventType, @NonNull Class callbackType) { 221 | this.eventType = eventType; 222 | this.callbackType = callbackType; 223 | } 224 | 225 | public Type type() { 226 | return eventType; 227 | } 228 | 229 | @Override public boolean equals(Object o) { 230 | if (this == o) return true; 231 | if (o == null || getClass() != o.getClass()) return false; 232 | 233 | Event event = (Event) o; 234 | 235 | if (eventType != event.eventType) return false; 236 | return callbackType.equals(event.callbackType); 237 | } 238 | 239 | @Override public int hashCode() { 240 | int result = eventType.hashCode(); 241 | result = 31 * result + callbackType.hashCode(); 242 | return result; 243 | } 244 | 245 | @Override public String toString() { 246 | return "Event{" + 247 | "eventType=" + eventType + 248 | ", callbackType=" + callbackType + 249 | '}'; 250 | } 251 | 252 | public enum Type { 253 | ALL, 254 | 255 | // Shared 256 | CREATE, 257 | START, 258 | RESUME, 259 | PAUSE, 260 | STOP, 261 | DESTROY, 262 | SAVE_INSTANCE_STATE, 263 | CONFIGURATION_CHANGED, 264 | ACTIVITY_RESULT, 265 | REQUEST_PERMISSIONS_RESULT, 266 | 267 | // Activity-only 268 | CREATE_PERSISTABLE, 269 | POST_CREATE, 270 | POST_CREATE_PERSISTABLE, 271 | RESTART, 272 | SAVE_INSTANCE_STATE_PERSISTABLE, 273 | RESTORE_INSTANCE_STATE, 274 | RESTORE_INSTANCE_STATE_PERSISTABLE, 275 | NEW_INTENT, 276 | BACK_PRESSED, 277 | ATTACHED_TO_WINDOW, 278 | DETACHED_FROM_WINDOW, 279 | 280 | // Fragment-only 281 | ATTACH, 282 | CREATE_VIEW, 283 | VIEW_CREATED, 284 | ACTIVITY_CREATED, 285 | VIEW_STATE_RESTORED, 286 | DESTROY_VIEW, 287 | DETACH 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/rx/RxNaviActivityTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2.rx; 16 | 17 | import android.app.Activity; 18 | import android.content.Intent; 19 | import android.content.res.Configuration; 20 | import android.os.Bundle; 21 | import android.os.PersistableBundle; 22 | import com.trello.navi2.Event; 23 | import com.trello.navi2.internal.NaviEmitter; 24 | import com.trello.navi2.model.ActivityResult; 25 | import com.trello.navi2.model.BundleBundle; 26 | import com.trello.navi2.model.RequestPermissionsResult; 27 | import io.reactivex.observers.TestObserver; 28 | import org.junit.Test; 29 | 30 | import static org.mockito.Mockito.mock; 31 | 32 | public final class RxNaviActivityTest { 33 | 34 | private final NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 35 | 36 | @Test public void observeCreate() { 37 | TestObserver testObserver = RxNavi.observe(emitter, Event.CREATE).test(); 38 | testObserver.assertNoValues(); 39 | 40 | Bundle bundle = new Bundle(); 41 | emitter.onCreate(bundle); 42 | testObserver.dispose(); 43 | emitter.onCreate(bundle); 44 | 45 | testObserver.assertValue(bundle); 46 | testObserver.assertNotTerminated(); 47 | } 48 | 49 | @Test public void observeCreatePersistable() { 50 | TestObserver testObserver = RxNavi.observe(emitter, Event.CREATE_PERSISTABLE).test(); 51 | testObserver.assertNoValues(); 52 | 53 | Bundle bundle = new Bundle(); 54 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 55 | emitter.onCreate(bundle, persistableBundle); 56 | testObserver.dispose(); 57 | emitter.onCreate(bundle, persistableBundle); 58 | 59 | testObserver.assertValue(BundleBundle.create(bundle, persistableBundle)); 60 | testObserver.assertNotTerminated(); 61 | } 62 | 63 | @Test public void observeStart() { 64 | TestObserver testObserver = RxNavi.observe(emitter, Event.START).test(); 65 | testObserver.assertNoValues(); 66 | 67 | emitter.onStart(); 68 | testObserver.dispose(); 69 | emitter.onStart(); 70 | 71 | testObserver.assertValueCount(1); 72 | testObserver.assertNotTerminated(); 73 | } 74 | 75 | @Test public void observePostCreate() { 76 | TestObserver testObserver = RxNavi.observe(emitter, Event.POST_CREATE).test(); 77 | testObserver.assertNoValues(); 78 | 79 | Bundle bundle = new Bundle(); 80 | emitter.onPostCreate(bundle); 81 | testObserver.dispose(); 82 | emitter.onPostCreate(bundle); 83 | 84 | testObserver.assertValue(bundle); 85 | testObserver.assertNotTerminated(); 86 | } 87 | 88 | @Test public void observePostCreatePersistable() { 89 | TestObserver testObserver = 90 | RxNavi.observe(emitter, Event.POST_CREATE_PERSISTABLE).test(); 91 | testObserver.assertNoValues(); 92 | 93 | Bundle bundle = new Bundle(); 94 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 95 | emitter.onPostCreate(bundle, persistableBundle); 96 | testObserver.dispose(); 97 | emitter.onPostCreate(bundle, persistableBundle); 98 | 99 | testObserver.assertValue(BundleBundle.create(bundle, persistableBundle)); 100 | testObserver.assertNotTerminated(); 101 | } 102 | 103 | @Test public void observeResume() { 104 | TestObserver testObserver = RxNavi.observe(emitter, Event.RESUME).test(); 105 | testObserver.assertNoValues(); 106 | 107 | emitter.onResume(); 108 | testObserver.dispose(); 109 | emitter.onResume(); 110 | 111 | testObserver.assertValueCount(1); 112 | testObserver.assertNotTerminated(); 113 | } 114 | 115 | @Test public void observePause() { 116 | TestObserver testObserver = RxNavi.observe(emitter, Event.PAUSE).test(); 117 | testObserver.assertNoValues(); 118 | 119 | emitter.onPause(); 120 | testObserver.dispose(); 121 | emitter.onPause(); 122 | 123 | testObserver.assertValueCount(1); 124 | testObserver.assertNotTerminated(); 125 | } 126 | 127 | @Test public void observeStop() { 128 | TestObserver testObserver = RxNavi.observe(emitter, Event.STOP).test(); 129 | testObserver.assertNoValues(); 130 | 131 | emitter.onStop(); 132 | testObserver.dispose(); 133 | emitter.onStop(); 134 | 135 | testObserver.assertValueCount(1); 136 | testObserver.assertNotTerminated(); 137 | } 138 | 139 | @Test public void observeDestroy() { 140 | TestObserver testObserver = RxNavi.observe(emitter, Event.DESTROY).test(); 141 | testObserver.assertNoValues(); 142 | 143 | emitter.onDestroy(); 144 | testObserver.dispose(); 145 | emitter.onDestroy(); 146 | 147 | testObserver.assertValueCount(1); 148 | testObserver.assertNotTerminated(); 149 | } 150 | 151 | @Test public void observeRestart() { 152 | TestObserver testObserver = RxNavi.observe(emitter, Event.RESTART).test(); 153 | testObserver.assertNoValues(); 154 | 155 | emitter.onRestart(); 156 | testObserver.dispose(); 157 | emitter.onRestart(); 158 | 159 | testObserver.assertValueCount(1); 160 | testObserver.assertNotTerminated(); 161 | } 162 | 163 | @Test public void observeSaveInstanceState() { 164 | TestObserver testObserver = RxNavi.observe(emitter, Event.SAVE_INSTANCE_STATE).test(); 165 | testObserver.assertNoValues(); 166 | 167 | Bundle bundle = new Bundle(); 168 | emitter.onSaveInstanceState(bundle); 169 | testObserver.dispose(); 170 | emitter.onSaveInstanceState(bundle); 171 | 172 | testObserver.assertValue(bundle); 173 | testObserver.assertNotTerminated(); 174 | } 175 | 176 | @Test public void observeSaveInstanceStatePersistable() { 177 | TestObserver testObserver = 178 | RxNavi.observe(emitter, Event.SAVE_INSTANCE_STATE_PERSISTABLE).test(); 179 | testObserver.assertNoValues(); 180 | 181 | Bundle bundle = new Bundle(); 182 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 183 | emitter.onSaveInstanceState(bundle, persistableBundle); 184 | testObserver.dispose(); 185 | emitter.onSaveInstanceState(bundle, persistableBundle); 186 | 187 | testObserver.assertValue(BundleBundle.create(bundle, persistableBundle)); 188 | testObserver.assertNotTerminated(); 189 | } 190 | 191 | @Test public void observeRestoreInstanceState() { 192 | TestObserver testObserver = RxNavi.observe(emitter, Event.RESTORE_INSTANCE_STATE).test(); 193 | testObserver.assertNoValues(); 194 | 195 | Bundle bundle = new Bundle(); 196 | emitter.onRestoreInstanceState(bundle); 197 | testObserver.dispose(); 198 | emitter.onRestoreInstanceState(bundle); 199 | 200 | testObserver.assertValue(bundle); 201 | testObserver.assertNotTerminated(); 202 | } 203 | 204 | @Test public void observeRestoreInstanceStatePersistable() { 205 | TestObserver testObserver = 206 | RxNavi.observe(emitter, Event.RESTORE_INSTANCE_STATE_PERSISTABLE).test(); 207 | testObserver.assertNoValues(); 208 | 209 | Bundle bundle = new Bundle(); 210 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 211 | emitter.onRestoreInstanceState(bundle, persistableBundle); 212 | testObserver.dispose(); 213 | emitter.onRestoreInstanceState(bundle, persistableBundle); 214 | 215 | testObserver.assertValue(BundleBundle.create(bundle, persistableBundle)); 216 | testObserver.assertNotTerminated(); 217 | } 218 | 219 | @Test public void observeNewIntent() { 220 | TestObserver testObserver = RxNavi.observe(emitter, Event.NEW_INTENT).test(); 221 | testObserver.assertNoValues(); 222 | 223 | Intent intent = new Intent(); 224 | emitter.onNewIntent(intent); 225 | testObserver.dispose(); 226 | emitter.onNewIntent(intent); 227 | 228 | testObserver.assertValue(intent); 229 | testObserver.assertNotTerminated(); 230 | } 231 | 232 | @Test public void observeBackPressed() { 233 | TestObserver testObserver = RxNavi.observe(emitter, Event.BACK_PRESSED).test(); 234 | testObserver.assertNoValues(); 235 | 236 | emitter.onBackPressed(); 237 | testObserver.dispose(); 238 | emitter.onBackPressed(); 239 | 240 | testObserver.assertValueCount(1); 241 | testObserver.assertNotTerminated(); 242 | } 243 | 244 | @Test public void observeAttachedToWindow() { 245 | TestObserver testObserver = RxNavi.observe(emitter, Event.ATTACHED_TO_WINDOW).test(); 246 | testObserver.assertNoValues(); 247 | 248 | emitter.onAttachedToWindow(); 249 | testObserver.dispose(); 250 | emitter.onAttachedToWindow(); 251 | 252 | testObserver.assertValueCount(1); 253 | testObserver.assertNotTerminated(); 254 | } 255 | 256 | @Test public void observeDetachedFromWindow() { 257 | TestObserver testObserver = RxNavi.observe(emitter, Event.DETACHED_FROM_WINDOW).test(); 258 | testObserver.assertNoValues(); 259 | 260 | emitter.onDetachedFromWindow(); 261 | testObserver.dispose(); 262 | emitter.onDetachedFromWindow(); 263 | 264 | testObserver.assertValueCount(1); 265 | testObserver.assertNotTerminated(); 266 | } 267 | 268 | @Test public void observeConfigurationChanged() { 269 | TestObserver testObserver = RxNavi.observe(emitter, Event.CONFIGURATION_CHANGED).test(); 270 | testObserver.assertNoValues(); 271 | 272 | Configuration configuration = mock(Configuration.class); 273 | emitter.onConfigurationChanged(configuration); 274 | testObserver.dispose(); 275 | emitter.onConfigurationChanged(configuration); 276 | 277 | testObserver.assertValue(configuration); 278 | testObserver.assertNotTerminated(); 279 | } 280 | 281 | @Test public void observeActivityResult() { 282 | TestObserver testObserver = RxNavi.observe(emitter, Event.ACTIVITY_RESULT).test(); 283 | testObserver.assertNoValues(); 284 | 285 | int requestCode = 1; 286 | int resultCode = Activity.RESULT_OK; 287 | Intent data = new Intent(); 288 | emitter.onActivityResult(requestCode, resultCode, data); 289 | testObserver.dispose(); 290 | emitter.onActivityResult(requestCode, resultCode, data); 291 | 292 | testObserver.assertValue(ActivityResult.create(requestCode, resultCode, data)); 293 | testObserver.assertNotTerminated(); 294 | } 295 | 296 | @Test public void observeRequestPermissionsResult() { 297 | TestObserver testObserver = 298 | RxNavi.observe(emitter, Event.REQUEST_PERMISSIONS_RESULT).test(); 299 | testObserver.assertNoValues(); 300 | 301 | int requestCode = 1; 302 | String[] permissions = new String[0]; 303 | int[] grantResults = new int[0]; 304 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 305 | testObserver.dispose(); 306 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 307 | 308 | testObserver.assertValue( 309 | RequestPermissionsResult.create(requestCode, permissions, grantResults)); 310 | testObserver.assertNotTerminated(); 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/NaviFragmentTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.content.res.Configuration; 21 | import android.os.Bundle; 22 | import android.view.View; 23 | import com.trello.navi2.internal.NaviEmitter; 24 | import com.trello.navi2.model.ActivityResult; 25 | import com.trello.navi2.model.RequestPermissionsResult; 26 | import com.trello.navi2.model.ViewCreated; 27 | import org.junit.Rule; 28 | import org.junit.Test; 29 | import org.junit.rules.ExpectedException; 30 | 31 | import static com.trello.navi2.TestUtils.setSdkInt; 32 | import static org.mockito.ArgumentMatchers.any; 33 | import static org.mockito.Mockito.mock; 34 | import static org.mockito.Mockito.verify; 35 | import static org.mockito.Mockito.verifyNoMoreInteractions; 36 | 37 | public final class NaviFragmentTest { 38 | 39 | @Rule public final ExpectedException exception = ExpectedException.none(); 40 | 41 | private final NaviEmitter emitter = NaviEmitter.createFragmentEmitter(); 42 | 43 | @Test public void attachListener() { 44 | setSdkInt(21); 45 | 46 | Listener listener = mock(Listener.class); 47 | emitter.addListener(Event.ATTACH, listener); 48 | 49 | Activity activity = mock(Activity.class); 50 | emitter.onAttach(activity); 51 | verify(listener).call(activity); 52 | 53 | emitter.removeListener(listener); 54 | emitter.onAttach(activity); 55 | verifyNoMoreInteractions(listener); 56 | } 57 | 58 | @Test public void attachListenerApi23() { 59 | setSdkInt(23); 60 | 61 | Listener listener = mock(Listener.class); 62 | emitter.addListener(Event.ATTACH, listener); 63 | 64 | Context context = mock(Context.class); 65 | emitter.onAttach(context); 66 | verify(listener).call(context); 67 | 68 | emitter.removeListener(listener); 69 | emitter.onAttach(context); 70 | verifyNoMoreInteractions(listener); 71 | } 72 | 73 | @Test public void createListener() { 74 | Listener listener = mock(Listener.class); 75 | emitter.addListener(Event.CREATE, listener); 76 | 77 | Bundle bundle = new Bundle(); 78 | emitter.onCreate(bundle); 79 | verify(listener).call(bundle); 80 | 81 | emitter.removeListener(listener); 82 | emitter.onCreate(bundle); 83 | verifyNoMoreInteractions(listener); 84 | } 85 | 86 | @Test public void createViewListener() { 87 | Listener listener = mock(Listener.class); 88 | emitter.addListener(Event.CREATE_VIEW, listener); 89 | 90 | Bundle bundle = new Bundle(); 91 | emitter.onCreateView(bundle); 92 | verify(listener).call(bundle); 93 | 94 | emitter.removeListener(listener); 95 | emitter.onCreate(bundle); 96 | verifyNoMoreInteractions(listener); 97 | } 98 | 99 | @Test public void onViewCreatedListener() { 100 | Listener listener = mock(Listener.class); 101 | emitter.addListener(Event.VIEW_CREATED, listener); 102 | 103 | View view = mock(View.class); 104 | Bundle bundle = new Bundle(); 105 | emitter.onViewCreated(view, bundle); 106 | verify(listener).call(ViewCreated.create(view, bundle)); 107 | 108 | emitter.removeListener(listener); 109 | emitter.onCreate(new Bundle()); 110 | verifyNoMoreInteractions(listener); 111 | } 112 | 113 | @Test public void activityCreatedListener() { 114 | Listener listener = mock(Listener.class); 115 | emitter.addListener(Event.ACTIVITY_CREATED, listener); 116 | 117 | Bundle bundle = new Bundle(); 118 | emitter.onActivityCreated(bundle); 119 | verify(listener).call(bundle); 120 | 121 | emitter.removeListener(listener); 122 | emitter.onActivityCreated(bundle); 123 | verifyNoMoreInteractions(listener); 124 | } 125 | 126 | @Test public void viewStateRestoredListener() { 127 | Listener listener = mock(Listener.class); 128 | emitter.addListener(Event.VIEW_STATE_RESTORED, listener); 129 | 130 | Bundle bundle = new Bundle(); 131 | emitter.onViewStateRestored(bundle); 132 | verify(listener).call(bundle); 133 | 134 | emitter.removeListener(listener); 135 | emitter.onViewStateRestored(bundle); 136 | verifyNoMoreInteractions(listener); 137 | } 138 | 139 | @Test public void startListener() { 140 | Listener listener = mock(Listener.class); 141 | emitter.addListener(Event.START, listener); 142 | 143 | emitter.onStart(); 144 | verify(listener).call(any()); 145 | 146 | emitter.removeListener(listener); 147 | emitter.onStart(); 148 | verifyNoMoreInteractions(listener); 149 | } 150 | 151 | @Test public void resumeListener() { 152 | Listener listener = mock(Listener.class); 153 | emitter.addListener(Event.RESUME, listener); 154 | 155 | emitter.onResume(); 156 | verify(listener).call(any()); 157 | 158 | emitter.removeListener(listener); 159 | emitter.onResume(); 160 | verifyNoMoreInteractions(listener); 161 | } 162 | 163 | @Test public void pauseListener() { 164 | Listener listener = mock(Listener.class); 165 | emitter.addListener(Event.PAUSE, listener); 166 | 167 | emitter.onPause(); 168 | verify(listener).call(any()); 169 | 170 | emitter.removeListener(listener); 171 | emitter.onPause(); 172 | verifyNoMoreInteractions(listener); 173 | } 174 | 175 | @Test public void stopListener() { 176 | Listener listener = mock(Listener.class); 177 | emitter.addListener(Event.STOP, listener); 178 | 179 | emitter.onStop(); 180 | verify(listener).call(any()); 181 | 182 | emitter.removeListener(listener); 183 | emitter.onStop(); 184 | verifyNoMoreInteractions(listener); 185 | } 186 | 187 | @Test public void destroyViewListener() { 188 | Listener listener = mock(Listener.class); 189 | emitter.addListener(Event.DESTROY_VIEW, listener); 190 | 191 | emitter.onDestroyView(); 192 | verify(listener).call(any()); 193 | 194 | emitter.removeListener(listener); 195 | emitter.onDestroyView(); 196 | verifyNoMoreInteractions(listener); 197 | 198 | emitter.addListener(Event.DESTROY_VIEW, mock(Listener.class)); 199 | } 200 | 201 | @Test public void destroyListener() { 202 | Listener listener = mock(Listener.class); 203 | emitter.addListener(Event.DESTROY, listener); 204 | 205 | emitter.onDestroy(); 206 | verify(listener).call(any()); 207 | 208 | emitter.removeListener(listener); 209 | emitter.onDestroy(); 210 | verifyNoMoreInteractions(listener); 211 | } 212 | 213 | @Test public void detachListener() { 214 | Listener listener = mock(Listener.class); 215 | emitter.addListener(Event.DETACH, listener); 216 | 217 | emitter.onDetach(); 218 | verify(listener).call(any()); 219 | 220 | emitter.removeListener(listener); 221 | emitter.onDetach(); 222 | verifyNoMoreInteractions(listener); 223 | } 224 | 225 | @Test public void saveInstanceStateListener() { 226 | Listener listener = mock(Listener.class); 227 | emitter.addListener(Event.SAVE_INSTANCE_STATE, listener); 228 | 229 | Bundle bundle = new Bundle(); 230 | emitter.onSaveInstanceState(bundle); 231 | verify(listener).call(bundle); 232 | 233 | emitter.removeListener(listener); 234 | emitter.onSaveInstanceState(bundle); 235 | verifyNoMoreInteractions(listener); 236 | } 237 | 238 | @Test public void configurationChangedListener() { 239 | Listener listener = mock(Listener.class); 240 | emitter.addListener(Event.CONFIGURATION_CHANGED, listener); 241 | 242 | Configuration configuration = new Configuration(); 243 | emitter.onConfigurationChanged(configuration); 244 | verify(listener).call(configuration); 245 | 246 | emitter.removeListener(listener); 247 | emitter.onConfigurationChanged(configuration); 248 | verifyNoMoreInteractions(listener); 249 | } 250 | 251 | @Test public void activityResultListener() { 252 | Listener listener = mock(Listener.class); 253 | emitter.addListener(Event.ACTIVITY_RESULT, listener); 254 | 255 | int requestCode = 1; 256 | int resultCode = Activity.RESULT_OK; 257 | Intent data = new Intent(); 258 | emitter.onActivityResult(requestCode, resultCode, data); 259 | verify(listener).call(ActivityResult.create(requestCode, resultCode, data)); 260 | 261 | emitter.removeListener(listener); 262 | emitter.onActivityResult(requestCode, resultCode, data); 263 | verifyNoMoreInteractions(listener); 264 | } 265 | 266 | @Test public void requestPermissionsResultListener() { 267 | Listener listener = mock(Listener.class); 268 | emitter.addListener(Event.REQUEST_PERMISSIONS_RESULT, listener); 269 | 270 | int requestCode = 1; 271 | String[] permissions = new String[0]; 272 | int[] grantResults = new int[0]; 273 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 274 | verify(listener).call(RequestPermissionsResult.create(requestCode, permissions, grantResults)); 275 | 276 | emitter.removeListener(listener); 277 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 278 | verifyNoMoreInteractions(listener); 279 | } 280 | 281 | // The below should not work with fragments 282 | 283 | @Test public void createPersistableListener() { 284 | exception.expect(IllegalArgumentException.class); 285 | emitter.addListener(Event.CREATE_PERSISTABLE, mock(Listener.class)); 286 | } 287 | 288 | @Test public void postCreateListener() { 289 | exception.expect(IllegalArgumentException.class); 290 | emitter.addListener(Event.POST_CREATE, mock(Listener.class)); 291 | } 292 | 293 | @Test public void postCreatePersistableListener() { 294 | exception.expect(IllegalArgumentException.class); 295 | emitter.addListener(Event.POST_CREATE_PERSISTABLE, mock(Listener.class)); 296 | } 297 | 298 | @Test public void restartListener() { 299 | exception.expect(IllegalArgumentException.class); 300 | emitter.addListener(Event.RESTART, mock(Listener.class)); 301 | } 302 | 303 | @Test public void saveInstanceStatePersistableListener() { 304 | exception.expect(IllegalArgumentException.class); 305 | emitter.addListener(Event.SAVE_INSTANCE_STATE_PERSISTABLE, mock(Listener.class)); 306 | } 307 | 308 | @Test public void restoreInstanceStateListener() { 309 | exception.expect(IllegalArgumentException.class); 310 | emitter.addListener(Event.RESTORE_INSTANCE_STATE, mock(Listener.class)); 311 | } 312 | 313 | @Test public void restoreInstanceStatePersistableListener() { 314 | exception.expect(IllegalArgumentException.class); 315 | emitter.addListener(Event.RESTORE_INSTANCE_STATE_PERSISTABLE, mock(Listener.class)); 316 | } 317 | 318 | @Test public void newIntentListener() { 319 | exception.expect(IllegalArgumentException.class); 320 | emitter.addListener(Event.NEW_INTENT, mock(Listener.class)); 321 | } 322 | 323 | @Test public void backPressedListener() { 324 | exception.expect(IllegalArgumentException.class); 325 | emitter.addListener(Event.BACK_PRESSED, mock(Listener.class)); 326 | } 327 | 328 | @Test public void attachedToWindowListener() { 329 | exception.expect(IllegalArgumentException.class); 330 | emitter.addListener(Event.ATTACHED_TO_WINDOW, mock(Listener.class)); 331 | } 332 | 333 | @Test public void detachedFromWindowListener() { 334 | exception.expect(IllegalArgumentException.class); 335 | emitter.addListener(Event.DETACHED_FROM_WINDOW, mock(Listener.class)); 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /navi/src/test/java/com/trello/navi2/NaviActivityTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.trello.navi2; 16 | 17 | import android.app.Activity; 18 | import android.content.Intent; 19 | import android.content.res.Configuration; 20 | import android.os.Bundle; 21 | import android.os.PersistableBundle; 22 | import com.trello.navi2.internal.NaviEmitter; 23 | import com.trello.navi2.model.ActivityResult; 24 | import com.trello.navi2.model.BundleBundle; 25 | import com.trello.navi2.model.RequestPermissionsResult; 26 | import org.junit.Rule; 27 | import org.junit.Test; 28 | import org.junit.rules.ExpectedException; 29 | 30 | import static org.mockito.ArgumentMatchers.any; 31 | import static org.mockito.Mockito.mock; 32 | import static org.mockito.Mockito.verify; 33 | import static org.mockito.Mockito.verifyNoMoreInteractions; 34 | import static org.mockito.Mockito.verifyZeroInteractions; 35 | 36 | public final class NaviActivityTest { 37 | 38 | @Rule public final ExpectedException exception = ExpectedException.none(); 39 | 40 | private final NaviEmitter emitter = NaviEmitter.createActivityEmitter(); 41 | 42 | @Test public void createListener() { 43 | Listener listener = mock(Listener.class); 44 | emitter.addListener(Event.CREATE, listener); 45 | 46 | Bundle bundle = new Bundle(); 47 | emitter.onCreate(bundle); 48 | verify(listener).call(bundle); 49 | 50 | emitter.removeListener(listener); 51 | emitter.onCreate(bundle); 52 | verifyNoMoreInteractions(listener); 53 | } 54 | 55 | @Test public void createPersistableListener() { 56 | Listener listener = mock(Listener.class); 57 | Listener persistableListener = mock(Listener.class); 58 | emitter.addListener(Event.CREATE, listener); 59 | emitter.addListener(Event.CREATE_PERSISTABLE, persistableListener); 60 | 61 | Bundle bundle = new Bundle(); 62 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 63 | emitter.onCreate(bundle, persistableBundle); 64 | verifyZeroInteractions(listener); 65 | verify(persistableListener).call(BundleBundle.create(bundle, persistableBundle)); 66 | 67 | emitter.removeListener(listener); 68 | emitter.removeListener(persistableListener); 69 | emitter.onCreate(bundle, persistableBundle); 70 | verifyNoMoreInteractions(listener); 71 | verifyNoMoreInteractions(persistableListener); 72 | } 73 | 74 | @Test public void startListener() { 75 | Listener listener = mock(Listener.class); 76 | emitter.addListener(Event.START, listener); 77 | 78 | emitter.onStart(); 79 | verify(listener).call(any()); 80 | 81 | emitter.removeListener(listener); 82 | emitter.onStart(); 83 | verifyNoMoreInteractions(listener); 84 | } 85 | 86 | @Test public void postCreateListener() { 87 | Listener listener = mock(Listener.class); 88 | emitter.addListener(Event.POST_CREATE, listener); 89 | 90 | Bundle bundle = new Bundle(); 91 | emitter.onPostCreate(bundle); 92 | verify(listener).call(bundle); 93 | 94 | emitter.removeListener(listener); 95 | emitter.onPostCreate(bundle); 96 | verifyNoMoreInteractions(listener); 97 | } 98 | 99 | @Test public void postCreatePersistableListener() { 100 | Listener listener = mock(Listener.class); 101 | Listener persistableListener = mock(Listener.class); 102 | emitter.addListener(Event.POST_CREATE, listener); 103 | emitter.addListener(Event.POST_CREATE_PERSISTABLE, persistableListener); 104 | 105 | Bundle bundle = new Bundle(); 106 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 107 | emitter.onPostCreate(bundle, persistableBundle); 108 | verifyZeroInteractions(listener); 109 | verify(persistableListener).call(BundleBundle.create(bundle, persistableBundle)); 110 | 111 | emitter.removeListener(listener); 112 | emitter.removeListener(persistableListener); 113 | emitter.onPostCreate(bundle, persistableBundle); 114 | verifyNoMoreInteractions(listener); 115 | verifyNoMoreInteractions(persistableListener); 116 | } 117 | 118 | @Test public void resumeListener() { 119 | Listener listener = mock(Listener.class); 120 | emitter.addListener(Event.RESUME, listener); 121 | 122 | emitter.onResume(); 123 | verify(listener).call(any()); 124 | 125 | emitter.removeListener(listener); 126 | emitter.onResume(); 127 | verifyNoMoreInteractions(listener); 128 | } 129 | 130 | @Test public void pauseListener() { 131 | Listener listener = mock(Listener.class); 132 | emitter.addListener(Event.PAUSE, listener); 133 | 134 | emitter.onPause(); 135 | verify(listener).call(any()); 136 | 137 | emitter.removeListener(listener); 138 | emitter.onPause(); 139 | verifyNoMoreInteractions(listener); 140 | } 141 | 142 | @Test public void stopListener() { 143 | Listener listener = mock(Listener.class); 144 | emitter.addListener(Event.STOP, listener); 145 | 146 | emitter.onStop(); 147 | verify(listener).call(any()); 148 | 149 | emitter.removeListener(listener); 150 | emitter.onStop(); 151 | verifyNoMoreInteractions(listener); 152 | } 153 | 154 | @Test public void destroyListener() { 155 | Listener listener = mock(Listener.class); 156 | emitter.addListener(Event.DESTROY, listener); 157 | 158 | emitter.onDestroy(); 159 | verify(listener).call(any()); 160 | 161 | emitter.removeListener(listener); 162 | emitter.onDestroy(); 163 | verifyNoMoreInteractions(listener); 164 | } 165 | 166 | @Test public void restartListener() { 167 | Listener listener = mock(Listener.class); 168 | emitter.addListener(Event.RESTART, listener); 169 | 170 | emitter.onRestart(); 171 | verify(listener).call(any()); 172 | 173 | emitter.removeListener(listener); 174 | emitter.onRestart(); 175 | verifyNoMoreInteractions(listener); 176 | } 177 | 178 | @Test public void saveInstanceStateListener() { 179 | Listener listener = mock(Listener.class); 180 | emitter.addListener(Event.SAVE_INSTANCE_STATE, listener); 181 | 182 | Bundle bundle = new Bundle(); 183 | emitter.onSaveInstanceState(bundle); 184 | verify(listener).call(bundle); 185 | 186 | emitter.removeListener(listener); 187 | emitter.onSaveInstanceState(bundle); 188 | verifyNoMoreInteractions(listener); 189 | } 190 | 191 | @Test public void saveInstanceStatePersistableListener() { 192 | Listener listener = mock(Listener.class); 193 | Listener persistableListener = mock(Listener.class); 194 | emitter.addListener(Event.SAVE_INSTANCE_STATE, listener); 195 | emitter.addListener(Event.SAVE_INSTANCE_STATE_PERSISTABLE, persistableListener); 196 | 197 | Bundle bundle = new Bundle(); 198 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 199 | emitter.onSaveInstanceState(bundle, persistableBundle); 200 | verifyZeroInteractions(listener); 201 | verify(persistableListener).call(BundleBundle.create(bundle, persistableBundle)); 202 | 203 | emitter.removeListener(listener); 204 | emitter.removeListener(persistableListener); 205 | emitter.onSaveInstanceState(bundle, persistableBundle); 206 | verifyNoMoreInteractions(listener); 207 | verifyNoMoreInteractions(persistableListener); 208 | } 209 | 210 | @Test public void restoreInstanceStateListener() { 211 | Listener listener = mock(Listener.class); 212 | emitter.addListener(Event.RESTORE_INSTANCE_STATE, listener); 213 | 214 | Bundle bundle = new Bundle(); 215 | emitter.onRestoreInstanceState(bundle); 216 | verify(listener).call(bundle); 217 | 218 | emitter.removeListener(listener); 219 | emitter.onRestoreInstanceState(bundle); 220 | verifyNoMoreInteractions(listener); 221 | } 222 | 223 | @Test public void restoreInstanceStatePersistableListener() { 224 | Listener listener = mock(Listener.class); 225 | Listener persistableListener = mock(Listener.class); 226 | emitter.addListener(Event.RESTORE_INSTANCE_STATE, listener); 227 | emitter.addListener(Event.RESTORE_INSTANCE_STATE_PERSISTABLE, persistableListener); 228 | 229 | Bundle bundle = new Bundle(); 230 | PersistableBundle persistableBundle = mock(PersistableBundle.class); 231 | emitter.onRestoreInstanceState(bundle, persistableBundle); 232 | verifyZeroInteractions(listener); 233 | verify(persistableListener).call(BundleBundle.create(bundle, persistableBundle)); 234 | 235 | emitter.removeListener(listener); 236 | emitter.removeListener(persistableListener); 237 | emitter.onRestoreInstanceState(bundle, persistableBundle); 238 | verifyNoMoreInteractions(listener); 239 | verifyNoMoreInteractions(persistableListener); 240 | } 241 | 242 | @Test public void newIntentListener() { 243 | Listener listener = mock(Listener.class); 244 | emitter.addListener(Event.NEW_INTENT, listener); 245 | 246 | Intent intent = new Intent(); 247 | emitter.onNewIntent(intent); 248 | verify(listener).call(intent); 249 | 250 | emitter.removeListener(listener); 251 | emitter.onNewIntent(intent); 252 | verifyNoMoreInteractions(listener); 253 | } 254 | 255 | @Test public void backPressedListener() { 256 | Listener listener = mock(Listener.class); 257 | emitter.addListener(Event.BACK_PRESSED, listener); 258 | 259 | emitter.onBackPressed(); 260 | verify(listener).call(any()); 261 | 262 | emitter.removeListener(listener); 263 | emitter.onBackPressed(); 264 | verifyNoMoreInteractions(listener); 265 | } 266 | 267 | @Test public void attachedToWindowListener() { 268 | Listener listener = mock(Listener.class); 269 | emitter.addListener(Event.ATTACHED_TO_WINDOW, listener); 270 | 271 | emitter.onAttachedToWindow(); 272 | verify(listener).call(any()); 273 | 274 | emitter.removeListener(listener); 275 | emitter.onAttachedToWindow(); 276 | verifyNoMoreInteractions(listener); 277 | } 278 | 279 | @Test public void detachedFromWindowListener() { 280 | Listener listener = mock(Listener.class); 281 | emitter.addListener(Event.DETACHED_FROM_WINDOW, listener); 282 | 283 | emitter.onDetachedFromWindow(); 284 | verify(listener).call(any()); 285 | 286 | emitter.removeListener(listener); 287 | emitter.onDetachedFromWindow(); 288 | verifyNoMoreInteractions(listener); 289 | } 290 | 291 | @Test public void configurationChangedListener() { 292 | Listener listener = mock(Listener.class); 293 | emitter.addListener(Event.CONFIGURATION_CHANGED, listener); 294 | 295 | Configuration configuration = new Configuration(); 296 | emitter.onConfigurationChanged(configuration); 297 | verify(listener).call(configuration); 298 | 299 | emitter.removeListener(listener); 300 | emitter.onConfigurationChanged(configuration); 301 | verifyNoMoreInteractions(listener); 302 | } 303 | 304 | @Test public void activityResultListener() { 305 | Listener listener = mock(Listener.class); 306 | emitter.addListener(Event.ACTIVITY_RESULT, listener); 307 | 308 | int requestCode = 1; 309 | int resultCode = Activity.RESULT_OK; 310 | Intent data = new Intent(); 311 | emitter.onActivityResult(requestCode, resultCode, data); 312 | verify(listener).call(ActivityResult.create(requestCode, resultCode, data)); 313 | 314 | emitter.removeListener(listener); 315 | emitter.onActivityResult(requestCode, resultCode, data); 316 | verifyNoMoreInteractions(listener); 317 | } 318 | 319 | @Test public void requestPermissionsResultListener() { 320 | Listener listener = mock(Listener.class); 321 | emitter.addListener(Event.REQUEST_PERMISSIONS_RESULT, listener); 322 | 323 | int requestCode = 1; 324 | String[] permissions = new String[0]; 325 | int[] grantResults = new int[0]; 326 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 327 | verify(listener).call(RequestPermissionsResult.create(requestCode, permissions, grantResults)); 328 | 329 | emitter.removeListener(listener); 330 | emitter.onRequestPermissionsResult(requestCode, permissions, grantResults); 331 | verifyNoMoreInteractions(listener); 332 | } 333 | 334 | // The below should not work with activities 335 | 336 | @Test public void attachListener() { 337 | exception.expect(IllegalArgumentException.class); 338 | emitter.addListener(Event.ATTACH, mock(Listener.class)); 339 | } 340 | 341 | @Test public void createViewListener() { 342 | exception.expect(IllegalArgumentException.class); 343 | emitter.addListener(Event.CREATE_VIEW, mock(Listener.class)); 344 | } 345 | 346 | @Test public void viewCreatedListener() { 347 | exception.expect(IllegalArgumentException.class); 348 | emitter.addListener(Event.VIEW_CREATED, mock(Listener.class)); 349 | } 350 | 351 | @Test public void activityCreatedListener() { 352 | exception.expect(IllegalArgumentException.class); 353 | emitter.addListener(Event.ACTIVITY_CREATED, mock(Listener.class)); 354 | } 355 | 356 | @Test public void viewStateRestoredListener() { 357 | exception.expect(IllegalArgumentException.class); 358 | emitter.addListener(Event.VIEW_STATE_RESTORED, mock(Listener.class)); 359 | } 360 | 361 | @Test public void destroyViewListener() { 362 | exception.expect(IllegalArgumentException.class); 363 | emitter.addListener(Event.DESTROY_VIEW, mock(Listener.class)); 364 | } 365 | 366 | @Test public void detachListener() { 367 | exception.expect(IllegalArgumentException.class); 368 | emitter.addListener(Event.DETACH, mock(Listener.class)); 369 | } 370 | } 371 | --------------------------------------------------------------------------------