├── library-lint
├── src
│ ├── test
│ │ ├── resources
│ │ │ └── java
│ │ │ │ ├── Empty.java
│ │ │ │ ├── BaseClass.java
│ │ │ │ ├── ValidActivityOtherMethodKt.kt
│ │ │ │ ├── ValidActivityOtherMethod.java
│ │ │ │ ├── InvalidActivityNoSaveKt.kt
│ │ │ │ ├── InvalidActivityNoRestoreKt.kt
│ │ │ │ ├── InvalidActivityNoRestoreDirectImportKt.kt
│ │ │ │ ├── InvalidActivityNoRestore.java
│ │ │ │ ├── InvalidActivityNoSave.java
│ │ │ │ ├── ValidActivityKt.kt
│ │ │ │ ├── stub
│ │ │ │ └── StateSaver.java
│ │ │ │ ├── InvalidActivityNoRestoreDirectImport.java
│ │ │ │ ├── ValidActivity.java
│ │ │ │ ├── InvalidActivityOtherMethodKt.kt
│ │ │ │ ├── ValidActivityDirectImportKt.kt
│ │ │ │ ├── InvalidActivityOtherMethod.java
│ │ │ │ └── ValidActivityDirectImport.java
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── evernote
│ │ │ └── android
│ │ │ └── state
│ │ │ └── lint
│ │ │ ├── registry
│ │ │ └── StateIssueRegistryTest.kt
│ │ │ ├── AbstractDetectorTest.kt
│ │ │ └── detectors
│ │ │ └── NonMatchingStateSaverDetectorTest.kt
│ └── main
│ │ └── kotlin
│ │ └── com
│ │ └── evernote
│ │ └── android
│ │ └── state
│ │ └── lint
│ │ ├── registry
│ │ └── StateIssueRegistry.kt
│ │ └── detector
│ │ └── AndroidStateDetector.kt
└── build.gradle
├── gradle.properties
├── library
├── src
│ ├── test
│ │ ├── resources
│ │ │ └── mockito-extensions
│ │ │ │ └── org.mockito.plugins.MockMaker
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── evernote
│ │ │ │ └── android
│ │ │ │ └── state
│ │ │ │ └── test
│ │ │ │ ├── TestSimple.java
│ │ │ │ ├── TestStatic.java
│ │ │ │ ├── TestFinal.java
│ │ │ │ ├── TestPrivateField.java
│ │ │ │ ├── TestInnerClassGeneric.java
│ │ │ │ ├── TestPrivateClass.java
│ │ │ │ ├── TestTypeNotSupported.java
│ │ │ │ ├── TestInnerClass.java
│ │ │ │ ├── TestInnerClassExtension.java
│ │ │ │ ├── TestProperty.java
│ │ │ │ ├── TestPrivateProperty.java
│ │ │ │ ├── GenericSerializable.java
│ │ │ │ ├── TestInheritance.java
│ │ │ │ ├── TestInheritanceGeneric.java
│ │ │ │ ├── TestJavaGenericSerializable.java
│ │ │ │ ├── TestJavaEnum.java
│ │ │ │ ├── TestNested.java
│ │ │ │ ├── TestPrivateClassBundler.java
│ │ │ │ ├── TestPrivateClassBundlerData.java
│ │ │ │ ├── TestView.java
│ │ │ │ ├── TestTypesReflection.java
│ │ │ │ ├── TestParcelableArray.java
│ │ │ │ ├── TestBundler.java
│ │ │ │ ├── TestJavaList.java
│ │ │ │ ├── TestPrivateInnerClass.java
│ │ │ │ ├── TestTypes.java
│ │ │ │ └── TestTypesProperty.java
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── evernote
│ │ │ └── android
│ │ │ └── state
│ │ │ ├── test
│ │ │ ├── TestKotlinGenericSerializable.kt
│ │ │ ├── TestKotlinInnerClass.kt
│ │ │ ├── TestKotlinBoolean.kt
│ │ │ ├── TestKotlinParcelableArray.kt
│ │ │ ├── TestKotlinEnum.kt
│ │ │ ├── TestKotlinBundler.kt
│ │ │ ├── TestKotlinComparable.kt
│ │ │ ├── TestKotlinList.kt
│ │ │ ├── TestKotlinPrivateInnerClass.kt
│ │ │ └── KotlinBundlingTest.kt
│ │ │ └── StateSaverTest.kt
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── evernote
│ │ │ └── android
│ │ │ └── state
│ │ │ ├── State.java
│ │ │ ├── StateReflection.java
│ │ │ ├── bundlers
│ │ │ ├── BundlerListString.java
│ │ │ ├── BundlerListInteger.java
│ │ │ ├── BundlerListCharSequence.java
│ │ │ └── BundlerListParcelable.java
│ │ │ ├── Bundler.java
│ │ │ ├── Injector.java
│ │ │ ├── AndroidLifecycleCallbacks.java
│ │ │ ├── StateSaver.java
│ │ │ └── StateSaverImpl.java
│ └── androidTest
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ └── com
│ │ └── evernote
│ │ └── android
│ │ └── state
│ │ └── test
│ │ └── GlobalStateSaverTest.kt
├── gradle.properties
├── lint.xml
├── proguard.cfg
└── build.gradle
├── demo
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ └── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── kotlin
│ │ └── com
│ │ │ └── evernote
│ │ │ └── android
│ │ │ └── state
│ │ │ └── demo
│ │ │ ├── App.kt
│ │ │ └── MainActivity.kt
│ │ ├── java
│ │ └── com
│ │ │ └── evernote
│ │ │ └── android
│ │ │ └── state
│ │ │ └── test
│ │ │ └── lint
│ │ │ ├── LintFailingActivityKotlin.kt
│ │ │ └── LintFailingActivityJava.java
│ │ └── AndroidManifest.xml
├── lint.xml
└── build.gradle
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── pmd
│ └── pmd-ruleset.xml
├── findbugs
│ └── findbugs-filter.xml
├── gradle-quality.gradle
├── checkstyle
│ └── checkstyle.xml
└── gradle-push.gradle
├── processor
├── gradle.properties
├── src
│ └── main
│ │ └── resources
│ │ └── META-INF
│ │ └── gradle
│ │ └── incremental.annotation.processors
└── build.gradle
├── demo-java-8
├── lint.xml
├── src
│ ├── main
│ │ ├── res
│ │ │ └── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── evernote
│ │ │ ├── different
│ │ │ ├── TestProguardHelper.java
│ │ │ ├── TestProguard.java
│ │ │ └── TestProguardBundler.java
│ │ │ └── android
│ │ │ └── state
│ │ │ └── test
│ │ │ └── java8
│ │ │ ├── TestNested.java
│ │ │ ├── TestTypes.java
│ │ │ └── TestTypesProperty.java
│ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── evernote
│ │ │ └── android
│ │ │ └── state
│ │ │ └── test
│ │ │ └── java8
│ │ │ └── ProguardTest.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── evernote
│ │ └── android
│ │ └── state
│ │ └── test
│ │ └── java8
│ │ └── Java8BundlingTest.java
├── proguard.cfg
└── build.gradle
├── settings.gradle
├── .gitignore
├── gradlew.bat
├── CHANGELOG.md
├── gradlew
└── README.md
/library-lint/src/test/resources/java/Empty.java:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #VERSION_NAME=1.4.1
2 | VERSION_NAME=1.4.1-SNAPSHOT
3 | VERSION_CODE=1
--------------------------------------------------------------------------------
/library/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker:
--------------------------------------------------------------------------------
1 | mock-maker-inline
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=android-state
2 | POM_NAME=Android State
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | State Demo
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Evernote/android-state/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/processor/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=android-state-processor
2 | POM_NAME=Android State Processor
3 | POM_PACKAGING=jar
--------------------------------------------------------------------------------
/demo/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/processor/src/main/resources/META-INF/gradle/incremental.annotation.processors:
--------------------------------------------------------------------------------
1 | com.evernote.android.state.StateProcessor,isolating
--------------------------------------------------------------------------------
/demo-java-8/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/library/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':demo'
2 | include ':library-lint'
3 | include ':library'
4 | include ':processor'
5 | include ':demo-java-8'
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Evernote/android-state/HEAD/demo/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Evernote/android-state/HEAD/demo/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Evernote/android-state/HEAD/demo/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Evernote/android-state/HEAD/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-java-8/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Evernote/android-state/HEAD/demo-java-8/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestSimple.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | public class TestSimple {
6 | @State
7 | int field;
8 | }
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestStatic.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import com.evernote.android.state.State;
4 | //
5 | //public class TestStatic {
6 | // @State
7 | // public static int test;
8 | //}
9 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestFinal.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import com.evernote.android.state.State;
4 | //
5 | //public class TestFinal {
6 | // @State
7 | // public final int test = 5;
8 | //}
9 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestPrivateField.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import com.evernote.android.state.State;
4 | //
5 | //public class TestPrivateField {
6 | // @State
7 | // private int test;
8 | //}
9 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestInnerClassGeneric.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | public class TestInnerClassGeneric
{
6 |
7 | public class Inner {
8 | @State int field;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestPrivateClass.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import com.evernote.android.state.State;
4 | //
5 | //public class TestPrivateClass {
6 | // private static class Inner {
7 | // @State
8 | // public int test;
9 | // }
10 | //}
11 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestTypeNotSupported.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import com.evernote.android.state.State;
4 | //
5 | //public class TestTypeNotSupported {
6 | // @State
7 | // public Other test;
8 | //
9 | // public static final class Other {}
10 | //}
11 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestInnerClass.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | /**
6 | * @author rwondratschek
7 | */
8 | public abstract class TestInnerClass {
9 | public class Inner {
10 | @State int field;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinGenericSerializable.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test
2 |
3 | import com.evernote.android.state.State
4 |
5 | /**
6 | * @author rwondratschek
7 | */
8 | class TestKotlinGenericSerializable {
9 |
10 | @State
11 | var genericSerializable: GenericSerializable? = null
12 | }
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinInnerClass.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test
2 |
3 | import java.io.Serializable
4 |
5 | /**
6 | * Copyright 2017 Evernote Corporation. All rights reserved.
7 | *
8 | * Created by rwondratschek on 3/16/17.
9 | */
10 | class TestKotlinInnerClass {
11 | class Inner : Serializable
12 | }
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/BaseClass.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.lint;
2 |
3 | /**
4 | * Created by junchengc on 3/29/17.
5 | */
6 | public class BaseClass {
7 | private boolean mBoolean;
8 | protected String mString;
9 | public static final boolean STATIC_BOOLEAN = true;
10 | public static final String STATIC_STRING = "some junk";
11 | }
12 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestInnerClassExtension.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | /**
6 | * @author rwondratschek
7 | */
8 | public class TestInnerClassExtension extends TestInnerClass {
9 | public class Inner extends TestInnerClass.Inner {
10 | @State int fields;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinBoolean.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test
2 |
3 | import com.evernote.android.state.State
4 |
5 | /**
6 | * @author rwondratschek
7 | */
8 | class TestKotlinBoolean {
9 |
10 | @State
11 | var test1 = false
12 |
13 | @State
14 | var isTest2 = false
15 |
16 | @State
17 | var mTest3 = false
18 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestProperty.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | public class TestProperty {
6 | @State
7 | private int test;
8 |
9 | public int getTest() {
10 | return test;
11 | }
12 |
13 | public void setTest(int test) {
14 | this.test = test;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gradle/pmd/pmd-ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | This ruleset checks my code for bad stuff
8 |
9 |
--------------------------------------------------------------------------------
/demo/src/main/kotlin/com/evernote/android/state/demo/App.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.demo
2 |
3 | import android.app.Application
4 |
5 | import com.evernote.android.state.StateSaver
6 |
7 | /**
8 | * @author rwondratschek
9 | */
10 | class App : Application() {
11 | override fun onCreate() {
12 | super.onCreate()
13 | StateSaver.setEnabledForAllActivitiesAndSupportFragments(this, true)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestPrivateProperty.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import com.evernote.android.state.State;
4 | //
5 | //public class TestPrivateProperty {
6 | // @State
7 | // private int test;
8 | //
9 | // private int getTest() {
10 | // return test;
11 | // }
12 | //
13 | // public void setTest(int test) {
14 | // this.test = test;
15 | // }
16 | //}
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Android generated
2 | bin
3 | gen
4 | target
5 | out
6 | build
7 |
8 | #Eclipse
9 | .project
10 | .classpath
11 | .settings
12 |
13 | #IntelliJ IDEA
14 | .idea
15 | *.iml
16 | classes
17 | *.ipr
18 | *.iws
19 | gen-external-apklibs
20 |
21 | #Maven
22 | release.properties
23 | pom.xml.*
24 |
25 | #Ant
26 | build.xml
27 | ant.properties
28 | local.properties
29 |
30 | #Gradle
31 | .gradle
32 |
33 | #Command line
34 | proguard-project.txt
35 | .DS_Store
36 | .tmp
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/GenericSerializable.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * @author rwondratschek
7 | */
8 | public class GenericSerializable implements Serializable {
9 |
10 | private T mValue;
11 |
12 | public T getValue() {
13 | return mValue;
14 | }
15 |
16 | public void setValue(T value) {
17 | mValue = value;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/library-lint/src/main/kotlin/com/evernote/android/state/lint/registry/StateIssueRegistry.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.lint.registry
2 |
3 | import com.android.tools.lint.client.api.IssueRegistry
4 | import com.evernote.android.state.lint.detector.AndroidStateDetector
5 |
6 | class StateIssueRegistry : IssueRegistry() {
7 | override val issues = listOf(AndroidStateDetector.ISSUE)
8 | override val api: Int = com.android.tools.lint.detector.api.CURRENT_API
9 | }
10 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestInheritance.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | public class TestInheritance {
6 |
7 | @State
8 | public int mValue1;
9 |
10 | public static class InheritanceLevel1 extends TestInheritance {
11 |
12 | }
13 |
14 | public static class InheritanceLevel2 extends InheritanceLevel1 {
15 |
16 | @State
17 | public int mValue2;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/demo-java-8/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/library/src/androidTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestInheritanceGeneric.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | public class TestInheritanceGeneric {
6 |
7 | @State
8 | public int mValue1;
9 |
10 | public P mGenericValue;
11 |
12 | public static class InheritanceLevelGeneric1
extends TestInheritanceGeneric
{
13 |
14 | }
15 |
16 | public static class InheritanceLevelGeneric2 extends InheritanceLevelGeneric1 {
17 |
18 | @State
19 | public int mValue2;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java:
--------------------------------------------------------------------------------
1 | package com.evernote.different;
2 |
3 | import androidx.annotation.Keep;
4 |
5 | /**
6 | * @author rwondratschek
7 | */
8 | public final class TestProguardHelper {
9 |
10 | private TestProguardHelper() {
11 | // no op
12 | }
13 |
14 | @Keep
15 | public static void setValue(TestProguard instance, int value) {
16 | instance.setValue(value);
17 | }
18 |
19 | @Keep
20 | public static void verifyValue(TestProguard instance, int value) {
21 | instance.verifyValue(value);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/evernote/android/state/test/lint/LintFailingActivityKotlin.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test.lint
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.os.Bundle
6 |
7 | import com.evernote.android.state.StateSaver
8 |
9 | /**
10 | * @author rwondratschek
11 | */
12 | class LintFailingActivityKotlin : Activity() {
13 |
14 | @SuppressLint("NonMatchingStateSaverCalls")
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | StateSaver.restoreInstanceState(this, savedInstanceState)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestJavaGenericSerializable.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | /**
6 | * @author rwondratschek
7 | */
8 | public class TestJavaGenericSerializable {
9 |
10 | @State
11 | private GenericSerializable mGenericSerializable;
12 |
13 | public GenericSerializable getGenericSerializable() {
14 | return mGenericSerializable;
15 | }
16 |
17 | public void setGenericSerializable(GenericSerializable genericSerializable) {
18 | mGenericSerializable = genericSerializable;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/library/proguard.cfg:
--------------------------------------------------------------------------------
1 | -dontwarn com.evernote.android.state.**
2 | -keep class com.evernote.android.state.** { *; }
3 | -keep class **$$StateSaver { *; }
4 |
5 | # generated class names
6 | -keepclasseswithmembernames class * { @com.evernote.android.state.State ;}
7 | -keepclasseswithmembernames class * { @com.evernote.android.state.StateReflection ;}
8 |
9 | # only keep non-private fields, there must be a getter / setter for private fields
10 | #-keepclassmembers class * {
11 | # @com.evernote.android.state.State !private ;
12 | #}
13 |
14 | # with reflection always keep the name of the field
15 | -keepclassmembers class * { @com.evernote.android.state.StateReflection ;}
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestJavaEnum.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 | import com.evernote.android.state.StateReflection;
5 |
6 | /**
7 | * @author rwondratschek
8 | */
9 | public class TestJavaEnum {
10 |
11 | public enum JavaEnum {
12 | LEFT, RIGHT
13 | }
14 |
15 | @State
16 | JavaEnum mJavaEnum = JavaEnum.LEFT;
17 |
18 | @StateReflection
19 | private JavaEnum mJavaEnum1 = JavaEnum.LEFT;
20 |
21 | public JavaEnum getJavaEnum1() {
22 | return mJavaEnum1;
23 | }
24 |
25 | public void setJavaEnum1(JavaEnum javaEnum1) {
26 | mJavaEnum1 = javaEnum1;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/evernote/android/state/test/lint/LintFailingActivityJava.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test.lint;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.os.Bundle;
6 | import androidx.annotation.Nullable;
7 |
8 | import com.evernote.android.state.StateSaver;
9 |
10 | /**
11 | * @author rwondratschek
12 | */
13 | public class LintFailingActivityJava extends Activity {
14 |
15 | @SuppressLint("NonMatchingStateSaverCalls")
16 | @Override
17 | protected void onCreate(@Nullable Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | StateSaver.restoreInstanceState(this, savedInstanceState);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/library-lint/src/test/kotlin/com/evernote/android/state/lint/registry/StateIssueRegistryTest.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.lint.registry
2 |
3 | import com.evernote.android.state.lint.detector.AndroidStateDetector
4 | import org.assertj.core.api.Assertions.assertThat
5 | import org.junit.Test
6 |
7 |
8 | /**
9 | * Test the [StateIssueRegistry].
10 | */
11 | class StateIssueRegistryTest {
12 |
13 | /**
14 | * Test that the issue registry contains the correct number of issues.
15 | */
16 | @Test
17 | fun testNumberOfIssues() {
18 | assertThat(StateIssueRegistry().issues).hasSize(1)
19 | }
20 |
21 | /**
22 | * Test that the issue registry contains the correct issues.
23 | */
24 | @Test
25 | fun testGetIssues() {
26 | assertThat(StateIssueRegistry().issues).contains(AndroidStateDetector.ISSUE)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestNested.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | public class TestNested {
6 | @State
7 | public int test;
8 |
9 | public static class Inner1 {
10 | @State
11 | public int test;
12 |
13 | public static class InnerInner1 {
14 | @State
15 | public int test;
16 | }
17 | public static class InnerInner2 {
18 | @State
19 | public int test;
20 | }
21 | }
22 | public static class Inner2 {
23 | @State
24 | public int test;
25 |
26 | public static class InnerInner1 {
27 | @State
28 | public int test;
29 | }
30 | public static class InnerInner2 {
31 | @State
32 | public int test;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/demo-java-8/src/main/java/com/evernote/android/state/test/java8/TestNested.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test.java8;
2 |
3 | import com.evernote.android.state.State;
4 |
5 | public class TestNested {
6 | @State
7 | public int test;
8 |
9 | public static class Inner1 {
10 | @State
11 | public int test;
12 |
13 | public static class InnerInner1 {
14 | @State
15 | public int test;
16 | }
17 | public static class InnerInner2 {
18 | @State
19 | public int test;
20 | }
21 | }
22 | public static class Inner2 {
23 | @State
24 | public int test;
25 |
26 | public static class InnerInner1 {
27 | @State
28 | public int test;
29 | }
30 | public static class InnerInner2 {
31 | @State
32 | public int test;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinParcelableArray.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test
2 |
3 | import com.evernote.android.state.State
4 | import com.evernote.android.state.StateReflection
5 |
6 | /**
7 | * @author rwondratschek
8 | */
9 | class TestKotlinParcelableArray {
10 | @State
11 | var parcelableArrayImpl1: Array = arrayOf(TestTypes.ParcelableImpl(0))
12 |
13 | @StateReflection
14 | private var mParcelableArrayImpl2: Array = arrayOf(TestTypes.ParcelableImpl(0))
15 |
16 | fun setToValue(value: Int) {
17 | parcelableArrayImpl1 = arrayOf(TestTypes.ParcelableImpl(value))
18 | mParcelableArrayImpl2 = arrayOf(TestTypes.ParcelableImpl(value))
19 | }
20 |
21 | fun isValue(value: Int): Boolean {
22 | return parcelableArrayImpl1[0].isValue(value) && mParcelableArrayImpl2[0].isValue(value)
23 | }
24 | }
--------------------------------------------------------------------------------
/demo-java-8/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 3
2 | -repackageclasses
3 | -dontusemixedcaseclassnames
4 | -dontskipnonpubliclibraryclasses
5 | -dontskipnonpubliclibraryclassmembers
6 | -dontpreverify
7 | -verbose
8 | -dontwarn
9 | -ignorewarnings
10 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*, !method/inlining/unique, !method/inlining/short
11 |
12 | -printconfiguration "build/outputs/mapping/configuration.txt"
13 |
14 | # Proguard rules that are applied to your test apk/code.
15 | -keepattributes *Annotation*
16 |
17 | -keep class junit.framework.** { *; }
18 | -keep class junit.runner.** { *; }
19 |
20 | -keep class android.test.** { *; }
21 | -keep class android.support.test.** { *; }
22 | -keep class org.junit.** { *; }
23 | -keep class org.hamcrest.** { *; }
24 | -keep class com.squareup.javawriter.JavaWriter { *; }
25 | -keep class com.google.devtools.** { *; }
26 | # Uncomment this if you use Mockito
27 | #-dontwarn org.mockito.**
--------------------------------------------------------------------------------
/gradle/findbugs/findbugs-filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/processor/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'com.github.ben-manes.versions'
3 | apply from: "$rootDir/gradle/gradle-quality.gradle"
4 |
5 | sourceCompatibility = JavaVersion.VERSION_1_7
6 | targetCompatibility = JavaVersion.VERSION_1_7
7 |
8 | archivesBaseName = 'android-state-processor'
9 |
10 | test.dependsOn ":library:bundleReleaseAar"
11 |
12 | dependencies {
13 | implementation 'com.squareup:javapoet:1.11.1'
14 |
15 | compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
16 |
17 | testImplementation 'com.google.android:android:4.1.1.4'
18 | testImplementation files('../library/build/intermediates/packaged-classes/release/classes.jar')
19 |
20 | testImplementation "junit:junit:$junitVersion"
21 | testImplementation 'com.google.testing.compile:compile-testing:0.15'
22 | testImplementation files(org.gradle.internal.jvm.Jvm.current().getToolsJar())
23 | }
24 |
25 | jar {
26 | destinationDir = new File("$project.buildDir/outputs/jar/")
27 | }
28 |
29 | apply from: "$rootDir/gradle/gradle-push.gradle"
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/ValidActivityOtherMethodKt.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint
12 |
13 | import android.app.Activity
14 | import android.os.Bundle
15 | import com.evernote.android.state.StateSaver
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | class ValidActivityOtherMethodKt : Activity() {
21 | protected override fun onCreate(savedInstanceState: Bundle) {
22 | super.onCreate(savedInstanceState)
23 | restoreInstanceState()
24 | }
25 |
26 | private fun restoreInstanceState() {
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/ValidActivityOtherMethod.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint;
12 |
13 | import android.app.Activity;
14 | import android.os.Bundle;
15 | import com.evernote.android.state.StateSaver;
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | public class ValidActivityOtherMethod extends Activity {
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | restoreInstanceState();
25 | }
26 |
27 | private void restoreInstanceState() {
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityNoSaveKt.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint
12 |
13 | import android.app.Activity
14 | import android.os.Bundle
15 | import com.evernote.android.state.StateSaver
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | class InvalidActivityNoSaveKt : Activity() {
21 | override fun onCreate(savedInstanceState: Bundle) {
22 | super.onCreate(savedInstanceState)
23 | StateSaver.restoreInstanceState(this, savedInstanceState)
24 | }
25 |
26 | override fun onSaveInstanceState(outState: Bundle) {
27 | super.onSaveInstanceState(outState)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityNoRestoreKt.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint
12 |
13 | import android.app.Activity
14 | import android.os.Bundle
15 | import com.evernote.android.state.StateSaver
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | class InvalidActivityNoRestoreKt : Activity() {
21 | protected override fun onCreate(savedInstanceState: Bundle) {
22 | super.onCreate(savedInstanceState)
23 | }
24 |
25 | protected override fun onSaveInstanceState(outState: Bundle) {
26 | super.onSaveInstanceState(outState)
27 | StateSaver.saveInstanceState(this, outState)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityNoRestoreDirectImportKt.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint
12 |
13 | import android.app.Activity
14 | import android.os.Bundle
15 | import com.evernote.android.state.StateSaver.saveInstanceState
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | class InvalidActivityNoRestoreDirectImportKt : Activity() {
21 | protected override fun onCreate(savedInstanceState: Bundle) {
22 | super.onCreate(savedInstanceState)
23 | }
24 |
25 | protected override fun onSaveInstanceState(outState: Bundle) {
26 | super.onSaveInstanceState(outState)
27 | saveInstanceState(this, outState)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityNoRestore.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint;
12 |
13 | import android.app.Activity;
14 | import android.os.Bundle;
15 | import com.evernote.android.state.StateSaver;
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | public class InvalidActivityNoRestore extends Activity {
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | }
25 |
26 | @Override
27 | protected void onSaveInstanceState(Bundle outState) {
28 | super.onSaveInstanceState(outState);
29 | StateSaver.saveInstanceState(this, outState);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityNoSave.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint;
12 |
13 | import android.app.Activity;
14 | import android.os.Bundle;
15 | import com.evernote.android.state.StateSaver;
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | public class InvalidActivityNoSave extends Activity {
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | StateSaver.restoreInstanceState(this, savedInstanceState);
25 | }
26 |
27 | @Override
28 | protected void onSaveInstanceState(Bundle outState) {
29 | super.onSaveInstanceState(outState);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/ValidActivityKt.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint
12 |
13 | import android.app.Activity
14 | import android.os.Bundle
15 | import com.evernote.android.state.StateSaver
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | class ValidActivityKt : Activity() {
21 | protected override fun onCreate(savedInstanceState: Bundle) {
22 | super.onCreate(savedInstanceState)
23 | StateSaver.restoreInstanceState(this, savedInstanceState)
24 | }
25 |
26 | protected override fun onSaveInstanceState(outState: Bundle) {
27 | super.onSaveInstanceState(outState)
28 | StateSaver.saveInstanceState(this, outState)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/stub/StateSaver.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Frankie Sardo, and Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Frankie Sardo - initial API and implementation
10 | * Ralf Wondratschek - documentation and feature enhancement
11 | *******************************************************************************/
12 | package com.evernote.android.state;
13 |
14 | import android.os.Bundle;
15 |
16 | /**
17 | * Entry point to save and restore objects.
18 | */
19 | @SuppressWarnings({"WeakerAccess", "unused"})
20 | public final class StateSaver {
21 | public static void saveInstanceState(T target, Bundle state) {
22 | // STUB
23 | }
24 | public static void restoreInstanceState(T target, Bundle state) {
25 | // STUB
26 | }
27 |
28 | private StateSaver() {
29 | throw new UnsupportedOperationException();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityNoRestoreDirectImport.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint;
12 |
13 | import android.app.Activity;
14 | import android.os.Bundle;
15 |
16 | import com.evernote.android.state.StateSaver.saveInstanceState;
17 |
18 | /**
19 | * @author rwondratschek
20 | */
21 | public class InvalidActivityNoRestoreDirectImport extends Activity {
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | }
26 |
27 | @Override
28 | protected void onSaveInstanceState(Bundle outState) {
29 | super.onSaveInstanceState(outState);
30 | saveInstanceState(this, outState);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/ValidActivity.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint;
12 |
13 | import android.app.Activity;
14 | import android.os.Bundle;
15 | import com.evernote.android.state.StateSaver;
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | public class ValidActivity extends Activity {
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | StateSaver.restoreInstanceState(this, savedInstanceState);
25 | }
26 |
27 | @Override
28 | protected void onSaveInstanceState(Bundle outState) {
29 | super.onSaveInstanceState(outState);
30 | StateSaver.saveInstanceState(this, outState);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/State.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Frankie Sardo, and Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Frankie Sardo - initial API and implementation
10 | * Ralf Wondratschek - documentation and feature enhancement
11 | *******************************************************************************/
12 | package com.evernote.android.state;
13 |
14 | import android.os.Bundle;
15 |
16 | import java.lang.annotation.ElementType;
17 | import java.lang.annotation.Retention;
18 | import java.lang.annotation.RetentionPolicy;
19 | import java.lang.annotation.Target;
20 |
21 | /**
22 | * Fields or properties with this annotation will be saved in a {@link Bundle} and restored
23 | * from it while using the {@link StateSaver}.
24 | */
25 | @Target(ElementType.FIELD)
26 | @Retention(RetentionPolicy.CLASS)
27 | public @interface State {
28 | Class extends Bundler> value() default Bundler.class;
29 | }
30 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityOtherMethodKt.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint
12 |
13 | import android.app.Activity
14 | import android.os.Bundle
15 | import com.evernote.android.state.StateSaver
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | class InvalidActivityOtherMethodKt : Activity() {
21 | protected override fun onCreate(savedInstanceState: Bundle) {
22 | super.onCreate(savedInstanceState)
23 | restoreInstanceState()
24 | }
25 |
26 | protected override fun onSaveInstanceState(outState: Bundle) {
27 | super.onSaveInstanceState(outState)
28 | StateSaver.saveInstanceState(this, outState)
29 | }
30 |
31 | private fun restoreInstanceState() {
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestPrivateClassBundler.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import android.os.Bundle;
4 | //
5 | //import com.evernote.android.state.Bundler;
6 | //import com.evernote.android.state.State;
7 | //
8 | //public class TestPrivateClassBundler {
9 | // @State(MyBundler.class)
10 | // private Data mData2;
11 | //
12 | // public Data getData2() {
13 | // return mData2;
14 | // }
15 | //
16 | // public void setData2(Data data2) {
17 | // mData2 = data2;
18 | // }
19 | //
20 | // public static final class Data {
21 | // private int int1;
22 | // private int int2;
23 | // }
24 | //
25 | // private static final class MyBundler implements Bundler {
26 | // @Override
27 | // public void put(String key, Data value, Bundle bundle) {
28 | // bundle.putInt(key + "1", value.int1);
29 | // bundle.putInt(key + "2", value.int2);
30 | // }
31 | //
32 | // @Override
33 | // public Data get(String key, Bundle bundle) {
34 | // Data data = new Data();
35 | // data.int1 = bundle.getInt(key + "1");
36 | // data.int2 = bundle.getInt(key + "2");
37 | // return data;
38 | // }
39 | // }
40 | //}
41 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinEnum.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.test
12 |
13 | import com.evernote.android.state.State
14 | import com.evernote.android.state.StateReflection
15 |
16 | /**
17 | * Copyright 2017 Evernote Corporation. All rights reserved.
18 | *
19 | * Created by rwondratschek on 2/13/17.
20 | */
21 | enum class KotlinEnum {
22 | LEFT, RIGHT
23 | }
24 |
25 | class TestKotlinEnum {
26 | @State
27 | var kotlinEnum = KotlinEnum.LEFT
28 |
29 | @StateReflection
30 | private var kotlinEnum1 = KotlinEnum.LEFT
31 |
32 | fun getKotlinEnum1(): KotlinEnum {
33 | return kotlinEnum1
34 | }
35 |
36 | fun setKotlinEnum1(kotlinEnum: KotlinEnum) {
37 | kotlinEnum1 = kotlinEnum
38 | }
39 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestPrivateClassBundlerData.java:
--------------------------------------------------------------------------------
1 | //package com.evernote.android.state.test;
2 | //
3 | //import android.os.Bundle;
4 | //
5 | //import com.evernote.android.state.Bundler;
6 | //import com.evernote.android.state.State;
7 | //
8 | //public class TestPrivateClassBundlerData {
9 | // @State(MyBundler.class)
10 | // private Data mData2;
11 | //
12 | // public Data getData2() {
13 | // return mData2;
14 | // }
15 | //
16 | // public void setData2(Data data2) {
17 | // mData2 = data2;
18 | // }
19 | //
20 | // private static final class Data {
21 | // private int int1;
22 | // private int int2;
23 | // }
24 | //
25 | // public static final class MyBundler implements Bundler {
26 | // @Override
27 | // public void put(String key, Data value, Bundle bundle) {
28 | // bundle.putInt(key + "1", value.int1);
29 | // bundle.putInt(key + "2", value.int2);
30 | // }
31 | //
32 | // @Override
33 | // public Data get(String key, Bundle bundle) {
34 | // Data data = new Data();
35 | // data.int1 = bundle.getInt(key + "1");
36 | // data.int2 = bundle.getInt(key + "2");
37 | // return data;
38 | // }
39 | // }
40 | //}
41 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/ValidActivityDirectImportKt.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint
12 |
13 | import android.app.Activity
14 | import android.os.Bundle
15 | import com.evernote.android.state.StateSaver.saveInstanceState
16 | import com.evernote.android.state.StateSaver.restoreInstanceState
17 |
18 | /**
19 | * @author rwondratschek
20 | */
21 | class ValidActivityDirectImportKt : Activity() {
22 | protected override fun onCreate(savedInstanceState: Bundle) {
23 | super.onCreate(savedInstanceState)
24 | restoreInstanceState(this, savedInstanceState)
25 | }
26 |
27 | protected override fun onSaveInstanceState(outState: Bundle) {
28 | super.onSaveInstanceState(outState)
29 | saveInstanceState(this, outState)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/InvalidActivityOtherMethod.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint;
12 |
13 | import android.app.Activity;
14 | import android.os.Bundle;
15 | import com.evernote.android.state.StateSaver;
16 |
17 | /**
18 | * @author rwondratschek
19 | */
20 | public class InvalidActivityOtherMethod extends Activity {
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | restoreInstanceState();
25 | }
26 |
27 | @Override
28 | protected void onSaveInstanceState(Bundle outState) {
29 | super.onSaveInstanceState(outState);
30 | StateSaver.saveInstanceState(this, outState);
31 | }
32 |
33 | private void restoreInstanceState() {
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/demo-java-8/src/main/java/com/evernote/different/TestProguard.java:
--------------------------------------------------------------------------------
1 | package com.evernote.different;
2 | // different package to avoid clash with Proguard rules
3 |
4 | import com.evernote.android.state.State;
5 | import com.evernote.android.state.StateReflection;
6 |
7 | /**
8 | * @author rwondratschek
9 | */
10 | public class TestProguard {
11 |
12 | @State
13 | public int test1;
14 |
15 | @State
16 | private int test2;
17 |
18 | @StateReflection
19 | private int test3;
20 |
21 | public int getTest2() {
22 | return test2;
23 | }
24 |
25 | public void setTest2(int test2) {
26 | this.test2 = test2;
27 | }
28 |
29 | public void setValue(int value) {
30 | test1 = value;
31 | setTest2(value);
32 | test3 = value;
33 | }
34 |
35 | public void verifyValue(int value) {
36 | if (test1 != value) {
37 | throw new IllegalStateException("test1 different, expected " + value + ", is " + test1);
38 | }
39 | if (getTest2() != value) {
40 | throw new IllegalStateException("getTest2() different, expected " + value + ", is " + getTest2());
41 | }
42 | if (test3 != value) {
43 | throw new IllegalStateException("test3 different, expected " + value + ", is " + test3);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/library-lint/src/test/resources/java/ValidActivityDirectImport.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.lint;
12 |
13 | import android.app.Activity;
14 | import android.os.Bundle;
15 |
16 | import static com.evernote.android.state.StateSaver.restoreInstanceState;
17 | import static com.evernote.android.state.StateSaver.saveInstanceState;
18 |
19 | /**
20 | * @author rwondratschek
21 | */
22 | public class ValidActivityDirectImport extends Activity {
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | restoreInstanceState(this, savedInstanceState);
27 | }
28 |
29 | @Override
30 | protected void onSaveInstanceState(Bundle outState) {
31 | super.onSaveInstanceState(outState);
32 | saveInstanceState(this, outState);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinBundler.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test
2 |
3 | import android.os.Bundle
4 | import com.evernote.android.state.Bundler
5 | import com.evernote.android.state.State
6 | import java.io.Serializable
7 |
8 | /**
9 | * @author rwondratschek
10 | */
11 | class MyClass {
12 | @State(value = WrapperBundler::class)
13 | var wrapped = Wrapper(42)
14 |
15 | @State(value = WrapperBundlerGeneric::class)
16 | var wrappedGeneric = Wrapper(42)
17 | }
18 |
19 | class Wrapper(val content: T?)
20 |
21 | class WrapperBundler : Bundler> {
22 | override fun get(key: String, bundle: Bundle): Wrapper? {
23 | @Suppress("UNCHECKED_CAST")
24 | return Wrapper(bundle.getSerializable(key) as Serializable)
25 | }
26 |
27 | override fun put(key: String, value: Wrapper, bundle: Bundle) {
28 | bundle.putSerializable(key, value.content)
29 | }
30 | }
31 |
32 | class WrapperBundlerGeneric : Bundler> {
33 | override fun get(key: String, bundle: Bundle): Wrapper? {
34 | @Suppress("UNCHECKED_CAST")
35 | return Wrapper(bundle.getSerializable(key) as T)
36 | }
37 |
38 | override fun put(key: String, value: Wrapper, bundle: Bundle) {
39 | bundle.putSerializable(key, value.content)
40 | }
41 | }
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 | apply plugin: 'com.github.ben-manes.versions'
5 | apply from: "$rootDir/gradle/gradle-quality.gradle"
6 |
7 | android {
8 | compileSdkVersion rootProject.ext.compileSdkVersion
9 | buildToolsVersion rootProject.ext.buildToolsVersion
10 |
11 | defaultConfig {
12 | applicationId "com.evernote.android.state.demo"
13 |
14 | minSdkVersion rootProject.ext.minSdkVersion
15 | targetSdkVersion rootProject.ext.targetSdkVersion
16 |
17 | versionName project.VERSION_NAME
18 | versionCode Integer.parseInt(project.VERSION_CODE)
19 | }
20 |
21 | compileOptions {
22 | sourceCompatibility JavaVersion.VERSION_1_7
23 | targetCompatibility JavaVersion.VERSION_1_7
24 | }
25 |
26 | sourceSets {
27 | main.java.srcDirs += 'src/main/kotlin'
28 | test.java.srcDirs += 'src/test/kotlin'
29 | androidTest.java.srcDirs += 'src/androidTest/kotlin'
30 | }
31 |
32 | lintOptions {
33 | abortOnError true
34 | }
35 | }
36 |
37 | dependencies {
38 | implementation project(':library')
39 | kapt project(':processor')
40 | implementation "androidx.appcompat:appcompat:1.0.0"
41 |
42 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
43 | }
44 |
45 | uploadArchives.enabled false
46 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/StateReflection.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Frankie Sardo, and Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Frankie Sardo - initial API and implementation
10 | * Ralf Wondratschek - documentation and feature enhancement
11 | *******************************************************************************/
12 | package com.evernote.android.state;
13 |
14 | import android.os.Bundle;
15 |
16 | import java.lang.annotation.ElementType;
17 | import java.lang.annotation.Retention;
18 | import java.lang.annotation.RetentionPolicy;
19 | import java.lang.annotation.Target;
20 |
21 | /**
22 | * Fields or properties with this annotation will be saved in a {@link Bundle} and restored
23 | * from it while using the {@link StateSaver}. Compared to {@link State} this strategy relies
24 | * on reflection. If you can, you should use {@link State} instead.
25 | */
26 | @Target(ElementType.FIELD)
27 | @Retention(RetentionPolicy.CLASS)
28 | public @interface StateReflection {
29 | Class extends Bundler> value() default Bundler.class;
30 | }
31 |
--------------------------------------------------------------------------------
/library-lint/src/test/kotlin/com/evernote/android/state/lint/AbstractDetectorTest.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.lint
2 |
3 | import com.android.tools.lint.checks.infrastructure.LintDetectorTest
4 | import com.android.utils.SdkUtils
5 | import junit.framework.AssertionFailedError
6 | import java.io.File
7 | import java.io.InputStream
8 |
9 | abstract class AbstractDetectorTest : LintDetectorTest() {
10 | override fun getTestResource(relativePath: String, expectExists: Boolean): InputStream {
11 | val path = "resources/test/java/$relativePath".replace('/', File.separatorChar)
12 | return File(testDataRootDir, path).inputStream()
13 | }
14 |
15 | private val testDataRootDir: File
16 | get() {
17 | val source = javaClass.protectionDomain.codeSource
18 | val location = source.location
19 | val classesDir = SdkUtils.urlToFile(location)
20 | return classesDir.parentFile.absoluteFile.parentFile.parentFile
21 | }
22 |
23 | protected fun getTestFile(file: String) = TestFile().from(file, this).to(file)!!
24 |
25 | override fun tearDown() {
26 | try {
27 | super.tearDown()
28 | } catch (e: AssertionFailedError) {
29 | // this is weird 🤷
30 | if (e.message != "There was a crash during lint execution; consult log for details") {
31 | throw e
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestView.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import android.content.Context;
4 | import android.os.Parcelable;
5 | import android.view.View;
6 |
7 | import com.evernote.android.state.State;
8 | import com.evernote.android.state.StateSaver;
9 |
10 | public class TestView extends View {
11 |
12 | @State
13 | public int mState;
14 |
15 | public TestView(Context context) {
16 | super(context);
17 | }
18 |
19 | @Override
20 | protected Parcelable onSaveInstanceState() {
21 | return StateSaver.saveInstanceState(this, super.onSaveInstanceState());
22 | }
23 |
24 | @Override
25 | protected void onRestoreInstanceState(Parcelable state) {
26 | super.onRestoreInstanceState(StateSaver.restoreInstanceState(this, state));
27 | }
28 |
29 | public static class InnerView extends TestView {
30 |
31 | @State
32 | public int mStateInner;
33 |
34 | public InnerView(Context context) {
35 | super(context);
36 | }
37 |
38 | @Override
39 | protected Parcelable onSaveInstanceState() {
40 | return StateSaver.saveInstanceState(this, super.onSaveInstanceState());
41 | }
42 |
43 | @Override
44 | protected void onRestoreInstanceState(Parcelable state) {
45 | super.onRestoreInstanceState(StateSaver.restoreInstanceState(this, state));
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/bundlers/BundlerListString.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.bundlers;
12 |
13 | import android.os.Bundle;
14 | import androidx.annotation.NonNull;
15 | import androidx.annotation.Nullable;
16 |
17 | import com.evernote.android.state.Bundler;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * @author rwondratschek
24 | */
25 | public class BundlerListString implements Bundler> {
26 | @Override
27 | public void put(@NonNull String key, @NonNull List value, @NonNull Bundle bundle) {
28 | ArrayList arrayList = value instanceof ArrayList ? (ArrayList) value : new ArrayList<>(value);
29 | bundle.putStringArrayList(key, arrayList);
30 | }
31 |
32 | @Nullable
33 | @Override
34 | public List get(@NonNull String key, @NonNull Bundle bundle) {
35 | return bundle.getStringArrayList(key);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/bundlers/BundlerListInteger.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.bundlers;
12 |
13 | import android.os.Bundle;
14 | import androidx.annotation.NonNull;
15 | import androidx.annotation.Nullable;
16 |
17 | import com.evernote.android.state.Bundler;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * @author rwondratschek
24 | */
25 | public class BundlerListInteger implements Bundler> {
26 | @Override
27 | public void put(@NonNull String key, @NonNull List value, @NonNull Bundle bundle) {
28 | ArrayList arrayList = value instanceof ArrayList ? (ArrayList) value : new ArrayList<>(value);
29 | bundle.putIntegerArrayList(key, arrayList);
30 | }
31 |
32 | @Nullable
33 | @Override
34 | public List get(@NonNull String key, @NonNull Bundle bundle) {
35 | return bundle.getIntegerArrayList(key);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinComparable.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("unused")
2 |
3 | package com.evernote.android.state.test
4 |
5 | import com.evernote.android.state.State
6 | import java.io.Serializable
7 | import java.util.*
8 |
9 | /**
10 | * Copyright 2017 Evernote Corporation. All rights reserved.
11 | *
12 | * Created by rwondratschek on 3/1/17.
13 | */
14 | class MyComparator : Comparator, Serializable {
15 | override fun compare(o1: MyComparable, o2: MyComparable): Int = 0
16 | }
17 |
18 | class MyComparable : Comparable, Serializable {
19 | override fun compareTo(other: MyComparable): Int = 0
20 | }
21 |
22 | interface MyInterface> {
23 | fun doSomething(other: T)
24 | }
25 |
26 | class MyInterfaceImpl : MyInterface, Serializable {
27 | override fun doSomething(other: MyInterfaceImpl) {}
28 | }
29 |
30 | interface MySerializableInterface> : Serializable {
31 | fun doSomething(other: T)
32 | }
33 |
34 | class MySerializableImpl : MySerializableInterface {
35 | override fun doSomething(other: MySerializableImpl) {}
36 | }
37 |
38 | class TestKotlinComparable {
39 |
40 | @State
41 | var comparator: MyComparator? = null
42 |
43 | @State
44 | var comparable: MyComparable? = null
45 |
46 | @State
47 | var myInterface: MyInterfaceImpl? = null
48 |
49 | @State
50 | var mySerializableInterface: MySerializableImpl? = null
51 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/bundlers/BundlerListCharSequence.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.bundlers;
12 |
13 | import android.os.Bundle;
14 | import androidx.annotation.NonNull;
15 | import androidx.annotation.Nullable;
16 |
17 | import com.evernote.android.state.Bundler;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * @author rwondratschek
24 | */
25 | public class BundlerListCharSequence implements Bundler> {
26 | @Override
27 | public void put(@NonNull String key, @NonNull List value, @NonNull Bundle bundle) {
28 | ArrayList arrayList = value instanceof ArrayList ? (ArrayList) value : new ArrayList<>(value);
29 | bundle.putCharSequenceArrayList(key, arrayList);
30 | }
31 |
32 | @Nullable
33 | @Override
34 | public List get(@NonNull String key, @NonNull Bundle bundle) {
35 | return bundle.getCharSequenceArrayList(key);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestTypesReflection.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import android.os.Bundle;
4 | import android.os.Parcelable;
5 | import android.util.SparseArray;
6 |
7 | import com.evernote.android.state.StateReflection;
8 |
9 | import java.util.ArrayList;
10 |
11 | public class TestTypesReflection {
12 | @StateReflection
13 | private int mInt;
14 | @StateReflection
15 | private int[] mIntArray;
16 | @StateReflection
17 | private Integer mIntegerObj;
18 | @StateReflection
19 | private Bundle mBundle;
20 | @StateReflection
21 | private Parcelable[] mParcelableArray;
22 | @StateReflection
23 | private ArrayList extends TestTypes.ParcelableImpl> mParcelableArrayList;
24 | @StateReflection
25 | private SparseArray mParcelableSparseArray;
26 |
27 | public int getInt() {
28 | return mInt;
29 | }
30 |
31 | public void setInt(int anInt) {
32 | mInt = anInt;
33 | }
34 |
35 | public Integer getIntegerObj() {
36 | return mIntegerObj;
37 | }
38 |
39 | public void setIntegerObj(Integer integerObj) {
40 | mIntegerObj = integerObj;
41 | }
42 |
43 | public ArrayList extends TestTypes.ParcelableImpl> getParcelableArrayList() {
44 | return mParcelableArrayList;
45 | }
46 |
47 | public void setParcelableArrayList(ArrayList extends TestTypes.ParcelableImpl> parcelableArrayList) {
48 | mParcelableArrayList = parcelableArrayList;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestParcelableArray.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import com.evernote.android.state.State;
4 | import com.evernote.android.state.StateReflection;
5 |
6 | /**
7 | * @author rwondratschek
8 | */
9 | public class TestParcelableArray {
10 | @State
11 | public TestTypes.ParcelableImpl[] mParcelableArrayImpl1 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(0)};
12 |
13 | @State
14 | private TestTypes.ParcelableImpl[] mParcelableArrayImpl2 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(0)};
15 |
16 | @StateReflection
17 | private TestTypes.ParcelableImpl[] mParcelableArrayImpl3 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(0)};
18 |
19 | public TestTypes.ParcelableImpl[] getParcelableArrayImpl2() {
20 | return mParcelableArrayImpl2;
21 | }
22 |
23 | public void setParcelableArrayImpl2(TestTypes.ParcelableImpl[] parcelableArrayImpl2) {
24 | mParcelableArrayImpl2 = parcelableArrayImpl2;
25 | }
26 |
27 | public void setToValue(int value) {
28 | mParcelableArrayImpl1 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(value)};
29 | mParcelableArrayImpl2 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(value)};
30 | mParcelableArrayImpl3 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(value)};
31 | }
32 |
33 | public boolean isValue(int value) {
34 | return mParcelableArrayImpl1[0].isValue(value) && mParcelableArrayImpl2[0].isValue(value) && mParcelableArrayImpl3[0].isValue(value);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/bundlers/BundlerListParcelable.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.bundlers;
12 |
13 | import android.os.Bundle;
14 | import android.os.Parcelable;
15 | import androidx.annotation.NonNull;
16 | import androidx.annotation.Nullable;
17 |
18 | import com.evernote.android.state.Bundler;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * @author rwondratschek
25 | */
26 | public class BundlerListParcelable implements Bundler> {
27 | @SuppressWarnings("unchecked")
28 | @Override
29 | public void put(@NonNull String key, @NonNull List extends Parcelable> value, @NonNull Bundle bundle) {
30 | ArrayList extends Parcelable> arrayList = value instanceof ArrayList ? (ArrayList extends Parcelable>) value : new ArrayList<>(value);
31 | bundle.putParcelableArrayList(key, arrayList);
32 | }
33 |
34 | @Nullable
35 | @Override
36 | public List extends Parcelable> get(@NonNull String key, @NonNull Bundle bundle) {
37 | return bundle.getParcelableArrayList(key);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/library-lint/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'kotlin'
3 | apply from: "$rootDir/gradle/gradle-quality.gradle"
4 |
5 | archivesBaseName = 'android-state-lint'
6 |
7 | sourceCompatibility = JavaVersion.VERSION_1_7
8 | targetCompatibility = JavaVersion.VERSION_1_7
9 |
10 | dependencies {
11 | // Lint dependencies
12 | compileOnly "com.android.tools.lint:lint-api:$lintVersion"
13 | compileOnly "com.android.tools.lint:lint-checks:$lintVersion"
14 |
15 | // Kotlin
16 | compileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
17 | testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion"
18 |
19 | testImplementation "junit:junit:$junitVersion"
20 | testImplementation "org.assertj:assertj-core:$assertjVersion"
21 |
22 | // Lint test dependencies
23 | testImplementation "com.android.tools.lint:lint:$lintVersion"
24 | testImplementation "com.android.tools.lint:lint-tests:$lintVersion"
25 | testImplementation "com.android.tools:testutils:$lintVersion"
26 | }
27 |
28 | jar {
29 | baseName 'com.evernote.android.state.lint'
30 | version '1.0'
31 |
32 | manifest {
33 | attributes 'Manifest-Version': 1.0
34 | attributes 'Lint-Registry': 'com.evernote.android.state.lint.registry.StateIssueRegistry'
35 | }
36 |
37 | sourceSets {
38 | main {
39 | java.srcDirs += 'src/main/kotlin'
40 | }
41 | test {
42 | java.srcDirs += 'src/test/kotlin'
43 | }
44 | }
45 | }
46 |
47 | test {
48 | testLogging {
49 | showStandardStreams = true
50 | exceptionFormat = 'full'
51 | events "passed", "skipped", "failed", "standardOut", "standardError"
52 | }
53 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestBundler.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import android.os.Bundle;
4 | import androidx.annotation.NonNull;
5 | import androidx.annotation.Nullable;
6 |
7 | import com.evernote.android.state.Bundler;
8 | import com.evernote.android.state.State;
9 | import com.evernote.android.state.StateReflection;
10 |
11 | public class TestBundler {
12 |
13 | @State(MyBundler.class)
14 | private Data mData2;
15 |
16 | @StateReflection(value = MyBundler.class)
17 | private Data mDataReflOtherName;
18 |
19 | public Data getData2() {
20 | return mData2;
21 | }
22 |
23 | public void setData2(Data data2) {
24 | mData2 = data2;
25 | }
26 |
27 | public Data getDataRefl() {
28 | return mDataReflOtherName;
29 | }
30 |
31 | public void setDataRefl(Data data) {
32 | mDataReflOtherName = data;
33 | }
34 |
35 | public static final class Data {
36 | public int int1;
37 | public int int2;
38 | }
39 |
40 | public static final class MyBundler implements Bundler {
41 | @Override
42 | public void put(@NonNull String key, @NonNull Data value, @NonNull Bundle bundle) {
43 | bundle.putInt(key + "1", value.int1);
44 | bundle.putInt(key + "2", value.int2);
45 | }
46 |
47 | @Override
48 | @Nullable
49 | public Data get(@NonNull String key, @NonNull Bundle bundle) {
50 | if (bundle.containsKey(key + "1")) {
51 | Data data = new Data();
52 | data.int1 = bundle.getInt(key + "1");
53 | data.int2 = bundle.getInt(key + "2");
54 | return data;
55 | } else {
56 | return null;
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/Bundler.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Frankie Sardo, and Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Frankie Sardo - initial API and implementation
10 | * Ralf Wondratschek - documentation and feature enhancement
11 | *******************************************************************************/
12 | package com.evernote.android.state;
13 |
14 | import android.os.Bundle;
15 |
16 | import androidx.annotation.NonNull;
17 | import androidx.annotation.Nullable;
18 |
19 | /**
20 | * Helper interface to save any object inside a {@link Bundle}.
21 | *
22 | * @param The object class.
23 | */
24 | public interface Bundler {
25 |
26 | /**
27 | * Save the given value inside of the bundle.
28 | *
29 | * @param key The base key for this value. Each field of the value should have a separate key with this prefix.
30 | * @param value The object which should be saved in the bundle.
31 | * @param bundle The bundle where the value should be stored.
32 | */
33 | void put(@NonNull String key, @NonNull T value, @NonNull Bundle bundle);
34 |
35 | /**
36 | * Restore the value from the bundle.
37 | *
38 | * @param key The base key for this value. Each field of the value should have a separate key with this prefix.
39 | * @param bundle The bundle in which the value is stored.
40 | * @return The object restored from the bundle.
41 | */
42 | @Nullable
43 | T get(@NonNull String key, @NonNull Bundle bundle);
44 | }
45 |
--------------------------------------------------------------------------------
/gradle/gradle-quality.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'checkstyle'
2 | //apply plugin: 'findbugs'
3 | //apply plugin: 'pmd'
4 |
5 | check.dependsOn 'checkstyle'//, 'pmd' //,'findbugs'
6 |
7 | checkstyle {
8 | configFile file("${rootDir}/gradle/checkstyle/checkstyle.xml")
9 | }
10 |
11 | task checkstyle(type: Checkstyle) {
12 | source 'src'
13 | include '**/*.java'
14 | exclude '**/gen/**'
15 | exclude '**/test/resources/**'
16 | exclude '**/com/google/devtools/**'
17 |
18 | classpath = files()
19 | }
20 |
21 | task findbugs(type: FindBugs) {
22 | ignoreFailures = true
23 | effort = "max"
24 | reportLevel = "high"
25 | excludeFilter = new File("${project.rootDir}/build-config/findbugs/findbugs-filter.xml")
26 | classes = files("$project.buildDir/intermediates/classes/")
27 |
28 | source 'src'
29 | include '**/*.java'
30 | exclude '**/gen/**'
31 |
32 | reports {
33 | xml.enabled = false
34 | html.enabled = true
35 |
36 | xml {
37 | destination file("$project.buildDir/reports/findbugs/findbugs.xml")
38 | xml.withMessages true
39 | }
40 | html {
41 | destination file("$project.buildDir/reports/findbugs/findbugs.html")
42 | }
43 | }
44 |
45 | classpath = files()
46 | }
47 |
48 | task pmd(type: Pmd) {
49 | ruleSetFiles = files("${project.rootDir}/build-config/pmd/pmd-ruleset.xml")
50 | ignoreFailures = true
51 | ruleSets = ["java-basic", "java-braces", "java-strings"]
52 |
53 | source 'src'
54 | include '**/*.java'
55 | exclude '**/gen/**'
56 |
57 | reports {
58 | xml.enabled = true
59 | html.enabled = true
60 |
61 | xml {
62 | destination file("$project.buildDir/reports/pmd/pmd.xml")
63 | }
64 | html {
65 | destination file("$project.buildDir/reports/pmd/pmd.html")
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/demo/src/main/kotlin/com/evernote/android/state/demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek - initial version
10 | *******************************************************************************/
11 | package com.evernote.android.state.demo
12 |
13 | import android.os.Bundle
14 | import androidx.fragment.app.Fragment
15 | import androidx.fragment.app.FragmentActivity
16 | import android.util.Log
17 |
18 | import com.evernote.android.state.State
19 | import com.evernote.android.state.StateReflection
20 |
21 | /**
22 | * @author rwondratschek
23 | */
24 | class MainActivity : FragmentActivity() {
25 |
26 | @State
27 | var test1: Int = 0
28 |
29 | @StateReflection
30 | private var test2: Int = 0
31 |
32 | override fun onCreate(savedInstanceState: Bundle?) {
33 | super.onCreate(savedInstanceState)
34 | test1++
35 | test2++
36 |
37 | if (savedInstanceState == null) {
38 | supportFragmentManager.beginTransaction().add(TestFragment(), "Tag").commit()
39 | }
40 | }
41 |
42 | override fun onResume() {
43 | super.onResume()
44 | Log.i("MainActivity", "onResume mTest1=$test1 test2=$test2")
45 | }
46 | }
47 |
48 | class TestFragment : Fragment() {
49 |
50 | @State
51 | var test: Int = 0
52 |
53 | override fun onCreate(savedInstanceState: Bundle?) {
54 | super.onCreate(savedInstanceState)
55 | test++
56 | }
57 |
58 | override fun onResume() {
59 | super.onResume()
60 | Log.i("TestFragment", "onResume test=" + test)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/StateSaverTest.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state
2 |
3 | import android.os.Bundle
4 | import com.nhaarman.mockito_kotlin.anyOrNull
5 | import com.nhaarman.mockito_kotlin.eq
6 | import com.nhaarman.mockito_kotlin.never
7 | import com.nhaarman.mockito_kotlin.spy
8 | import com.nhaarman.mockito_kotlin.times
9 | import com.nhaarman.mockito_kotlin.verify
10 | import org.junit.FixMethodOrder
11 | import org.junit.Test
12 | import org.junit.runners.MethodSorters
13 |
14 |
15 | /**
16 | * @author rwondratschek
17 | */
18 | @FixMethodOrder(MethodSorters.JVM)
19 | class StateSaverTest {
20 |
21 | @Suppress("ReplacePutWithAssignment")
22 | @Test
23 | fun verifyClassIsResolvedOnlyOnce() {
24 | val injectors = spy, Injector>>(mutableMapOf())
25 | val stateSaver = StateSaverImpl(injectors)
26 |
27 | val savedObject = StateSaverTest()
28 | stateSaver.saveInstanceState(savedObject, Bundle())
29 | verify(injectors, times(1)).put(eq(StateSaverTest::class.java), anyOrNull())
30 |
31 | stateSaver.saveInstanceState(savedObject, Bundle())
32 | stateSaver.restoreInstanceState(savedObject, Bundle())
33 | verify(injectors, times(1)).put(eq(StateSaverTest::class.java), anyOrNull())
34 | }
35 |
36 | @Suppress("ReplacePutWithAssignment")
37 | @Test
38 | fun verifyJavaClassIsSkipped() {
39 | val injectors = spy, Injector>>(mutableMapOf())
40 | val stateSaver = StateSaverImpl(injectors)
41 |
42 | val savedObject = Any()
43 | stateSaver.saveInstanceState(savedObject, Bundle())
44 | verify(injectors, never()).put(anyOrNull(), anyOrNull())
45 | }
46 |
47 | @Suppress("ReplacePutWithAssignment")
48 | @Test
49 | fun verifyAndroidClassIsSkipped() {
50 | val injectors = spy, Injector>>(mutableMapOf())
51 | val stateSaver = StateSaverImpl(injectors)
52 |
53 | val savedObject = Bundle()
54 | stateSaver.saveInstanceState(savedObject, Bundle())
55 | verify(injectors, never()).put(anyOrNull(), anyOrNull())
56 | }
57 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/Injector.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Frankie Sardo, and Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Frankie Sardo - initial API and implementation
10 | * Ralf Wondratschek - documentation and feature enhancement
11 | *******************************************************************************/
12 | package com.evernote.android.state;
13 |
14 | import android.os.Bundle;
15 | import android.os.Parcelable;
16 |
17 | public class Injector {
18 |
19 | protected Injector() {
20 | }
21 |
22 | public abstract static class Object extends Injector {
23 | /*package*/ static final Object> DEFAULT = new Object() {
24 | @Override
25 | public void restore(java.lang.Object target, Bundle state) {
26 | // no op
27 | }
28 |
29 | @Override
30 | public void save(java.lang.Object target, Bundle state) {
31 | // no op
32 | }
33 | };
34 |
35 | public abstract void restore(T target, Bundle state);
36 |
37 | public abstract void save(T target, Bundle state);
38 | }
39 |
40 | public abstract static class View extends Injector {
41 |
42 | /*package*/ static final View> DEFAULT = new View() {
43 | @Override
44 | public Parcelable restore(java.lang.Object target, Parcelable state) {
45 | return state;
46 | }
47 |
48 | @Override
49 | public Parcelable save(java.lang.Object target, Parcelable state) {
50 | return state;
51 | }
52 | };
53 |
54 | public abstract Parcelable restore(T target, Parcelable state);
55 |
56 | public abstract Parcelable save(T target, Parcelable state);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinList.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.test
12 |
13 | import com.evernote.android.state.State
14 | import com.evernote.android.state.bundlers.BundlerListInteger
15 | import com.evernote.android.state.bundlers.BundlerListParcelable
16 | import com.evernote.android.state.bundlers.BundlerListString
17 | import java.io.Serializable
18 |
19 | /**
20 | * Copyright 2017 Evernote Corporation. All rights reserved.
21 | *
22 | * Created by rwondratschek on 2/13/17.
23 | */
24 | class TestKotlinList {
25 |
26 | @State(BundlerListString::class)
27 | var stringList = listOf("Hello", "World")
28 |
29 | @State(BundlerListInteger::class)
30 | var emptyList = emptyList()
31 |
32 | @State(BundlerListParcelable::class)
33 | var parcelableList = mutableListOf(TestTypes.ParcelableImpl(1))
34 |
35 | @State @Suppress("unused")
36 | var innerClass: TestKotlinInnerClass.Inner? = null
37 |
38 | @State(BundlerListParcelable::class)
39 | var nullableList: List? = null
40 |
41 | @State(BundlerListParcelable::class)
42 | lateinit var lateInitList: List
43 |
44 | @State
45 | var nullableArrayList: ArrayList? = null
46 |
47 | @State
48 | lateinit var lateInitArrayList: ArrayList
49 |
50 | @State
51 | var mParcelable: TestTypes.ParcelableImpl? = null
52 |
53 | @State
54 | var arrayListString = arrayListOf("Hello", "World")
55 |
56 | @State
57 | var arrayListSerializable = arrayListOf()
58 | }
59 |
60 | class MySerializable : TestView(null), Serializable
--------------------------------------------------------------------------------
/demo-java-8/src/androidTest/java/com/evernote/android/state/test/java8/ProguardTest.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test.java8;
2 |
3 | import android.os.Bundle;
4 | import android.support.test.runner.AndroidJUnit4;
5 |
6 | import com.evernote.android.state.StateSaver;
7 | import com.evernote.different.TestProguard;
8 | import com.evernote.different.TestProguardBundler;
9 | import com.evernote.different.TestProguardHelper;
10 |
11 | import org.junit.Test;
12 | import org.junit.runner.RunWith;
13 |
14 | /**
15 | * @author rwondratschek
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ProguardTest {
19 |
20 | @Test
21 | public void testProguardRules() {
22 | TestProguard data = new TestProguard();
23 | TestProguardHelper.verifyValue(data, 0);
24 | TestProguardHelper.setValue(data, 1);
25 |
26 | Bundle bundle = new Bundle();
27 | StateSaver.saveInstanceState(data, bundle);
28 |
29 | TestProguardHelper.setValue(data, 0);
30 | TestProguardHelper.verifyValue(data, 0);
31 |
32 | StateSaver.restoreInstanceState(data, bundle);
33 | TestProguardHelper.verifyValue(data, 1);
34 | }
35 |
36 | @Test
37 | public void verifyCodeObfuscated() throws Exception {
38 | TestProguard.class.getDeclaredField("test1"); // test1
39 | // TestProguard.class.getDeclaredField("a"); // test2
40 | TestProguard.class.getDeclaredField("test2"); // test2
41 | TestProguard.class.getDeclaredField("test3");
42 | TestProguard.class.getDeclaredMethod("a"); // getTest2()
43 |
44 | // TestProguardBundler.class.getDeclaredField("a"); // mData2
45 | TestProguardBundler.class.getDeclaredField("mData2"); // mData2
46 | TestProguardBundler.class.getDeclaredField("mDataReflOtherName");
47 | TestProguardBundler.class.getDeclaredMethod("a"); // getData2()
48 | }
49 |
50 | @Test
51 | public void testBundler() {
52 | TestProguardBundler data = new TestProguardBundler();
53 | data.verifyValue(0);
54 |
55 | data.setValue(1);
56 |
57 | Bundle bundle = new Bundle();
58 | StateSaver.saveInstanceState(data, bundle);
59 |
60 | data.setValue(0);
61 | data.verifyValue(0);
62 |
63 | StateSaver.restoreInstanceState(data, bundle);
64 | data.verifyValue(1);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestJavaList.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.test;
12 |
13 | import com.evernote.android.state.State;
14 | import com.evernote.android.state.bundlers.BundlerListInteger;
15 | import com.evernote.android.state.bundlers.BundlerListParcelable;
16 | import com.evernote.android.state.bundlers.BundlerListString;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | /**
23 | * @author rwondratschek
24 | */
25 | public class TestJavaList {
26 |
27 | @State(BundlerListString.class)
28 | private List stringList = Collections.unmodifiableList(new ArrayList(){{
29 | add("Hello");
30 | add("World");
31 | }});
32 |
33 | @State(BundlerListInteger.class)
34 | private List emptyList = Collections.emptyList();
35 |
36 | @State(BundlerListParcelable.class)
37 | private List parcelableList = Collections.singletonList(new TestTypes.ParcelableImpl(1));
38 |
39 | @State(BundlerListParcelable.class)
40 | List parcelableListPublic = Collections.singletonList(new TestTypes.ParcelableImpl(1));
41 |
42 | public List getStringList() {
43 | return stringList;
44 | }
45 |
46 | public void setStringList(List stringList) {
47 | this.stringList = stringList;
48 | }
49 |
50 | public List getEmptyList() {
51 | return emptyList;
52 | }
53 |
54 | public void setEmptyList(List emptyList) {
55 | this.emptyList = emptyList;
56 | }
57 |
58 | public List getParcelableList() {
59 | return parcelableList;
60 | }
61 |
62 | public void setParcelableList(List parcelableList) {
63 | this.parcelableList = parcelableList;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/demo-java-8/src/main/java/com/evernote/different/TestProguardBundler.java:
--------------------------------------------------------------------------------
1 | package com.evernote.different;
2 |
3 | import android.os.Bundle;
4 | import androidx.annotation.Keep;
5 | import androidx.annotation.NonNull;
6 | import androidx.annotation.Nullable;
7 |
8 | import com.evernote.android.state.Bundler;
9 | import com.evernote.android.state.State;
10 | import com.evernote.android.state.StateReflection;
11 |
12 | public class TestProguardBundler {
13 |
14 | @State(MyBundler.class)
15 | private Data mData2 = new Data();
16 |
17 | @StateReflection(value = MyBundler.class)
18 | private Data mDataReflOtherName = new Data();
19 |
20 | public Data getData2() {
21 | return mData2;
22 | }
23 |
24 | public void setData2(Data data2) {
25 | mData2 = data2;
26 | }
27 |
28 | @Keep
29 | public void setValue(int value) {
30 | mData2.int1 = value;
31 | mData2.int2 = value;
32 | mDataReflOtherName.int1 = value;
33 | mDataReflOtherName.int2 = value;
34 | }
35 |
36 | @Keep
37 | public void verifyValue(int value) {
38 | if (mData2.int1 != value) {
39 | throw new IllegalStateException();
40 | }
41 | if (mData2.int2 != value) {
42 | throw new IllegalStateException();
43 | }
44 | if (mDataReflOtherName.int1 != value) {
45 | throw new IllegalStateException();
46 | }
47 | if (mDataReflOtherName.int2 != value) {
48 | throw new IllegalStateException();
49 | }
50 | }
51 |
52 | public static final class Data {
53 | public int int1;
54 | public int int2;
55 | }
56 |
57 | public static final class MyBundler implements Bundler {
58 | @Override
59 | public void put(@NonNull String key, @NonNull Data value, @NonNull Bundle bundle) {
60 | bundle.putInt(key + "1", value.int1);
61 | bundle.putInt(key + "2", value.int2);
62 | }
63 |
64 | @Override
65 | @Nullable
66 | public Data get(@NonNull String key, @NonNull Bundle bundle) {
67 | if (bundle.containsKey(key + "1")) {
68 | Data data = new Data();
69 | data.int1 = bundle.getInt(key + "1");
70 | data.int2 = bundle.getInt(key + "2");
71 | return data;
72 | } else {
73 | return null;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/AndroidLifecycleCallbacks.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state;
2 |
3 | import android.app.Activity;
4 | import android.app.Application.ActivityLifecycleCallbacks;
5 | import android.os.Bundle;
6 |
7 | import androidx.fragment.app.Fragment;
8 | import androidx.fragment.app.FragmentActivity;
9 | import androidx.fragment.app.FragmentManager;
10 |
11 | /**
12 | * @author rwondratschek
13 | */
14 | /*package*/ final class AndroidLifecycleCallbacks extends FragmentManager.FragmentLifecycleCallbacks implements ActivityLifecycleCallbacks {
15 |
16 | static final AndroidLifecycleCallbacks INSTANCE = new AndroidLifecycleCallbacks();
17 |
18 | boolean mEnabled; // the extra flag is necessary in case this feature gets disabled, then we still can receive some callbacks for fragments
19 |
20 | private AndroidLifecycleCallbacks() {
21 |
22 | }
23 |
24 | @Override
25 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
26 | if (mEnabled) {
27 | StateSaver.restoreInstanceState(activity, savedInstanceState);
28 | }
29 |
30 | if (activity instanceof FragmentActivity) {
31 | ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(this, true);
32 | }
33 | }
34 |
35 | @Override
36 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
37 | if (mEnabled) {
38 | StateSaver.saveInstanceState(activity, outState);
39 | }
40 | }
41 |
42 | @Override
43 | public void onFragmentPreCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
44 | if (mEnabled) {
45 | StateSaver.restoreInstanceState(f, savedInstanceState);
46 | }
47 | }
48 |
49 | @Override
50 | public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
51 | if (mEnabled) {
52 | StateSaver.saveInstanceState(f, outState);
53 | }
54 | }
55 |
56 | @Override
57 | public void onActivityStarted(Activity activity) {
58 | }
59 |
60 | @Override
61 | public void onActivityResumed(Activity activity) {
62 | }
63 |
64 | @Override
65 | public void onActivityPaused(Activity activity) {
66 | }
67 |
68 | @Override
69 | public void onActivityStopped(Activity activity) {
70 | }
71 |
72 | @Override
73 | public void onActivityDestroyed(Activity activity) {
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 |
--------------------------------------------------------------------------------
/demo-java-8/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.github.ben-manes.versions'
3 | apply plugin: 'de.mobilej.unmock'
4 | apply from: "$rootDir/gradle/gradle-quality.gradle"
5 |
6 | android {
7 | compileSdkVersion rootProject.ext.compileSdkVersion
8 | buildToolsVersion rootProject.ext.buildToolsVersion
9 |
10 | defaultConfig {
11 | applicationId "com.evernote.android.state.demo.java8"
12 |
13 | minSdkVersion rootProject.ext.minSdkVersion
14 | targetSdkVersion rootProject.ext.targetSdkVersion
15 |
16 | versionName project.VERSION_NAME
17 | versionCode Integer.parseInt(project.VERSION_CODE)
18 |
19 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
20 | }
21 |
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 |
27 | testOptions {
28 | unitTests.returnDefaultValues = true
29 | unitTests.includeAndroidResources = true
30 | unitTests.all {
31 | testLogging {
32 | events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
33 | }
34 | }
35 | }
36 |
37 | buildTypes {
38 | debug {
39 | minifyEnabled true
40 | testProguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard.cfg'
41 | }
42 |
43 | release {
44 | minifyEnabled true
45 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard.cfg'
46 | }
47 | }
48 |
49 | lintOptions {
50 | abortOnError true
51 | }
52 | }
53 |
54 | dependencies {
55 | implementation project(':library')
56 | annotationProcessor project(':processor')
57 |
58 | implementation "androidx.appcompat:appcompat:1.0.0"
59 |
60 | androidTestImplementation "androidx.annotation:annotation:1.0.0"
61 | androidTestImplementation "com.android.support.test:runner:$testRuleVersion"
62 | androidTestImplementation "com.android.support.test:rules:testRuleVersion"
63 | androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
64 | androidTestImplementation "com.squareup.assertj:assertj-android:$assertjAndroidVersion"
65 |
66 | testImplementation "junit:junit:$junitVersion"
67 | testImplementation "org.assertj:assertj-core:$assertjVersion"
68 |
69 | unmock rootProject.ext.unmockVersion
70 | }
71 |
72 | uploadArchives.enabled false
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinPrivateInnerClass.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test
2 |
3 | import android.os.Parcel
4 | import android.os.Parcelable
5 | import com.evernote.android.state.StateReflection
6 |
7 | /**
8 | * @author rwondratschek
9 | */
10 | class TestKotlinPrivateInnerClass {
11 | @StateReflection
12 | private var inner= Inner.A
13 |
14 | @StateReflection
15 | private var parcelable = ParcelableImpl(1)
16 |
17 | @StateReflection
18 | private var innerList = arrayListOf(Inner.A)
19 |
20 | @StateReflection
21 | private var parcelableList = arrayListOf(ParcelableImpl(1))
22 |
23 | init {
24 | setToA()
25 | }
26 |
27 | fun setToA() {
28 | inner = Inner.A
29 | parcelable = ParcelableImpl(1)
30 | innerList = arrayListOf(Inner.A)
31 | parcelableList = arrayListOf(ParcelableImpl(1))
32 | }
33 |
34 | fun setToB() {
35 | inner = Inner.B
36 | parcelable = ParcelableImpl(2)
37 | innerList = arrayListOf(Inner.B)
38 | parcelableList = arrayListOf(ParcelableImpl(2))
39 | }
40 |
41 | fun isA(): Boolean {
42 | return inner == Inner.A && parcelable.value == 1 && innerList[0] == Inner.A && parcelableList[0].value == 1
43 | }
44 |
45 | fun isB(): Boolean {
46 | return inner == Inner.B && parcelable.value == 2 && innerList[0] == Inner.B && parcelableList[0].value == 2
47 | }
48 |
49 | private enum class Inner {
50 | A, B
51 | }
52 |
53 | private class ParcelableImpl : Parcelable {
54 | var value: Int = 0
55 |
56 | constructor(anInt: Int) {
57 | value = anInt
58 | }
59 |
60 | protected constructor(`in`: Parcel) {
61 | value = `in`.readInt()
62 | }
63 |
64 | override fun equals(o: Any?): Boolean {
65 | if (this === o) return true
66 | if (o == null || javaClass != o.javaClass) return false
67 |
68 | val that = o as ParcelableImpl?
69 |
70 | return value == that!!.value
71 | }
72 |
73 | override fun hashCode(): Int {
74 | return value
75 | }
76 |
77 | override fun writeToParcel(dest: Parcel, flags: Int) {
78 | dest.writeInt(value)
79 | }
80 |
81 | override fun describeContents(): Int {
82 | return 0
83 | }
84 |
85 | companion object {
86 |
87 | val CREATOR: Parcelable.Creator = object : Parcelable.Creator {
88 | override fun createFromParcel(`in`: Parcel): ParcelableImpl {
89 | return ParcelableImpl(`in`)
90 | }
91 |
92 | override fun newArray(size: Int): Array {
93 | return arrayOfNulls(size)
94 | }
95 | }
96 | }
97 | }
98 |
99 | }
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.ben-manes.versions'
3 | apply plugin: 'kotlin-android'
4 | apply plugin: 'kotlin-kapt'
5 | apply plugin: 'de.mobilej.unmock'
6 | apply from: "$rootDir/gradle/gradle-quality.gradle"
7 |
8 | archivesBaseName = 'android-state'
9 |
10 | android {
11 | compileSdkVersion rootProject.ext.compileSdkVersion
12 | buildToolsVersion rootProject.ext.buildToolsVersion
13 |
14 | resourcePrefix 'state_'
15 |
16 | useLibrary 'android.test.mock'
17 |
18 | defaultConfig {
19 | minSdkVersion rootProject.ext.minSdkVersion
20 | targetSdkVersion rootProject.ext.targetSdkVersion
21 |
22 | versionName project.VERSION_NAME
23 | versionCode Integer.parseInt(project.VERSION_CODE)
24 |
25 | consumerProguardFiles 'proguard.cfg'
26 |
27 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
28 | }
29 |
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_7
32 | targetCompatibility JavaVersion.VERSION_1_7
33 | }
34 |
35 | lintOptions {
36 | abortOnError true
37 | }
38 |
39 | sourceSets {
40 | //main.java.srcDirs += 'src/main/kotlin'
41 | test.java.srcDirs += 'src/test/kotlin'
42 | androidTest.java.srcDirs += 'src/androidTest/kotlin'
43 | }
44 |
45 | testOptions {
46 | unitTests.returnDefaultValues = true
47 | unitTests.includeAndroidResources = true
48 | unitTests.all {
49 | testLogging {
50 | events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
51 | }
52 | }
53 | }
54 | }
55 |
56 | dependencies {
57 | implementation "androidx.fragment:fragment:1.0.0"
58 | lintChecks project(':library-lint')
59 |
60 | testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
61 |
62 | testImplementation "junit:junit:$junitVersion"
63 | testImplementation "org.assertj:assertj-core:$assertjVersion"
64 | testImplementation "com.nhaarman:mockito-kotlin-kt1.1:$kotlinMockitoVersion"
65 | testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion"
66 | testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion"
67 |
68 | kaptTest project(':processor')
69 |
70 | androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
71 | androidTestImplementation "androidx.annotation:annotation:1.0.0"
72 | androidTestImplementation "com.android.support.test:runner:$testRuleVersion"
73 | androidTestImplementation "com.android.support.test:rules:$testRuleVersion"
74 | androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
75 | androidTestImplementation "com.squareup.assertj:assertj-android:$assertjAndroidVersion"
76 |
77 | kaptAndroidTest project(':processor')
78 |
79 | //noinspection GradleDependency
80 | unmock rootProject.ext.unmockVersion
81 | }
82 |
83 | apply from: "$rootDir/gradle/gradle-push.gradle"
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestPrivateInnerClass.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.evernote.android.state.StateReflection;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Collections;
10 |
11 | /**
12 | * @author rwondratschek
13 | */
14 | public class TestPrivateInnerClass {
15 |
16 | @StateReflection
17 | private Inner mInner2;
18 |
19 | @StateReflection
20 | private ParcelableImpl mParcelable2;
21 |
22 | @StateReflection
23 | private ArrayList mInnerList = new ArrayList<>();
24 |
25 | @StateReflection
26 | private ArrayList mParcelableList = new ArrayList<>();
27 |
28 | public TestPrivateInnerClass() {
29 | setToA();
30 | }
31 |
32 | public void setToA() {
33 | mInner2 = Inner.A;
34 | mParcelable2 = new ParcelableImpl(1);
35 | mInnerList = new ArrayList<>(Collections.singletonList(Inner.A));
36 | mParcelableList = new ArrayList<>(Collections.singletonList(new ParcelableImpl(1)));
37 | }
38 |
39 | public void setToB() {
40 | mInner2 = Inner.B;
41 | mParcelable2 = new ParcelableImpl(2);
42 | mInnerList = new ArrayList<>(Collections.singletonList(Inner.B));
43 | mParcelableList = new ArrayList<>(Collections.singletonList(new ParcelableImpl(2)));
44 | }
45 |
46 | public boolean isA() {
47 | return mInner2 == Inner.A && mParcelable2.mInt == 1 && mInnerList.get(0) == Inner.A && mParcelableList.get(0).mInt == 1;
48 | }
49 |
50 | public boolean isB() {
51 | return mInner2 == Inner.B && mParcelable2.mInt == 2 && mInnerList.get(0) == Inner.B && mParcelableList.get(0).mInt == 2;
52 | }
53 |
54 | private enum Inner {
55 | A, B
56 | }
57 |
58 | private static class ParcelableImpl implements Parcelable {
59 | private int mInt;
60 |
61 | public ParcelableImpl(int anInt) {
62 | mInt = anInt;
63 | }
64 |
65 | protected ParcelableImpl(Parcel in) {
66 | mInt = in.readInt();
67 | }
68 |
69 | @Override
70 | public boolean equals(Object o) {
71 | if (this == o) return true;
72 | if (o == null || getClass() != o.getClass()) return false;
73 |
74 | ParcelableImpl that = (ParcelableImpl) o;
75 |
76 | return mInt == that.mInt;
77 | }
78 |
79 | @Override
80 | public int hashCode() {
81 | return mInt;
82 | }
83 |
84 | @Override
85 | public void writeToParcel(Parcel dest, int flags) {
86 | dest.writeInt(mInt);
87 | }
88 |
89 | @Override
90 | public int describeContents() {
91 | return 0;
92 | }
93 |
94 | public static final Creator CREATOR = new Creator() {
95 | @Override
96 | public ParcelableImpl createFromParcel(Parcel in) {
97 | return new ParcelableImpl(in);
98 | }
99 |
100 | @Override
101 | public ParcelableImpl[] newArray(int size) {
102 | return new ParcelableImpl[size];
103 | }
104 | };
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.4.1 (2018-10-06)
2 |
3 | * Remove Android dependency from processor, this resolves problems with the Jetifier, see #56
4 |
5 | ## 1.4.0 (2018-09-23)
6 |
7 | * Migrated dependencies to AndroidX
8 | * Sort elements by name to make processor deterministic, see #57 (Thanks @DSteve595)
9 | * Fix compile error with generic inner classes and kapt, see #54 (Thanks @janbina)
10 |
11 | ## 1.3.1 (2018-06-10)
12 |
13 | * Avoid obfuscating the class name if the class contains a field annotated with `@State`, see #43
14 | * Don't use the serializable type for parcelable arrays, see #53
15 |
16 | ## 1.3.0 (2018-05-28)
17 |
18 | * Support incremental annotation processing, see #48
19 | * Omit the type for private inner classes when using reflection, see #44
20 |
21 | ## 1.2.1 (2018-03-18)
22 |
23 | * Fix an issue with kapt where a class cannot be found, see #42
24 | * Fix problems with the Proguard rules and allow better obfuscation, see #43
25 |
26 | ## 1.2.0 (2018-02-02)
27 |
28 | * Add the option to automatically save the instance state of all activities and fragments from the support library
29 | * Support Kotlin in Lint checks
30 |
31 | ## 1.1.6 (2017-11-01)
32 |
33 | * Don't crash when the license header file cannot be read, see #35
34 |
35 | ## 1.1.5 (2017-08-31)
36 |
37 | * Handle generics in bundlers properly, see #32
38 |
39 | ## 1.1.4 (2017-08-18)
40 |
41 | * Add a small optimization, if the object doesn't contain any state variable, see #31
42 | * Fix potential `ClassCastException`, see #30
43 | * Serialize `ArrayList` if it contains `Serializable` elements, see #29
44 |
45 | ## 1.1.3 (2017-07-24)
46 |
47 | * Fix wrong handling of properties in Kotlin in Hungarian notation, see #26
48 |
49 | ## 1.1.2 (2017-07-11)
50 |
51 | * Fix nullable lists containing `Parcelable` elements in Kotlin, see #25
52 |
53 | ## 1.1.1 (2017-06-22)
54 |
55 | * Add a Proguard rule to keep the class name if the class contains a `State` or `StateReflection annoation`, see #23
56 | * Handle a generic `Serializable` or `Parcelable` properly, see #24
57 |
58 | ## 1.1.0 (2017-06-05)
59 |
60 | * Remove unnecessary Proguard rules prevent proper obfuscation, see #15
61 | * Add new annotation `StateReflection` to properly support obfuscation even though reflection is being used, see #15
62 | * Bundle library classes in annotation processor, see #13
63 | * Detect correct getter and setter for boolean properties with a "is" prefix in Kotlin, see #18
64 | * Add a Lint check to find matching save and restore calls to ensure a proper usage of the library
65 |
66 | ## 1.0.6 (2017-04-07)
67 |
68 | * Fix inner classes in Kotlin, see #11
69 | * Add a license header to each generated file, see #10
70 |
71 | ## 1.0.5 (2017-03-02)
72 |
73 | * Fix a Stackoverflow error when using Kotlin generics, see #9
74 |
75 | ## 1.0.4 (2017-02-24)
76 |
77 | * Fix a Stackoverflow error when using Kotlin enums, see #8
78 |
79 | ## 1.0.3 (2017-02-15)
80 |
81 | * Provide some `Bundler` implementations for lists, see #4
82 | * Add a workaround for the Jack compiler where the package name is always "package", may fix #5
83 | * Erase generics of extended classes, fixes #6
84 |
85 | ## 1.0.2 (2017-02-15)
86 |
87 | * NOT AVAILABLE because of Maven Central sync issues
88 |
89 | ## 1.0.1 (2017-01-27)
90 |
91 | * Insert missing casted type for `Parcelable` or `Serializable` getters
92 | * Allow `is` as getter prefix for boolean getters
93 |
94 | ## 1.0.0 (2017-01-26)
95 |
96 | * Initial release
--------------------------------------------------------------------------------
/demo-java-8/src/main/java/com/evernote/android/state/test/java8/TestTypes.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test.java8;
2 |
3 | import android.os.Bundle;
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 | import android.util.SparseArray;
7 |
8 | import com.evernote.android.state.State;
9 |
10 | import java.io.Serializable;
11 | import java.util.ArrayList;
12 |
13 | public class TestTypes {
14 | @State
15 | public boolean mBoolean;
16 | @State
17 | public boolean[] mBooleanArray;
18 | @State
19 | public Boolean mBooleanObj;
20 | @State
21 | public byte mByte;
22 | @State
23 | public byte[] mByteArray;
24 | @State
25 | public Byte mByteObj;
26 | @State
27 | public char mChar;
28 | @State
29 | public char[] mCharArray;
30 | @State
31 | public Character mCharObj;
32 | @State
33 | public double mDouble;
34 | @State
35 | public double[] mDoubleArray;
36 | @State
37 | public Double mDoubleObj;
38 | @State
39 | public float mFloat;
40 | @State
41 | public float[] mFloatArray;
42 | @State
43 | public Float mFloatObj;
44 | @State
45 | public int mInt;
46 | @State
47 | public int[] mIntArray;
48 | @State
49 | public Integer mIntegerObj;
50 | @State
51 | public long mLong;
52 | @State
53 | public long[] mLongArray;
54 | @State
55 | public Long mLongObj;
56 | @State
57 | public short mShort;
58 | @State
59 | public short[] mShortArray;
60 | @State
61 | public Short mShortObj;
62 | @State
63 | public CharSequence mCharSequence;
64 | @State
65 | public CharSequence[] mCharSequenceArray;
66 | @State
67 | public String mString;
68 | @State
69 | public String[] mStringArray;
70 | @State
71 | public ArrayList mCharSequenceArrayList;
72 | @State
73 | public ArrayList mIntegerArrayList;
74 | @State
75 | public ArrayList mStringArrayList;
76 | @State
77 | public Bundle mBundle;
78 | @State
79 | public Parcelable[] mParcelableArray;
80 | @State
81 | public ParcelableImpl mParcelableImpl;
82 | @State
83 | public SerializableImpl mSerializableImpl;
84 | @State
85 | public ArrayList mParcelableArrayList;
86 | @State
87 | public SparseArray mParcelableSparseArray;
88 |
89 | public static class ParcelableImpl implements Parcelable {
90 | private int mInt;
91 |
92 | public ParcelableImpl(int anInt) {
93 | mInt = anInt;
94 | }
95 |
96 | protected ParcelableImpl(Parcel in) {
97 | mInt = in.readInt();
98 | }
99 |
100 | @Override
101 | public boolean equals(Object o) {
102 | if (this == o) return true;
103 | if (o == null || getClass() != o.getClass()) return false;
104 |
105 | ParcelableImpl that = (ParcelableImpl) o;
106 |
107 | return mInt == that.mInt;
108 | }
109 |
110 | @Override
111 | public int hashCode() {
112 | return mInt;
113 | }
114 |
115 | @Override
116 | public void writeToParcel(Parcel dest, int flags) {
117 | dest.writeInt(mInt);
118 | }
119 |
120 | @Override
121 | public int describeContents() {
122 | return 0;
123 | }
124 |
125 | public static final Creator CREATOR = new Creator() {
126 | @Override
127 | public ParcelableImpl createFromParcel(Parcel in) {
128 | return new ParcelableImpl(in);
129 | }
130 |
131 | @Override
132 | public ParcelableImpl[] newArray(int size) {
133 | return new ParcelableImpl[size];
134 | }
135 | };
136 | }
137 |
138 | public static class SerializableImpl implements Serializable {
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestTypes.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import android.os.Bundle;
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 | import android.util.SparseArray;
7 |
8 | import com.evernote.android.state.State;
9 |
10 | import java.io.Serializable;
11 | import java.util.ArrayList;
12 |
13 | public class TestTypes {
14 | @State
15 | public boolean mBoolean;
16 | @State
17 | public boolean[] mBooleanArray;
18 | @State
19 | public Boolean mBooleanObj;
20 | @State
21 | public byte mByte;
22 | @State
23 | public byte[] mByteArray;
24 | @State
25 | public Byte mByteObj;
26 | @State
27 | public char mChar;
28 | @State
29 | public char[] mCharArray;
30 | @State
31 | public Character mCharObj;
32 | @State
33 | public double mDouble;
34 | @State
35 | public double[] mDoubleArray;
36 | @State
37 | public Double mDoubleObj;
38 | @State
39 | public float mFloat;
40 | @State
41 | public float[] mFloatArray;
42 | @State
43 | public Float mFloatObj;
44 | @State
45 | public int mInt;
46 | @State
47 | public int[] mIntArray;
48 | @State
49 | public Integer mIntegerObj;
50 | @State
51 | public long mLong;
52 | @State
53 | public long[] mLongArray;
54 | @State
55 | public Long mLongObj;
56 | @State
57 | public short mShort;
58 | @State
59 | public short[] mShortArray;
60 | @State
61 | public Short mShortObj;
62 | @State
63 | public CharSequence mCharSequence;
64 | @State
65 | public CharSequence[] mCharSequenceArray;
66 | @State
67 | public String mString;
68 | @State
69 | public String[] mStringArray;
70 | @State
71 | public ArrayList mCharSequenceArrayList;
72 | @State
73 | public ArrayList mIntegerArrayList;
74 | @State
75 | public ArrayList mStringArrayList;
76 | @State
77 | public Bundle mBundle;
78 | @State
79 | public Parcelable[] mParcelableArray;
80 | @State
81 | public ParcelableImpl mParcelableImpl;
82 | @State
83 | public SerializableImpl mSerializableImpl;
84 | @State
85 | public ArrayList mParcelableArrayList;
86 | @State
87 | public SparseArray mParcelableSparseArray;
88 |
89 | public static class ParcelableImpl implements Parcelable {
90 | private int mInt;
91 |
92 | public ParcelableImpl(int anInt) {
93 | mInt = anInt;
94 | }
95 |
96 | protected ParcelableImpl(Parcel in) {
97 | mInt = in.readInt();
98 | }
99 |
100 | public boolean isValue(int value) {
101 | return mInt == value;
102 | }
103 |
104 | @Override
105 | public boolean equals(Object o) {
106 | if (this == o) return true;
107 | if (o == null || getClass() != o.getClass()) return false;
108 |
109 | ParcelableImpl that = (ParcelableImpl) o;
110 |
111 | return mInt == that.mInt;
112 | }
113 |
114 | @Override
115 | public int hashCode() {
116 | return mInt;
117 | }
118 |
119 | @Override
120 | public void writeToParcel(Parcel dest, int flags) {
121 | dest.writeInt(mInt);
122 | }
123 |
124 | @Override
125 | public int describeContents() {
126 | return 0;
127 | }
128 |
129 | public static final Creator CREATOR = new Creator() {
130 | @Override
131 | public ParcelableImpl createFromParcel(Parcel in) {
132 | return new ParcelableImpl(in);
133 | }
134 |
135 | @Override
136 | public ParcelableImpl[] newArray(int size) {
137 | return new ParcelableImpl[size];
138 | }
139 | };
140 | }
141 |
142 | public static class SerializableImpl implements Serializable {
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/StateSaver.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Frankie Sardo, and Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Frankie Sardo - initial API and implementation
10 | * Ralf Wondratschek - documentation and feature enhancement
11 | *******************************************************************************/
12 | package com.evernote.android.state;
13 |
14 | import android.app.Application;
15 | import android.os.Bundle;
16 | import android.os.Parcelable;
17 | import androidx.annotation.NonNull;
18 | import androidx.annotation.Nullable;
19 | import android.view.View;
20 |
21 | import java.util.LinkedHashMap;
22 |
23 | /**
24 | * Entry point to save and restore objects.
25 | */
26 | @SuppressWarnings({"WeakerAccess", "unused"})
27 | public final class StateSaver {
28 |
29 | public static final String SUFFIX = "$$StateSaver";
30 | public static final String ANDROID_PREFIX = "android.";
31 | public static final String JAVA_PREFIX = "java.";
32 |
33 | private static final StateSaverImpl IMPL = new StateSaverImpl(new LinkedHashMap, Injector>());
34 |
35 | /**
36 | * Save the given {@code target} in the passed in {@link Bundle}.
37 | *
38 | * @param target The object containing fields annotated with {@link State}.
39 | * @param state The object is saved into this bundle.
40 | */
41 | public static void saveInstanceState(@NonNull T target, @NonNull Bundle state) {
42 | IMPL.saveInstanceState(target, state);
43 | }
44 |
45 | /**
46 | * Restore the given {@code target} from the passed in {@link Bundle}.
47 | *
48 | * @param target The object containing fields annotated with {@link State}.
49 | * @param state The object is being restored from this bundle. Nothing is restored if the argument is {@code null}.
50 | */
51 | public static void restoreInstanceState(@NonNull T target, @Nullable Bundle state) {
52 | IMPL.restoreInstanceState(target, state);
53 | }
54 |
55 | /**
56 | * Save the state of the given view and the other state inside of the returned {@link Parcelable}.
57 | *
58 | * @param target The view containing fields annotated with {@link State}.
59 | * @param state The super state of the parent class of the view. Usually it isn't {@code null}.
60 | * @return A parcelable containing the view's state and its super state.
61 | */
62 | @NonNull
63 | public static Parcelable saveInstanceState(@NonNull T target, @Nullable Parcelable state) {
64 | return IMPL.saveInstanceState(target, state);
65 | }
66 |
67 | /**
68 | * Restore the sate of the given view and return the super state of the parent class.
69 | *
70 | * @param target The view containing fields annotated with {@link State}.
71 | * @param state The parcelable containing the view's state and its super sate.
72 | * @return The super state of teh parent class of the view. Usually it isn't {@code null}.
73 | */
74 | @Nullable
75 | public static Parcelable restoreInstanceState(@NonNull T target, @Nullable Parcelable state) {
76 | return IMPL.restoreInstanceState(target, state);
77 | }
78 |
79 | /**
80 | * Turns automatic instance saving on or off for all activities and fragments from the support library. This avoids
81 | * manual calls of {@link #saveInstanceState(Object, Bundle)} and {@link #restoreInstanceState(Object, Bundle)}, instead
82 | * the library is doing this automatically for you. It's still necessary to annotate fields with {@link State}, though.
83 | *
84 | *
85 | * The best place to turn on this feature is in your {@link Application#onCreate()} method.
86 | *
87 | * @param application Your application instance.
88 | * @param enabled Whether this feature should be enabled.
89 | */
90 | public static void setEnabledForAllActivitiesAndSupportFragments(@NonNull Application application, boolean enabled) {
91 | IMPL.setEnabledForAllActivitiesAndSupportFragments(application, enabled);
92 | }
93 |
94 | private StateSaver() {
95 | throw new UnsupportedOperationException();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/demo-java-8/src/test/java/com/evernote/android/state/test/java8/Java8BundlingTest.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | package com.evernote.android.state.test.java8;
12 |
13 | import android.os.Bundle;
14 |
15 | import com.evernote.android.state.StateSaver;
16 |
17 | import org.junit.Before;
18 | import org.junit.FixMethodOrder;
19 | import org.junit.Test;
20 | import org.junit.runners.MethodSorters;
21 |
22 | import java.util.ArrayList;
23 |
24 | import static org.assertj.core.api.Assertions.assertThat;
25 |
26 | /**
27 | * @author rwondratschek
28 | */
29 | @FixMethodOrder(MethodSorters.JVM)
30 | public class Java8BundlingTest {
31 |
32 | private Bundle mBundle;
33 |
34 | @Before
35 | public void setUp() {
36 | mBundle = new Bundle();
37 | }
38 |
39 | @Test
40 | public void testTypes() {
41 | TestTypes object = createSavedInstance(TestTypes.class);
42 | object.mBooleanObj = Boolean.FALSE;
43 |
44 | StateSaver.restoreInstanceState(object, mBundle);
45 | assertThat(object.mBooleanObj).isNull();
46 |
47 | object.mInt = 5;
48 | object.mIntegerObj = 6;
49 | object.mParcelableArrayList = new ArrayList() {{
50 | add(new TestTypes.ParcelableImpl(7));
51 | }};
52 |
53 | StateSaver.saveInstanceState(object, mBundle);
54 | object.mInt = 0;
55 | object.mIntegerObj = null;
56 | object.mParcelableArrayList = null;
57 |
58 | StateSaver.restoreInstanceState(object, mBundle);
59 | assertThat(object.mInt).isEqualTo(5);
60 | assertThat(object.mIntegerObj).isNotNull().isEqualTo(6);
61 | assertThat(object.mParcelableArrayList).isNotNull().isNotEmpty().containsExactly(new TestTypes.ParcelableImpl(7));
62 | }
63 |
64 | @Test
65 | public void testTypesProperty() {
66 | TestTypesProperty object = createSavedInstance(TestTypesProperty.class);
67 | object.setBooleanObj(Boolean.FALSE);
68 |
69 | StateSaver.restoreInstanceState(object, mBundle);
70 | assertThat(object.getBooleanObj()).isNull();
71 |
72 | object.setInt(5);
73 | object.setIntegerObj(6);
74 | object.setParcelableImplExtension(new TestTypesProperty.ParcelableImplExtension(7, 8));
75 | object.setParcelableArrayList(new ArrayList() {{
76 | add(new TestTypes.ParcelableImpl(9));
77 | }});
78 |
79 | StateSaver.saveInstanceState(object, mBundle);
80 | object.setInt(0);
81 | object.setIntegerObj(0);
82 | object.setParcelableImplExtension(null);
83 | object.setParcelableArrayList(null);
84 |
85 | StateSaver.restoreInstanceState(object, mBundle);
86 | assertThat(object.getInt()).isEqualTo(5);
87 | assertThat(object.getIntegerObj()).isNotNull().isEqualTo(6);
88 | assertThat(object.getParcelableImplExtension()).isNotNull().isEqualTo(new TestTypesProperty.ParcelableImplExtension(7, 8));
89 | assertThat(object.getParcelableArrayList()).isNotNull().isNotEmpty().containsExactly(new TestTypes.ParcelableImpl(9));
90 | }
91 |
92 | @Test
93 | public void testNested() {
94 | TestNested.Inner1.InnerInner1 object1 = createSavedInstance(TestNested.Inner1.InnerInner1.class);
95 | TestNested.Inner2.InnerInner1 object2 = createSavedInstance(TestNested.Inner2.InnerInner1.class);
96 |
97 | object1.test = 5;
98 | object2.test = 5;
99 |
100 | StateSaver.restoreInstanceState(object1, mBundle);
101 | StateSaver.restoreInstanceState(object2, mBundle);
102 |
103 | assertThat(object1.test).isEqualTo(0);
104 | assertThat(object2.test).isEqualTo(0);
105 | }
106 |
107 | private T createSavedInstance(Class clazz) {
108 | try {
109 | T instance = clazz.newInstance();
110 | StateSaver.saveInstanceState(instance, mBundle);
111 | return instance;
112 | } catch (Exception e) {
113 | throw new RuntimeException(e);
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/library-lint/src/main/kotlin/com/evernote/android/state/lint/detector/AndroidStateDetector.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.lint.detector
2 |
3 | import com.android.tools.lint.client.api.UElementHandler
4 | import com.android.tools.lint.detector.api.Category
5 | import com.android.tools.lint.detector.api.Context
6 | import com.android.tools.lint.detector.api.Detector
7 | import com.android.tools.lint.detector.api.Implementation
8 | import com.android.tools.lint.detector.api.Issue
9 | import com.android.tools.lint.detector.api.JavaContext
10 | import com.android.tools.lint.detector.api.Scope
11 | import com.android.tools.lint.detector.api.Severity
12 | import org.jetbrains.uast.UCallExpression
13 | import org.jetbrains.uast.UDeclaration
14 | import org.jetbrains.uast.UElement
15 | import org.jetbrains.uast.getContainingUClass
16 | import org.jetbrains.uast.getContainingUFile
17 | import java.util.EnumSet
18 |
19 | /**
20 | * This detector crawls through the Java and Kotlin files and looks for non-matching instances of
21 | * saveInstanceState and restoreInstanceState for the StateSaver library.
22 | *
23 | * Created by junchengc on 5/15/17.
24 | */
25 | class AndroidStateDetector : Detector(), Detector.UastScanner {
26 | companion object Issues {
27 | private val IMPLEMENTATION = Implementation(AndroidStateDetector::class.java, Scope.JAVA_FILE_SCOPE)
28 | private const val ADVICE = "StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState()."
29 |
30 | @JvmField
31 | val ISSUE = Issue.create(
32 | "NonMatchingStateSaverCalls",
33 | ADVICE,
34 | "$ADVICE Failing to do so could result in weird behaviors after activity recreation where certain states are not persisted.",
35 | Category.CORRECTNESS,
36 | 6,
37 | Severity.WARNING,
38 | IMPLEMENTATION
39 | )
40 |
41 | private const val SAVE_INSTANCE_STATE_METHOD = "saveInstanceState"
42 | private const val RESTORE_INSTANCE_STATE_METHOD = "restoreInstanceState"
43 | private val APPLICABLE_METHODS = listOf(SAVE_INSTANCE_STATE_METHOD, RESTORE_INSTANCE_STATE_METHOD)
44 | private const val STATE_SAVER_CLASS_SIMPLE = "StateSaver"
45 | private const val STATE_SAVER_CLASS = "com.evernote.android.state.$STATE_SAVER_CLASS_SIMPLE"
46 | }
47 |
48 | private val saveCalls = mutableMapOf()
49 | private val restoreCalls = mutableMapOf()
50 |
51 | override fun afterCheckFile(context: Context) {
52 | try {
53 | if (context !is JavaContext) return
54 |
55 | val allClasses = mutableSetOf().apply {
56 | addAll(saveCalls.keys)
57 | addAll(restoreCalls.keys)
58 | }
59 |
60 | allClasses
61 | .filter { saveCalls.containsKey(it) xor restoreCalls.containsKey(it) }
62 | .map { (saveCalls[it] ?: restoreCalls[it])!! }
63 | .forEach {
64 | context.report(ISSUE, it, context.getLocation(it), ADVICE)
65 | }
66 | } finally {
67 | saveCalls.clear()
68 | restoreCalls.clear()
69 | }
70 | }
71 |
72 | override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
73 | override fun visitCallExpression(node: UCallExpression) {
74 | val methodName = node.methodIdentifier?.name ?: return
75 | val uastParent = node.uastParent ?: return
76 |
77 | if (!APPLICABLE_METHODS.contains(methodName)) return
78 |
79 | val uFile = node.getContainingUFile() ?: return
80 | val imports = uFile.imports.mapNotNull { it.importReference?.asSourceString() }
81 | val parent = uastParent.psi?.text ?: return // StateSaver.restoreInstanceState or surrounding method with direct import
82 |
83 | if (!isStateSaverMethod(methodName, imports, parent)) return
84 |
85 | val cls = node.getContainingUClass()!!
86 | when (methodName) {
87 | SAVE_INSTANCE_STATE_METHOD -> saveCalls[cls] = node
88 | RESTORE_INSTANCE_STATE_METHOD -> restoreCalls[cls] = node
89 | }
90 | }
91 |
92 | private fun isStateSaverMethod(methodName: String, imports: List, parent: String) =
93 | if (imports.contains("$STATE_SAVER_CLASS.$methodName")) {
94 | true // direct import
95 | } else {
96 | // StateSaver.methodName check
97 | imports.contains(STATE_SAVER_CLASS) && parent.startsWith("$STATE_SAVER_CLASS_SIMPLE.$methodName")
98 | }
99 | }
100 |
101 | override fun getApplicableUastTypes(): List> = listOf(UCallExpression::class.java)
102 | override fun getApplicableFiles(): EnumSet = Scope.JAVA_FILE_SCOPE
103 | override fun getApplicableMethodNames(): List = APPLICABLE_METHODS
104 | }
105 |
--------------------------------------------------------------------------------
/library/src/androidTest/kotlin/com/evernote/android/state/test/GlobalStateSaverTest.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test
2 |
3 | import android.app.Activity
4 | import android.app.Application
5 | import android.content.Intent
6 | import android.content.pm.ActivityInfo
7 | import android.content.res.Configuration
8 | import android.os.Bundle
9 | import android.os.Looper
10 | import android.support.test.InstrumentationRegistry
11 | import android.support.test.rule.ActivityTestRule
12 | import android.support.test.runner.AndroidJUnit4
13 | import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
14 | import android.support.test.runner.lifecycle.Stage
15 | import androidx.fragment.app.Fragment
16 | import androidx.fragment.app.FragmentActivity
17 | import com.evernote.android.state.State
18 | import com.evernote.android.state.StateSaver
19 | import org.assertj.core.api.Assertions.assertThat
20 | import org.junit.Rule
21 | import org.junit.Test
22 | import org.junit.runner.RunWith
23 | import java.util.concurrent.CountDownLatch
24 |
25 | /**
26 | * @author rwondratschek
27 | */
28 | @RunWith(AndroidJUnit4::class)
29 | class GlobalStateSaverTest {
30 |
31 | @Rule
32 | @JvmField
33 | val activityRule = ActivityTestRule(MyActivity::class.java, true, false)
34 |
35 | @Test
36 | fun verifyStateSaverGloballyEnabled() {
37 | val context = InstrumentationRegistry.getTargetContext()
38 | StateSaver.setEnabledForAllActivitiesAndSupportFragments(context.applicationContext as Application, true)
39 | activityRule.launchActivity(Intent(context, MyActivity::class.java)) // launch manually delayed
40 |
41 | var count = 0
42 |
43 | repeat(4) {
44 | count++
45 | assertThat(activity.state).isEqualTo(count)
46 | assertThat(activity.fragment.state).isEqualTo(count)
47 | assertThat(activity.fragment.innerFragment.state).isEqualTo(count)
48 |
49 | changeOrientation()
50 | }
51 | }
52 |
53 | @Test
54 | fun verifyStateSaverGloballyDisabled() {
55 | val context = InstrumentationRegistry.getTargetContext()
56 | StateSaver.setEnabledForAllActivitiesAndSupportFragments(context.applicationContext as Application, false)
57 | activityRule.launchActivity(Intent(context, MyActivity::class.java)) // launch manually delayed
58 |
59 | val count = 1
60 |
61 | repeat(4) {
62 | assertThat(activity.state).isEqualTo(count)
63 | assertThat(activity.fragment.state).isEqualTo(count)
64 | assertThat(activity.fragment.innerFragment.state).isEqualTo(count)
65 |
66 | changeOrientation()
67 | }
68 | }
69 |
70 | private fun changeOrientation() {
71 | activity.requestedOrientation =
72 | if (activity.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
73 | ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
74 | } else {
75 | ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
76 | }
77 |
78 | InstrumentationRegistry.getInstrumentation().waitForIdleSync()
79 | Thread.sleep(1000)
80 | InstrumentationRegistry.getInstrumentation().waitForIdleSync()
81 | }
82 |
83 | private val activity: MyActivity
84 | get() {
85 | return if (Looper.getMainLooper() == Looper.myLooper()) {
86 | var result: Activity? = null
87 | for (i in 1..4) {
88 | result = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED).firstOrNull { it is MyActivity }
89 | if (result !is MyActivity) {
90 | Thread.sleep(1000)
91 | }
92 | }
93 | result as MyActivity
94 | } else {
95 | val latch = CountDownLatch(1)
96 | lateinit var result: MyActivity
97 | activityRule.runOnUiThread {
98 | result = activity
99 | latch.countDown()
100 | }
101 | latch.await()
102 | result
103 | }
104 | }
105 | }
106 |
107 | class MyActivity : FragmentActivity() {
108 |
109 | @State
110 | var state = 0
111 |
112 | val fragment: MyFragment get() = supportFragmentManager.findFragmentByTag("Tag") as MyFragment
113 |
114 | override fun onCreate(savedInstanceState: Bundle?) {
115 | super.onCreate(savedInstanceState)
116 | if (savedInstanceState == null) {
117 | supportFragmentManager.beginTransaction().add(MyFragment().apply {
118 | arguments = Bundle().apply { putBoolean("create_inner", true) }
119 | }, "Tag").commit()
120 | }
121 | state++
122 | }
123 | }
124 |
125 | class MyFragment : Fragment() {
126 |
127 | @State
128 | var state = 0
129 |
130 | val innerFragment: MyFragment get() = fragmentManager!!.findFragmentByTag("Inner") as MyFragment
131 |
132 | override fun onCreate(savedInstanceState: Bundle?) {
133 | super.onCreate(savedInstanceState)
134 | if (savedInstanceState == null && arguments?.getBoolean("create_inner", false) == true) {
135 | fragmentManager!!.beginTransaction().add(MyFragment(), "Inner").commit()
136 | }
137 | state++
138 | }
139 | }
140 |
141 |
--------------------------------------------------------------------------------
/gradle/checkstyle/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/evernote/android/state/StateSaverImpl.java:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Frankie Sardo, and Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Frankie Sardo - initial API and implementation
10 | * Ralf Wondratschek - documentation and feature enhancement
11 | *******************************************************************************/
12 | package com.evernote.android.state;
13 |
14 | import android.app.Application;
15 | import android.os.Bundle;
16 | import android.os.Parcelable;
17 | import androidx.annotation.NonNull;
18 | import androidx.annotation.Nullable;
19 | import android.view.View;
20 |
21 | import java.util.Map;
22 |
23 | /*package*/ @SuppressWarnings({"unused", "WeakerAccess"})
24 | final class StateSaverImpl {
25 |
26 | private final Map, Injector> mInjectors;
27 |
28 | /*package*/ StateSaverImpl(Map, Injector> injectors) {
29 | mInjectors = injectors;
30 | }
31 |
32 | private Injector getInjector(Class> cls) {
33 | Injector injector = mInjectors.get(cls);
34 | if (injector != null || mInjectors.containsKey(cls)) {
35 | return injector;
36 | }
37 | String clsName = cls.getName();
38 | if (clsName.startsWith(StateSaver.ANDROID_PREFIX) || clsName.startsWith(StateSaver.JAVA_PREFIX)) {
39 | return null;
40 | }
41 | try {
42 | Class> injectorClass = Class.forName(clsName + StateSaver.SUFFIX);
43 | injector = (Injector) injectorClass.newInstance();
44 | } catch (Exception e) {
45 | injector = getInjector(cls.getSuperclass());
46 | }
47 | mInjectors.put(cls, injector);
48 | return injector;
49 | }
50 |
51 | @SuppressWarnings("unchecked")
52 | private T safeGet(Object target, Injector nop) {
53 | try {
54 | Class> targetClass = target.getClass();
55 | Injector injector = getInjector(targetClass);
56 | if (injector == null) {
57 | injector = nop;
58 | }
59 | return (T) injector;
60 | } catch (Exception e) {
61 | throw new RuntimeException("Unable to inject state for " + target, e);
62 | }
63 | }
64 |
65 | /**
66 | * Save the given {@code target} in the passed in {@link Bundle}.
67 | *
68 | * @param target The object containing fields annotated with {@link State}.
69 | * @param state The object is saved into this bundle.
70 | */
71 | /*package*/ void saveInstanceState(@NonNull T target, @NonNull Bundle state) {
72 | Injector.Object injector = safeGet(target, Injector.Object.DEFAULT);
73 | injector.save(target, state);
74 | }
75 |
76 | /**
77 | * Restore the given {@code target} from the passed in {@link Bundle}.
78 | *
79 | * @param target The object containing fields annotated with {@link State}.
80 | * @param state The object is being restored from this bundle. Nothing is restored if the argument is {@code null}.
81 | */
82 | /*package*/ void restoreInstanceState(@NonNull T target, @Nullable Bundle state) {
83 | if (state != null) {
84 | Injector.Object injector = safeGet(target, Injector.Object.DEFAULT);
85 | injector.restore(target, state);
86 | }
87 | }
88 |
89 | /**
90 | * Save the state of the given view and the other state inside of the returned {@link Parcelable}.
91 | *
92 | * @param target The view containing fields annotated with {@link State}.
93 | * @param state The super state of the parent class of the view. Usually it isn't {@code null}.
94 | * @return A parcelable containing the view's state and its super state.
95 | */
96 | @NonNull
97 | /*package*/ Parcelable saveInstanceState(@NonNull T target, @Nullable Parcelable state) {
98 | Injector.View injector = safeGet(target, Injector.View.DEFAULT);
99 | return injector.save(target, state);
100 | }
101 |
102 | /**
103 | * Restore the sate of the given view and return the super state of the parent class.
104 | *
105 | * @param target The view containing fields annotated with {@link State}.
106 | * @param state The parcelable containing the view's state and its super sate.
107 | * @return The super state of teh parent class of the view. Usually it isn't {@code null}.
108 | */
109 | @Nullable
110 | /*package*/ Parcelable restoreInstanceState(@NonNull T target, @Nullable Parcelable state) {
111 | if (state != null) {
112 | Injector.View injector = safeGet(target, Injector.View.DEFAULT);
113 | return injector.restore(target, state);
114 | } else {
115 | return null;
116 | }
117 | }
118 |
119 | /**
120 | * Turns automatic instance saving on or off for all activities and fragments from the support library. This avoids
121 | * manual calls of {@link #saveInstanceState(Object, Bundle)} and {@link #restoreInstanceState(Object, Bundle)}, instead
122 | * the library is doing this automatically for you. It's still necessary to annotate fields with {@link State}, though.
123 | *
124 | *
125 | * The best place to turn on this feature is in your {@link Application#onCreate()} method.
126 | *
127 | * @param application Your application instance.
128 | * @param enabled Whether this feature should be enabled.
129 | */
130 | /*package*/ void setEnabledForAllActivitiesAndSupportFragments(@NonNull Application application, boolean enabled) {
131 | if (AndroidLifecycleCallbacks.INSTANCE.mEnabled != enabled) {
132 | if (enabled) {
133 | application.registerActivityLifecycleCallbacks(AndroidLifecycleCallbacks.INSTANCE);
134 | } else {
135 | application.unregisterActivityLifecycleCallbacks(AndroidLifecycleCallbacks.INSTANCE);
136 | }
137 | AndroidLifecycleCallbacks.INSTANCE.mEnabled = enabled;
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DEPRECATED
2 |
3 | This library is not maintained anymore.
4 |
5 | # ~~Android-State~~
6 |
7 | A utility library for Android to save objects in a `Bundle` without any boilerplate. It uses an annotation processor to wire up all dependencies.
8 |
9 | ## Download
10 |
11 | Download the latest [library](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22android-state%22) and [processor](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22android-state-processor%22) or grab via Gradle:
12 |
13 | ```groovy
14 | dependencies {
15 | implementation 'com.evernote:android-state:1.4.1'
16 | // Java only project
17 | annotationProcessor 'com.evernote:android-state-processor:1.4.1'
18 |
19 | // Kotlin with or without Java
20 | kapt 'com.evernote:android-state-processor:1.4.1'
21 | }
22 | ```
23 |
24 | You can read the [JavaDoc here](https://evernote.github.io/android-state/javadoc/).
25 |
26 | ## Usage
27 |
28 | It's recommended to turn on a global setting in your `Application` class to save and restore the instance state of all activities and fragments from the support library. After that you only need to annotate your fields with `@State` inside of your fragments and activities. You can save any type which can be saved in a `Bundle` like the `String`, `Serializable`, and `Parcelable` data structures.
29 |
30 | ```java
31 | public class App extends Application {
32 | @Override
33 | public void onCreate() {
34 | super.onCreate();
35 | StateSaver.setEnabledForAllActivitiesAndSupportFragments(this, true);
36 | }
37 | }
38 |
39 | public class MainActivity extends Activity {
40 |
41 | @State
42 | public int mValue;
43 |
44 | // ...
45 | }
46 |
47 | class MainFragment : Fragment() {
48 |
49 | @State
50 | var title = "My fragment"
51 | }
52 | ```
53 |
54 | If you want to save the state of any other object or didn't turn on the global setting, then you need to use the `StateSaver` class for manually saving and restoring the instance state.
55 |
56 | ```java
57 | public class MainActivity extends Activity {
58 |
59 | @State
60 | public int mValue;
61 |
62 | @Override
63 | protected void onCreate(Bundle savedInstanceState) {
64 | super.onCreate(savedInstanceState);
65 | StateSaver.restoreInstanceState(this, savedInstanceState);
66 | }
67 |
68 | @Override
69 | protected void onSaveInstanceState(Bundle outState) {
70 | super.onSaveInstanceState(outState);
71 | StateSaver.saveInstanceState(this, outState);
72 | }
73 | }
74 | ```
75 |
76 | ## Advanced
77 |
78 | You can also save state in a `View` class.
79 |
80 | ```java
81 | public class TestView extends View {
82 |
83 | @State
84 | public int mState;
85 |
86 | public TestView(Context context) {
87 | super(context);
88 | }
89 |
90 | @Override
91 | protected Parcelable onSaveInstanceState() {
92 | return StateSaver.saveInstanceState(this, super.onSaveInstanceState());
93 | }
94 |
95 | @Override
96 | protected void onRestoreInstanceState(Parcelable state) {
97 | super.onRestoreInstanceState(StateSaver.restoreInstanceState(this, state));
98 | }
99 | }
100 | ```
101 |
102 | It is recommended that saved properties not be `private`. If a property is `private`, then a non-private getter and setter method are required. This is especially useful for Kotlin, because properties are `private` by default and the aforementioned methods are generated by the compiler.
103 |
104 | If you **want** your getter and setter to be used rather than the field value being used directly, the field **must** be private.
105 |
106 | ```kotlin
107 | class DemoPresenter : Presenter() {
108 |
109 | @State
110 | var counter = 0
111 |
112 | // ...
113 | }
114 |
115 | ```
116 |
117 | Of course, this also works in Java.
118 |
119 | ```java
120 | public class TitleUpdater {
121 |
122 | @State
123 | private String mTitle;
124 |
125 | public String getTitle() {
126 | return mTitle;
127 | }
128 |
129 | public void setTitle(String title) {
130 | mTitle = title;
131 | }
132 | }
133 | ```
134 |
135 | If you have a private field and don't want to provide a getter or setter method, then you can fallback to reflection. However, this method is not recommended.
136 |
137 | ```java
138 | public class ImageProcessor {
139 |
140 | @StateReflection
141 | private byte[] mImageData;
142 |
143 | // ...
144 | }
145 | ```
146 |
147 | A custom bundler can be useful, if a class doesn't implement the `Parcelable` or `Serializable` interface, which oftentimes happens with third party dependencies.
148 |
149 | ```java
150 | public class MappingProvider {
151 |
152 | @State(PairBundler.class)
153 | public Pair mMapping;
154 |
155 | public static final class PairBundler implements Bundler> {
156 | @Override
157 | public void put(@NonNull String key, @NonNull Pair value, @NonNull Bundle bundle) {
158 | bundle.putString(key + "first", value.first);
159 | bundle.putInt(key + "second", value.second);
160 | }
161 |
162 | @Nullable
163 | @Override
164 | public Pair get(@NonNull String key, @NonNull Bundle bundle) {
165 | if (bundle.containsKey(key + "first")) {
166 | return new Pair<>(bundle.getString(key + "first"), bundle.getInt(key + "second"));
167 | } else {
168 | return null;
169 | }
170 | }
171 | }
172 | }
173 | ```
174 |
175 | ### Lint
176 |
177 | The library comes with Lint rules to verify a correct usage of the library. The lint checks work in Java and Kotlin files.
178 |
179 | ### ProGuard
180 |
181 | This library comes with a ProGuard config. No further steps are required, but all necessary rules can be found [here](library/proguard.cfg).
182 |
183 | ## [Icepick](https://github.com/frankiesardo/icepick)
184 |
185 | This library is based on [Icepick](https://github.com/frankiesardo/icepick), a great library from Frankie Sardo. However, Icepick is missing some features important to us: it [doesn't support properties](https://github.com/frankiesardo/icepick/issues/81) which is a [bummer for Kotlin](https://github.com/frankiesardo/icepick/issues/47). Also, Icepick does not support private fields which may break encapsulation. A tool shouldn't force you into this direction.
186 |
187 | Since Icepick is implemented in Clojure, we decided that it's better for us to rewrite the annotation processor in Java. Unfortunately, that makes it hard to push our features into Icepick itself. That's why we decided to fork the project.
188 |
189 | There are also alternatives for Kotlin like [IceKick](https://github.com/tinsukE/icekick). We did not want to use two libraries to solve the same problem for two different languages; we wanted to have one solution for all scenarios.
190 |
191 | Upgrading to this library from Icepick is easy. The API is the same; only the packages and the class name (i.e. from `Icepick` to `StateSaver`) have changed. If Icepick works well for you, then there's no need to upgrade.
192 |
193 | ## License
194 |
195 | ```
196 | Copyright (c) 2017 Evernote Corporation.
197 | All rights reserved. This program and the accompanying materials
198 | are made available under the terms of the Eclipse Public License v1.0
199 | which accompanies this distribution, and is available at
200 |
201 | http://www.eclipse.org/legal/epl-v10.html
202 |
203 | Files produced by Android-State code generator are not subject to terms
204 | of the Eclipse Public License 1.0 and can be used as set out in the
205 | copyright notice included in the generated files.
206 | ```
207 |
--------------------------------------------------------------------------------
/library-lint/src/test/kotlin/com/evernote/android/state/lint/detectors/NonMatchingStateSaverDetectorTest.kt:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.lint.detectors
2 |
3 | import com.evernote.android.state.lint.AbstractDetectorTest
4 | import com.evernote.android.state.lint.detector.AndroidStateDetector
5 | import org.assertj.core.api.Assertions.assertThat
6 |
7 | /**
8 | * Created by junchengc on 5/11/17.
9 | */
10 |
11 | private const val NO_WARNINGS = "No warnings."
12 |
13 | class NonMatchingStateSaverDetectorTest : AbstractDetectorTest() {
14 |
15 | private val stateSaverJava = getTestFile("stub/StateSaver.java")
16 |
17 | override fun getDetector() = AndroidStateDetector()
18 | override fun getIssues() = listOf(AndroidStateDetector.ISSUE)
19 |
20 | fun testEmpty() {
21 | assertThat(lintFiles(getTestFile("Empty.java"))).isEqualTo(NO_WARNINGS)
22 | }
23 |
24 | fun testValidActivity() {
25 | assertThat(lintFiles(stateSaverJava, getTestFile("ValidActivity.java"))).isEqualTo(NO_WARNINGS)
26 | }
27 |
28 | fun testValidActivityKotlin() {
29 | assertThat(lintFiles(stateSaverJava, getTestFile("ValidActivityKt.kt"))).isEqualTo(NO_WARNINGS)
30 | }
31 |
32 | fun testValidActivityDirectImport() {
33 | assertThat(lintFiles(stateSaverJava, getTestFile("ValidActivityDirectImport.java"))).isEqualTo(NO_WARNINGS)
34 | }
35 |
36 | fun testValidActivityDirectImportKotlin() {
37 | assertThat(lintFiles(stateSaverJava, getTestFile("ValidActivityDirectImportKt.kt"))).isEqualTo(NO_WARNINGS)
38 | }
39 |
40 | fun testValidActivityOtherMethod() {
41 | assertThat(lintFiles(stateSaverJava, getTestFile("ValidActivityOtherMethod.java"))).isEqualTo(NO_WARNINGS)
42 | }
43 |
44 | fun testValidActivityOtherMethodKotlin() {
45 | assertThat(lintFiles(stateSaverJava, getTestFile("ValidActivityOtherMethodKt.kt"))).isEqualTo(NO_WARNINGS)
46 | }
47 |
48 | fun testInvalidActivityNoSave() {
49 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityNoSave.java"))).isEqualTo(
50 | """
51 | InvalidActivityNoSave.java:24: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
52 | StateSaver.restoreInstanceState(this, savedInstanceState);
53 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | 0 errors, 1 warnings
55 |
56 | """.trimIndent()
57 | )
58 | }
59 |
60 | fun testInvalidActivityNoSaveKotlin() {
61 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityNoSaveKt.kt"))).isEqualTo(
62 | """
63 | InvalidActivityNoSaveKt.kt:23: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
64 | StateSaver.restoreInstanceState(this, savedInstanceState)
65 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66 | 0 errors, 1 warnings
67 |
68 | """.trimIndent()
69 | )
70 | }
71 |
72 | fun testInvalidActivityNoRestore() {
73 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityNoRestore.java"))).isEqualTo(
74 | """
75 | InvalidActivityNoRestore.java:29: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
76 | StateSaver.saveInstanceState(this, outState);
77 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78 | 0 errors, 1 warnings
79 |
80 | """.trimIndent()
81 | )
82 | }
83 |
84 | fun testInvalidActivityNoRestoreKotlin() {
85 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityNoRestoreKt.kt"))).isEqualTo(
86 | """
87 | InvalidActivityNoRestoreKt.kt:27: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
88 | StateSaver.saveInstanceState(this, outState)
89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
90 | 0 errors, 1 warnings
91 |
92 | """.trimIndent()
93 | )
94 | }
95 |
96 | fun testInvalidActivityNoRestoreDirectImport() {
97 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityNoRestoreDirectImport.java"))).isEqualTo(
98 | """
99 | InvalidActivityNoRestoreDirectImport.java:30: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
100 | saveInstanceState(this, outState);
101 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102 | 0 errors, 1 warnings
103 |
104 | """.trimIndent()
105 | )
106 | }
107 |
108 | fun testInvalidActivityNoRestoreDirectImportKotlin() {
109 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityNoRestoreDirectImportKt.kt"))).isEqualTo(
110 | """
111 | InvalidActivityNoRestoreDirectImportKt.kt:27: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
112 | saveInstanceState(this, outState)
113 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
114 | 0 errors, 1 warnings
115 |
116 | """.trimIndent()
117 | )
118 | }
119 |
120 | fun testInvalidActivityOtherMethod() {
121 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityOtherMethod.java"))).isEqualTo(
122 | """
123 | InvalidActivityOtherMethod.java:30: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
124 | StateSaver.saveInstanceState(this, outState);
125 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126 | 0 errors, 1 warnings
127 |
128 | """.trimIndent()
129 | )
130 | }
131 |
132 | fun testInvalidActivityOtherMethodKotlin() {
133 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityOtherMethodKt.kt"))).isEqualTo(
134 | """
135 | InvalidActivityOtherMethodKt.kt:28: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
136 | StateSaver.saveInstanceState(this, outState)
137 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
138 | 0 errors, 1 warnings
139 |
140 | """.trimIndent()
141 | )
142 | }
143 |
144 | fun testMultipleFiles() {
145 | assertThat(lintFiles(stateSaverJava, getTestFile("InvalidActivityNoRestoreKt.kt"), getTestFile("InvalidActivityNoSave.java"))).isEqualTo(
146 | """
147 | InvalidActivityNoRestoreKt.kt:27: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
148 | StateSaver.saveInstanceState(this, outState)
149 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150 | InvalidActivityNoSave.java:24: Warning: StateSaver calls should always occur in pairs. StateSaver.saveInstanceState() should always have a matching call to StateSaver.restoreInstanceState(). [NonMatchingStateSaverCalls]
151 | StateSaver.restoreInstanceState(this, savedInstanceState);
152 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
153 | 0 errors, 2 warnings
154 |
155 | """.trimIndent()
156 | )
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/gradle/gradle-push.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven'
2 | apply plugin: 'signing'
3 |
4 | @SuppressWarnings(["GrMethodMayBeStatic", "GroovyUnusedDeclaration"])
5 | def isReleaseBuild() {
6 | return !VERSION_NAME.contains("SNAPSHOT")
7 | }
8 |
9 | def isAndroidProject() {
10 | return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')
11 | }
12 |
13 | def isLocal() {
14 | return hasProperty('local') ? Boolean.parseBoolean(getProperty('local')) : true
15 | }
16 |
17 | def getReleaseRepositoryUrl() {
18 | if (this.isLocal()) {
19 | return hasProperty('RELEASE_REPOSITORY_LOCAL') ? RELEASE_REPOSITORY_LOCAL : "file://${System.env.HOME}/.m2/repository"
20 | } else {
21 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
22 | }
23 | }
24 |
25 | def getSnapshotRepositoryUrl() {
26 | if (this.isLocal()) {
27 | return hasProperty('SNAPSHOT_REPOSITORY_LOCAL') ? SNAPSHOT_REPOSITORY_LOCAL : "file://${System.env.HOME}/.m2/repository"
28 | } else {
29 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL : "https://oss.sonatype.org/content/repositories/snapshots/"
30 | }
31 | }
32 |
33 | def getRepositoryUsername() {
34 | return hasProperty('SONATYPE_USERNAME') ? SONATYPE_USERNAME : ""
35 | }
36 |
37 | def getRepositoryPassword() {
38 | return hasProperty('SONATYPE_PASSWORD') ? SONATYPE_PASSWORD : ""
39 | }
40 |
41 | if (isAndroidProject()) {
42 | android.libraryVariants.all { variant ->
43 | variant.outputs.each { output ->
44 | File outputFile = output.outputFile
45 | if (outputFile != null && outputFile.name.endsWith('.aar') && 'release' == variant.buildType.name) {
46 | output.outputFileName = "${project.archivesBaseName}-${version}.aar"
47 | }
48 | }
49 | }
50 | }
51 |
52 | version = VERSION_NAME
53 |
54 | artifacts {
55 | archives file("$buildDir/outputs/jar/${project.archivesBaseName}-${project.version}-sources.jar")
56 | archives file("$buildDir/outputs/jar/${project.archivesBaseName}-${project.version}-javadoc.jar")
57 | }
58 |
59 | afterEvaluate { project ->
60 | uploadArchives {
61 | //noinspection GradleMisplacedStatement
62 | repositories {
63 | //noinspection GroovyAssignabilityCheck
64 | mavenDeployer {
65 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
66 |
67 | pom.groupId = 'com.evernote'
68 | pom.artifactId = POM_ARTIFACT_ID
69 | pom.version = VERSION_NAME
70 |
71 | repository(url: this.getReleaseRepositoryUrl()) {
72 | authentication(userName: this.getRepositoryUsername(), password: this.getRepositoryPassword())
73 | }
74 | snapshotRepository(url: this.getSnapshotRepositoryUrl()) {
75 | authentication(userName: this.getRepositoryUsername(), password: this.getRepositoryPassword())
76 | }
77 |
78 | pom.project {
79 | name POM_NAME
80 | packaging POM_PACKAGING
81 | description 'Android library to save object states into a bundle.'
82 | url 'https://github.com/evernote/android-state'
83 | inceptionYear '2017'
84 |
85 | scm {
86 | url 'https://github.com/evernote/android-state'
87 | connection 'scm:git:git://github.com/evernote/android-state.git'
88 | developerConnection 'scm:git:git@github.com:evernote/android-state.git'
89 | }
90 |
91 | developers {
92 | developer {
93 | name 'Ralf Wondratschek'
94 | email 'rwondratschek@evernote.com'
95 | id 'rwondratschek'
96 | url 'http://vrallev.net'
97 | timezone '+1'
98 | roles {
99 | role 'developer'
100 | }
101 | }
102 | }
103 |
104 | licenses {
105 | license {
106 | name 'Eclipse Public License - v 1.0'
107 | url 'https://github.com/evernote/android-state/blob/master/LICENSE'
108 | distribution 'repo'
109 | }
110 | }
111 |
112 | issueManagement {
113 | system 'GitHub Issues'
114 | url 'https://github.com/evernote/android-state/issues'
115 | }
116 | }
117 | }
118 | }
119 | }
120 |
121 | signing {
122 | required { gradle.taskGraph.hasTask("uploadArchives") }
123 | sign configurations.archives
124 | }
125 | }
126 |
127 | project.tasks.whenTaskAdded { task ->
128 | if (task.name == 'signArchives') {
129 | this.addSourcesAndJavadocTask task
130 | }
131 | }
132 |
133 | def addSourcesAndJavadocTask(Task uploadTask) {
134 | if (this.isAndroidProject()) {
135 | android.libraryVariants.all { variant ->
136 | // javadoc jar
137 | project.task("${variant.name.capitalize()}Javadoc", type: Javadoc) {
138 | failOnError true
139 |
140 | destinationDir = new File("$project.buildDir/javadoc/$variant.name")
141 |
142 | source = variant.javaCompile.source
143 |
144 | ext.androidJar = "${project.android.sdkDirectory}/platforms/${project.android.compileSdkVersion}/android.jar"
145 |
146 | options {
147 | linksOffline("http://d.android.com/reference", "${project.android.sdkDirectory}/docs/reference")
148 | links("http://docs.oracle.com/javase/7/docs/api/")
149 | setMemberLevel(JavadocMemberLevel.PACKAGE)
150 | addStringOption('Xdoclint:none', '-quiet')
151 | docEncoding = 'UTF-8'
152 | encoding = 'UTF-8'
153 | charSet = 'UTF-8'
154 | }
155 |
156 | exclude '**/BuildConfig.java'
157 | exclude '**/R.java'
158 | }
159 |
160 | project.task("generate${variant.name.capitalize()}JavadocJar", type: Jar, dependsOn: "${variant.name.capitalize()}Javadoc") {
161 | classifier 'javadoc'
162 |
163 | description = 'Assembles a jar archive containing the generated Javadoc API documentation of $variant.name.'
164 |
165 | destinationDir = new File("$project.buildDir/outputs/jar/")
166 |
167 | exclude '**/BuildConfig.class'
168 | exclude '**/R.class'
169 |
170 | from "$project.buildDir/javadoc/$variant.name"
171 | }
172 |
173 | // sources jar
174 | project.task("generate${variant.name.capitalize()}SourcesJar", type: Jar) {
175 | classifier = 'sources'
176 |
177 | description = 'Assembles a jar archive containing the main sources of $variant.name..'
178 |
179 | destinationDir = new File("$project.buildDir/outputs/jar/")
180 |
181 | // exclude generated files
182 | exclude '**/BuildConfig.java'
183 | exclude '**/R.java'
184 |
185 | from variant.javaCompile.source
186 | }
187 |
188 | if (variant.name.equalsIgnoreCase('release')) {
189 | uploadTask.dependsOn project.tasks.getByName("assemble${variant.name.capitalize()}")
190 | uploadTask.dependsOn project.tasks.getByName("generate${variant.name.capitalize()}JavadocJar")
191 | uploadTask.dependsOn project.tasks.getByName("generate${variant.name.capitalize()}SourcesJar")
192 | }
193 | }
194 | } else {
195 | task sourcesJar(type: Jar, dependsOn: classes) {
196 | classifier = 'sources'
197 | destinationDir = new File("$project.buildDir/outputs/jar/")
198 | from sourceSets.main.allSource
199 | }
200 |
201 | task javadocJar(type: Jar, dependsOn: javadoc) {
202 | classifier = 'javadoc'
203 | destinationDir = new File("$project.buildDir/outputs/jar/")
204 | from javadoc.destinationDir
205 | }
206 |
207 | if (JavaVersion.current().isJava8Compatible()) {
208 | allprojects {
209 | tasks.withType(Javadoc) {
210 | options.addStringOption('Xdoclint:none', '-quiet')
211 | }
212 | }
213 | }
214 |
215 | uploadTask.dependsOn project.tasks.getByName("jar")
216 | uploadTask.dependsOn project.tasks.getByName("javadocJar")
217 | uploadTask.dependsOn project.tasks.getByName("sourcesJar")
218 | }
219 | }
--------------------------------------------------------------------------------
/library/src/test/kotlin/com/evernote/android/state/test/KotlinBundlingTest.kt:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | * Copyright (c) 2017 Evernote Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * Ralf Wondratschek
10 | *******************************************************************************/
11 | @file:Suppress("UsePropertyAccessSyntax")
12 |
13 | package com.evernote.android.state.test
14 |
15 | import android.os.Bundle
16 | import com.evernote.android.state.StateSaver
17 | import org.assertj.core.api.Assertions.assertThat
18 | import org.junit.FixMethodOrder
19 | import org.junit.Test
20 | import org.junit.runners.MethodSorters
21 |
22 | /**
23 | * Copyright 2017 Evernote Corporation. All rights reserved.
24 | *
25 | * Created by rwondratschek on 2/13/17.
26 | */
27 | @FixMethodOrder(MethodSorters.JVM)
28 | class KotlinBundlingTest {
29 |
30 | @Test
31 | fun testKotlinList() {
32 | val kotlinList = TestKotlinList()
33 | assertThat(kotlinList.emptyList).isEmpty()
34 | assertThat(kotlinList.stringList).isNotEmpty()
35 | assertThat(kotlinList.parcelableList[0]).isEqualTo(TestTypes.ParcelableImpl(1))
36 |
37 | val bundle = Bundle()
38 | StateSaver.saveInstanceState(kotlinList, bundle)
39 |
40 | kotlinList.stringList = mutableListOf("single")
41 | kotlinList.parcelableList = mutableListOf(TestTypes.ParcelableImpl(2))
42 | assertThat(kotlinList.stringList).containsExactly("single")
43 | assertThat(kotlinList.parcelableList[0]).isEqualTo(TestTypes.ParcelableImpl(2))
44 |
45 | StateSaver.restoreInstanceState(kotlinList, bundle)
46 | assertThat(kotlinList.stringList).containsExactly("Hello", "World")
47 | assertThat(kotlinList.parcelableList[0]).isEqualTo(TestTypes.ParcelableImpl(1))
48 | }
49 |
50 | @Test
51 | fun testJavaList() {
52 | val kotlinList = com.evernote.android.state.test.TestJavaList()
53 | assertThat(kotlinList.emptyList).isEmpty()
54 | assertThat(kotlinList.stringList).isNotEmpty()
55 | assertThat(kotlinList.parcelableList[0]).isEqualTo(TestTypes.ParcelableImpl(1))
56 | assertThat(kotlinList.parcelableListPublic[0]).isEqualTo(TestTypes.ParcelableImpl(1))
57 |
58 | val bundle = Bundle()
59 | StateSaver.saveInstanceState(kotlinList, bundle)
60 |
61 | kotlinList.stringList = mutableListOf("single")
62 | kotlinList.parcelableList = mutableListOf(TestTypes.ParcelableImpl(2))
63 | kotlinList.parcelableListPublic = mutableListOf(TestTypes.ParcelableImpl(2))
64 | assertThat(kotlinList.stringList).containsExactly("single")
65 | assertThat(kotlinList.parcelableList[0]).isEqualTo(TestTypes.ParcelableImpl(2))
66 | assertThat(kotlinList.parcelableListPublic[0]).isEqualTo(TestTypes.ParcelableImpl(2))
67 |
68 | StateSaver.restoreInstanceState(kotlinList, bundle)
69 | assertThat(kotlinList.stringList).containsExactly("Hello", "World")
70 | assertThat(kotlinList.parcelableList[0]).isEqualTo(TestTypes.ParcelableImpl(1))
71 | assertThat(kotlinList.parcelableListPublic[0]).isEqualTo(TestTypes.ParcelableImpl(1))
72 | }
73 |
74 | @Test
75 | fun testKotlinEnum() {
76 | val kotlinEnum = TestKotlinEnum()
77 | assertThat(kotlinEnum.kotlinEnum).isEqualTo(KotlinEnum.LEFT)
78 | assertThat(kotlinEnum.getKotlinEnum1()).isEqualTo(KotlinEnum.LEFT)
79 |
80 | val bundle = Bundle()
81 | StateSaver.saveInstanceState(kotlinEnum, bundle)
82 |
83 | kotlinEnum.kotlinEnum = KotlinEnum.RIGHT
84 | kotlinEnum.setKotlinEnum1(KotlinEnum.RIGHT)
85 | StateSaver.restoreInstanceState(kotlinEnum, bundle)
86 | assertThat(kotlinEnum.kotlinEnum).isEqualTo(KotlinEnum.LEFT)
87 | assertThat(kotlinEnum.getKotlinEnum1()).isEqualTo(KotlinEnum.LEFT)
88 |
89 | kotlinEnum.kotlinEnum = KotlinEnum.RIGHT
90 | kotlinEnum.setKotlinEnum1(KotlinEnum.RIGHT)
91 | StateSaver.saveInstanceState(kotlinEnum, bundle)
92 |
93 | kotlinEnum.kotlinEnum = KotlinEnum.LEFT
94 | kotlinEnum.setKotlinEnum1(KotlinEnum.LEFT)
95 | StateSaver.restoreInstanceState(kotlinEnum, bundle)
96 | assertThat(kotlinEnum.kotlinEnum).isEqualTo(KotlinEnum.RIGHT)
97 | assertThat(kotlinEnum.getKotlinEnum1()).isEqualTo(KotlinEnum.RIGHT)
98 | }
99 |
100 | @Test
101 | fun testKotlinBoolean() {
102 | val kotlinBoolean = TestKotlinBoolean()
103 | assertThat(kotlinBoolean.test1).isFalse()
104 | assertThat(kotlinBoolean.isTest2).isFalse()
105 | assertThat(kotlinBoolean.mTest3).isFalse()
106 |
107 | val bundle = Bundle()
108 | StateSaver.saveInstanceState(kotlinBoolean, bundle)
109 |
110 | kotlinBoolean.test1 = true
111 | kotlinBoolean.isTest2 = true
112 | kotlinBoolean.mTest3 = true
113 |
114 | StateSaver.restoreInstanceState(kotlinBoolean, bundle)
115 | assertThat(kotlinBoolean.test1).isFalse()
116 | assertThat(kotlinBoolean.isTest2).isFalse()
117 | assertThat(kotlinBoolean.mTest3).isFalse()
118 |
119 | kotlinBoolean.test1 = true
120 | kotlinBoolean.isTest2 = true
121 | kotlinBoolean.mTest3 = true
122 | StateSaver.saveInstanceState(kotlinBoolean, bundle)
123 |
124 | kotlinBoolean.test1 = false
125 | kotlinBoolean.isTest2 = false
126 | kotlinBoolean.mTest3 = false
127 |
128 | StateSaver.restoreInstanceState(kotlinBoolean, bundle)
129 | assertThat(kotlinBoolean.test1).isTrue()
130 | assertThat(kotlinBoolean.isTest2).isTrue()
131 | assertThat(kotlinBoolean.mTest3).isTrue()
132 | }
133 |
134 | @Test
135 | fun testGenericSerializable() {
136 | val javaGenericSerializable = TestJavaGenericSerializable()
137 | val kotlinGenericSerializable = TestKotlinGenericSerializable()
138 | assertThat(javaGenericSerializable.genericSerializable).isNull()
139 | assertThat(kotlinGenericSerializable.genericSerializable).isNull()
140 |
141 | val bundle = Bundle()
142 | StateSaver.saveInstanceState(javaGenericSerializable, bundle)
143 | StateSaver.saveInstanceState(kotlinGenericSerializable, bundle)
144 |
145 | javaGenericSerializable.genericSerializable = GenericSerializable()
146 | kotlinGenericSerializable.genericSerializable = GenericSerializable()
147 |
148 | StateSaver.restoreInstanceState(javaGenericSerializable, bundle)
149 | StateSaver.restoreInstanceState(kotlinGenericSerializable, bundle)
150 | assertThat(javaGenericSerializable.genericSerializable).isNull()
151 | assertThat(kotlinGenericSerializable.genericSerializable).isNull()
152 |
153 | javaGenericSerializable.genericSerializable = GenericSerializable()
154 | kotlinGenericSerializable.genericSerializable = GenericSerializable()
155 | StateSaver.saveInstanceState(javaGenericSerializable, bundle)
156 | StateSaver.saveInstanceState(kotlinGenericSerializable, bundle)
157 |
158 | javaGenericSerializable.genericSerializable = null
159 | kotlinGenericSerializable.genericSerializable = null
160 |
161 | StateSaver.restoreInstanceState(javaGenericSerializable, bundle)
162 | StateSaver.restoreInstanceState(kotlinGenericSerializable, bundle)
163 | assertThat(javaGenericSerializable.genericSerializable as Any).isNotNull()
164 | assertThat(kotlinGenericSerializable.genericSerializable as Any).isNotNull()
165 | }
166 |
167 | @Test
168 | fun testWithNoneConcreteType() {
169 | val item = MyClass()
170 |
171 | assertThat(item.wrapped.content).isEqualTo(42)
172 | assertThat(item.wrappedGeneric.content).isEqualTo(42)
173 |
174 | val bundle = Bundle()
175 | StateSaver.saveInstanceState(item, bundle)
176 |
177 | item.wrapped = Wrapper(10)
178 | item.wrappedGeneric = Wrapper(10)
179 |
180 | StateSaver.restoreInstanceState(item, bundle)
181 | assertThat(item.wrapped.content).isEqualTo(42)
182 | assertThat(item.wrappedGeneric.content).isEqualTo(42)
183 |
184 | item.wrapped = Wrapper(10)
185 | item.wrappedGeneric = Wrapper(10)
186 | StateSaver.saveInstanceState(item, bundle)
187 |
188 | item.wrapped = Wrapper(42)
189 | item.wrappedGeneric = Wrapper(42)
190 |
191 | StateSaver.restoreInstanceState(item, bundle)
192 | assertThat(item.wrapped.content).isEqualTo(10)
193 | assertThat(item.wrappedGeneric.content).isEqualTo(10)
194 | }
195 |
196 | @Test
197 | fun testPrivateInnerClass() {
198 | val item = TestKotlinPrivateInnerClass()
199 | assertThat(item.isA()).isTrue()
200 |
201 | val bundle = Bundle()
202 | StateSaver.saveInstanceState(item, bundle)
203 |
204 | item.setToB()
205 |
206 | StateSaver.restoreInstanceState(item, bundle)
207 | assertThat(item.isA()).isTrue()
208 |
209 | item.setToB()
210 | StateSaver.saveInstanceState(item, bundle)
211 |
212 | item.setToA()
213 |
214 | StateSaver.restoreInstanceState(item, bundle)
215 | assertThat(item.isB()).isTrue()
216 | }
217 |
218 | @Test
219 | fun testParcelableArray() {
220 | val item = TestKotlinParcelableArray()
221 | assertThat(item.isValue(0)).isTrue()
222 |
223 | val bundle = Bundle()
224 | StateSaver.saveInstanceState(item, bundle)
225 |
226 | item.setToValue(1)
227 |
228 | StateSaver.restoreInstanceState(item, bundle)
229 | assertThat(item.isValue(0)).isTrue()
230 |
231 | item.setToValue(1)
232 | StateSaver.saveInstanceState(item, bundle)
233 |
234 | item.setToValue(0)
235 |
236 | StateSaver.restoreInstanceState(item, bundle)
237 | assertThat(item.isValue(1)).isTrue()
238 | }
239 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/evernote/android/state/test/TestTypesProperty.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test;
2 |
3 | import android.os.Bundle;
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 | import android.util.SparseArray;
7 |
8 | import com.evernote.android.state.State;
9 |
10 | import java.util.ArrayList;
11 |
12 | public class TestTypesProperty {
13 | @State
14 | private boolean mBoolean;
15 | @State
16 | private boolean[] mBooleanArray;
17 | @State
18 | private Boolean mBooleanObj;
19 | @State
20 | private byte mByte;
21 | @State
22 | private byte[] mByteArray;
23 | @State
24 | private Byte mByteObj;
25 | @State
26 | private char mChar;
27 | @State
28 | private char[] mCharArray;
29 | @State
30 | private Character mCharObj;
31 | @State
32 | private double mDouble;
33 | @State
34 | private double[] mDoubleArray;
35 | @State
36 | private Double mDoubleObj;
37 | @State
38 | private float mFloat;
39 | @State
40 | private float[] mFloatArray;
41 | @State
42 | private Float mFloatObj;
43 | @State
44 | private int mInt;
45 | @State
46 | private int[] mIntArray;
47 | @State
48 | private Integer mIntegerObj;
49 | @State
50 | private long mLong;
51 | @State
52 | private long[] mLongArray;
53 | @State
54 | private Long mLongObj;
55 | @State
56 | private short mShort;
57 | @State
58 | private short[] mShortArray;
59 | @State
60 | private Short mShortObj;
61 | @State
62 | private CharSequence mCharSequence;
63 | @State
64 | private CharSequence[] mCharSequenceArray;
65 | @State
66 | private String mString;
67 | @State
68 | private String[] mStringArray;
69 | @State
70 | private ArrayList mCharSequenceArrayList;
71 | @State
72 | private ArrayList mIntegerArrayList;
73 | @State
74 | private ArrayList mStringArrayList;
75 | @State
76 | private Bundle mBundle;
77 | @State
78 | private Parcelable[] mParcelableArray;
79 | @State
80 | private TestTypes.ParcelableImpl mParcelableImpl;
81 | @State
82 | private ParcelableImplExtension mParcelableImplExtension;
83 | @State
84 | private TestTypes.SerializableImpl mSerializableImpl;
85 | @State
86 | private ArrayList mParcelableArrayList;
87 | @State
88 | private SparseArray mParcelableSparseArray;
89 |
90 | public boolean isBoolean() {
91 | return mBoolean;
92 | }
93 |
94 | public void setBoolean(boolean aBoolean) {
95 | mBoolean = aBoolean;
96 | }
97 |
98 | public boolean[] getBooleanArray() {
99 | return mBooleanArray;
100 | }
101 |
102 | public void setBooleanArray(boolean[] booleanArray) {
103 | mBooleanArray = booleanArray;
104 | }
105 |
106 | public Boolean getBooleanObj() {
107 | return mBooleanObj;
108 | }
109 |
110 | public void setBooleanObj(Boolean booleanObj) {
111 | mBooleanObj = booleanObj;
112 | }
113 |
114 | public byte getByte() {
115 | return mByte;
116 | }
117 |
118 | public void setByte(byte aByte) {
119 | mByte = aByte;
120 | }
121 |
122 | public byte[] getByteArray() {
123 | return mByteArray;
124 | }
125 |
126 | public void setByteArray(byte[] byteArray) {
127 | mByteArray = byteArray;
128 | }
129 |
130 | public Byte getByteObj() {
131 | return mByteObj;
132 | }
133 |
134 | public void setByteObj(Byte byteObj) {
135 | mByteObj = byteObj;
136 | }
137 |
138 | public char getChar() {
139 | return mChar;
140 | }
141 |
142 | public void setChar(char aChar) {
143 | mChar = aChar;
144 | }
145 |
146 | public char[] getCharArray() {
147 | return mCharArray;
148 | }
149 |
150 | public void setCharArray(char[] charArray) {
151 | mCharArray = charArray;
152 | }
153 |
154 | public Character getCharObj() {
155 | return mCharObj;
156 | }
157 |
158 | public void setCharObj(Character charObj) {
159 | mCharObj = charObj;
160 | }
161 |
162 | public double getDouble() {
163 | return mDouble;
164 | }
165 |
166 | public void setDouble(double aDouble) {
167 | mDouble = aDouble;
168 | }
169 |
170 | public double[] getDoubleArray() {
171 | return mDoubleArray;
172 | }
173 |
174 | public void setDoubleArray(double[] doubleArray) {
175 | mDoubleArray = doubleArray;
176 | }
177 |
178 | public Double getDoubleObj() {
179 | return mDoubleObj;
180 | }
181 |
182 | public void setDoubleObj(Double doubleObj) {
183 | mDoubleObj = doubleObj;
184 | }
185 |
186 | public float getFloat() {
187 | return mFloat;
188 | }
189 |
190 | public void setFloat(float aFloat) {
191 | mFloat = aFloat;
192 | }
193 |
194 | public float[] getFloatArray() {
195 | return mFloatArray;
196 | }
197 |
198 | public void setFloatArray(float[] floatArray) {
199 | mFloatArray = floatArray;
200 | }
201 |
202 | public Float getFloatObj() {
203 | return mFloatObj;
204 | }
205 |
206 | public void setFloatObj(Float floatObj) {
207 | mFloatObj = floatObj;
208 | }
209 |
210 | public int getInt() {
211 | return mInt;
212 | }
213 |
214 | public void setInt(int anInt) {
215 | mInt = anInt;
216 | }
217 |
218 | public int[] getIntArray() {
219 | return mIntArray;
220 | }
221 |
222 | public void setIntArray(int[] intArray) {
223 | mIntArray = intArray;
224 | }
225 |
226 | public Integer getIntegerObj() {
227 | return mIntegerObj;
228 | }
229 |
230 | public void setIntegerObj(Integer integerObj) {
231 | mIntegerObj = integerObj;
232 | }
233 |
234 | public long getLong() {
235 | return mLong;
236 | }
237 |
238 | public void setLong(long aLong) {
239 | mLong = aLong;
240 | }
241 |
242 | public long[] getLongArray() {
243 | return mLongArray;
244 | }
245 |
246 | public void setLongArray(long[] longArray) {
247 | mLongArray = longArray;
248 | }
249 |
250 | public Long getLongObj() {
251 | return mLongObj;
252 | }
253 |
254 | public void setLongObj(Long longObj) {
255 | mLongObj = longObj;
256 | }
257 |
258 | public short getShort() {
259 | return mShort;
260 | }
261 |
262 | public void setShort(short aShort) {
263 | mShort = aShort;
264 | }
265 |
266 | public short[] getShortArray() {
267 | return mShortArray;
268 | }
269 |
270 | public void setShortArray(short[] shortArray) {
271 | mShortArray = shortArray;
272 | }
273 |
274 | public Short getShortObj() {
275 | return mShortObj;
276 | }
277 |
278 | public void setShortObj(Short shortObj) {
279 | mShortObj = shortObj;
280 | }
281 |
282 | public CharSequence getCharSequence() {
283 | return mCharSequence;
284 | }
285 |
286 | public void setCharSequence(CharSequence charSequence) {
287 | mCharSequence = charSequence;
288 | }
289 |
290 | public CharSequence[] getCharSequenceArray() {
291 | return mCharSequenceArray;
292 | }
293 |
294 | public void setCharSequenceArray(CharSequence[] charSequenceArray) {
295 | mCharSequenceArray = charSequenceArray;
296 | }
297 |
298 | public String getString() {
299 | return mString;
300 | }
301 |
302 | public void setString(String string) {
303 | mString = string;
304 | }
305 |
306 | public String[] getStringArray() {
307 | return mStringArray;
308 | }
309 |
310 | public void setStringArray(String[] stringArray) {
311 | mStringArray = stringArray;
312 | }
313 |
314 | public ArrayList getCharSequenceArrayList() {
315 | return mCharSequenceArrayList;
316 | }
317 |
318 | public void setCharSequenceArrayList(ArrayList charSequenceArrayList) {
319 | mCharSequenceArrayList = charSequenceArrayList;
320 | }
321 |
322 | public ArrayList getIntegerArrayList() {
323 | return mIntegerArrayList;
324 | }
325 |
326 | public void setIntegerArrayList(ArrayList integerArrayList) {
327 | mIntegerArrayList = integerArrayList;
328 | }
329 |
330 | public ArrayList getStringArrayList() {
331 | return mStringArrayList;
332 | }
333 |
334 | public void setStringArrayList(ArrayList stringArrayList) {
335 | mStringArrayList = stringArrayList;
336 | }
337 |
338 | public Bundle getBundle() {
339 | return mBundle;
340 | }
341 |
342 | public void setBundle(Bundle bundle) {
343 | mBundle = bundle;
344 | }
345 |
346 | public Parcelable[] getParcelableArray() {
347 | return mParcelableArray;
348 | }
349 |
350 | public void setParcelableArray(Parcelable[] parcelableArray) {
351 | mParcelableArray = parcelableArray;
352 | }
353 |
354 | public TestTypes.ParcelableImpl getParcelableImpl() {
355 | return mParcelableImpl;
356 | }
357 |
358 | public void setParcelableImpl(TestTypes.ParcelableImpl parcelableImpl) {
359 | mParcelableImpl = parcelableImpl;
360 | }
361 |
362 | public TestTypes.SerializableImpl getSerializableImpl() {
363 | return mSerializableImpl;
364 | }
365 |
366 | public void setSerializableImpl(TestTypes.SerializableImpl serializableImpl) {
367 | mSerializableImpl = serializableImpl;
368 | }
369 |
370 | public ArrayList getParcelableArrayList() {
371 | return mParcelableArrayList;
372 | }
373 |
374 | public void setParcelableArrayList(ArrayList parcelableArrayList) {
375 | mParcelableArrayList = parcelableArrayList;
376 | }
377 |
378 | public SparseArray getParcelableSparseArray() {
379 | return mParcelableSparseArray;
380 | }
381 |
382 | public void setParcelableSparseArray(SparseArray parcelableSparseArray) {
383 | mParcelableSparseArray = parcelableSparseArray;
384 | }
385 |
386 | public ParcelableImplExtension getParcelableImplExtension() {
387 | return mParcelableImplExtension;
388 | }
389 |
390 | public void setParcelableImplExtension(ParcelableImplExtension parcelableImplExtension) {
391 | mParcelableImplExtension = parcelableImplExtension;
392 | }
393 |
394 | public static class ParcelableImplExtension extends TestTypes.ParcelableImpl {
395 | private int mInt2;
396 |
397 | public ParcelableImplExtension(int anInt, int anInt2) {
398 | super(anInt);
399 | mInt2 = anInt2;
400 | }
401 |
402 | protected ParcelableImplExtension(Parcel in) {
403 | super(in);
404 | mInt2 = in.readInt();
405 | }
406 |
407 | @Override
408 | public boolean equals(Object o) {
409 | if (this == o) return true;
410 | if (o == null || getClass() != o.getClass()) return false;
411 | if (!super.equals(o)) return false;
412 |
413 | ParcelableImplExtension that = (ParcelableImplExtension) o;
414 |
415 | return mInt2 == that.mInt2;
416 | }
417 |
418 | @Override
419 | public int hashCode() {
420 | int result = super.hashCode();
421 | result = 31 * result + mInt2;
422 | return result;
423 | }
424 |
425 | @Override
426 | public void writeToParcel(Parcel dest, int flags) {
427 | super.writeToParcel(dest, flags);
428 | dest.writeInt(mInt2);
429 | }
430 |
431 | @Override
432 | public int describeContents() {
433 | return 0;
434 | }
435 |
436 | public static final Creator CREATOR = new Creator() {
437 | @Override
438 | public TestTypes.ParcelableImpl createFromParcel(Parcel in) {
439 | return new TestTypes.ParcelableImpl(in);
440 | }
441 |
442 | @Override
443 | public TestTypes.ParcelableImpl[] newArray(int size) {
444 | return new TestTypes.ParcelableImpl[size];
445 | }
446 | };
447 | }
448 |
449 | }
450 |
--------------------------------------------------------------------------------
/demo-java-8/src/main/java/com/evernote/android/state/test/java8/TestTypesProperty.java:
--------------------------------------------------------------------------------
1 | package com.evernote.android.state.test.java8;
2 |
3 | import android.os.Bundle;
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 | import android.util.SparseArray;
7 |
8 | import com.evernote.android.state.State;
9 |
10 | import java.util.ArrayList;
11 |
12 | public class TestTypesProperty {
13 | @State
14 | private boolean mBoolean;
15 | @State
16 | private boolean[] mBooleanArray;
17 | @State
18 | private Boolean mBooleanObj;
19 | @State
20 | private byte mByte;
21 | @State
22 | private byte[] mByteArray;
23 | @State
24 | private Byte mByteObj;
25 | @State
26 | private char mChar;
27 | @State
28 | private char[] mCharArray;
29 | @State
30 | private Character mCharObj;
31 | @State
32 | private double mDouble;
33 | @State
34 | private double[] mDoubleArray;
35 | @State
36 | private Double mDoubleObj;
37 | @State
38 | private float mFloat;
39 | @State
40 | private float[] mFloatArray;
41 | @State
42 | private Float mFloatObj;
43 | @State
44 | private int mInt;
45 | @State
46 | private int[] mIntArray;
47 | @State
48 | private Integer mIntegerObj;
49 | @State
50 | private long mLong;
51 | @State
52 | private long[] mLongArray;
53 | @State
54 | private Long mLongObj;
55 | @State
56 | private short mShort;
57 | @State
58 | private short[] mShortArray;
59 | @State
60 | private Short mShortObj;
61 | @State
62 | private CharSequence mCharSequence;
63 | @State
64 | private CharSequence[] mCharSequenceArray;
65 | @State
66 | private String mString;
67 | @State
68 | private String[] mStringArray;
69 | @State
70 | private ArrayList mCharSequenceArrayList;
71 | @State
72 | private ArrayList mIntegerArrayList;
73 | @State
74 | private ArrayList mStringArrayList;
75 | @State
76 | private Bundle mBundle;
77 | @State
78 | private Parcelable[] mParcelableArray;
79 | @State
80 | private TestTypes.ParcelableImpl mParcelableImpl;
81 | @State
82 | private ParcelableImplExtension mParcelableImplExtension;
83 | @State
84 | private TestTypes.SerializableImpl mSerializableImpl;
85 | @State
86 | private ArrayList mParcelableArrayList;
87 | @State
88 | private SparseArray mParcelableSparseArray;
89 |
90 | public boolean isBoolean() {
91 | return mBoolean;
92 | }
93 |
94 | public void setBoolean(boolean aBoolean) {
95 | mBoolean = aBoolean;
96 | }
97 |
98 | public boolean[] getBooleanArray() {
99 | return mBooleanArray;
100 | }
101 |
102 | public void setBooleanArray(boolean[] booleanArray) {
103 | mBooleanArray = booleanArray;
104 | }
105 |
106 | public Boolean getBooleanObj() {
107 | return mBooleanObj;
108 | }
109 |
110 | public void setBooleanObj(Boolean booleanObj) {
111 | mBooleanObj = booleanObj;
112 | }
113 |
114 | public byte getByte() {
115 | return mByte;
116 | }
117 |
118 | public void setByte(byte aByte) {
119 | mByte = aByte;
120 | }
121 |
122 | public byte[] getByteArray() {
123 | return mByteArray;
124 | }
125 |
126 | public void setByteArray(byte[] byteArray) {
127 | mByteArray = byteArray;
128 | }
129 |
130 | public Byte getByteObj() {
131 | return mByteObj;
132 | }
133 |
134 | public void setByteObj(Byte byteObj) {
135 | mByteObj = byteObj;
136 | }
137 |
138 | public char getChar() {
139 | return mChar;
140 | }
141 |
142 | public void setChar(char aChar) {
143 | mChar = aChar;
144 | }
145 |
146 | public char[] getCharArray() {
147 | return mCharArray;
148 | }
149 |
150 | public void setCharArray(char[] charArray) {
151 | mCharArray = charArray;
152 | }
153 |
154 | public Character getCharObj() {
155 | return mCharObj;
156 | }
157 |
158 | public void setCharObj(Character charObj) {
159 | mCharObj = charObj;
160 | }
161 |
162 | public double getDouble() {
163 | return mDouble;
164 | }
165 |
166 | public void setDouble(double aDouble) {
167 | mDouble = aDouble;
168 | }
169 |
170 | public double[] getDoubleArray() {
171 | return mDoubleArray;
172 | }
173 |
174 | public void setDoubleArray(double[] doubleArray) {
175 | mDoubleArray = doubleArray;
176 | }
177 |
178 | public Double getDoubleObj() {
179 | return mDoubleObj;
180 | }
181 |
182 | public void setDoubleObj(Double doubleObj) {
183 | mDoubleObj = doubleObj;
184 | }
185 |
186 | public float getFloat() {
187 | return mFloat;
188 | }
189 |
190 | public void setFloat(float aFloat) {
191 | mFloat = aFloat;
192 | }
193 |
194 | public float[] getFloatArray() {
195 | return mFloatArray;
196 | }
197 |
198 | public void setFloatArray(float[] floatArray) {
199 | mFloatArray = floatArray;
200 | }
201 |
202 | public Float getFloatObj() {
203 | return mFloatObj;
204 | }
205 |
206 | public void setFloatObj(Float floatObj) {
207 | mFloatObj = floatObj;
208 | }
209 |
210 | public int getInt() {
211 | return mInt;
212 | }
213 |
214 | public void setInt(int anInt) {
215 | mInt = anInt;
216 | }
217 |
218 | public int[] getIntArray() {
219 | return mIntArray;
220 | }
221 |
222 | public void setIntArray(int[] intArray) {
223 | mIntArray = intArray;
224 | }
225 |
226 | public Integer getIntegerObj() {
227 | return mIntegerObj;
228 | }
229 |
230 | public void setIntegerObj(Integer integerObj) {
231 | mIntegerObj = integerObj;
232 | }
233 |
234 | public long getLong() {
235 | return mLong;
236 | }
237 |
238 | public void setLong(long aLong) {
239 | mLong = aLong;
240 | }
241 |
242 | public long[] getLongArray() {
243 | return mLongArray;
244 | }
245 |
246 | public void setLongArray(long[] longArray) {
247 | mLongArray = longArray;
248 | }
249 |
250 | public Long getLongObj() {
251 | return mLongObj;
252 | }
253 |
254 | public void setLongObj(Long longObj) {
255 | mLongObj = longObj;
256 | }
257 |
258 | public short getShort() {
259 | return mShort;
260 | }
261 |
262 | public void setShort(short aShort) {
263 | mShort = aShort;
264 | }
265 |
266 | public short[] getShortArray() {
267 | return mShortArray;
268 | }
269 |
270 | public void setShortArray(short[] shortArray) {
271 | mShortArray = shortArray;
272 | }
273 |
274 | public Short getShortObj() {
275 | return mShortObj;
276 | }
277 |
278 | public void setShortObj(Short shortObj) {
279 | mShortObj = shortObj;
280 | }
281 |
282 | public CharSequence getCharSequence() {
283 | return mCharSequence;
284 | }
285 |
286 | public void setCharSequence(CharSequence charSequence) {
287 | mCharSequence = charSequence;
288 | }
289 |
290 | public CharSequence[] getCharSequenceArray() {
291 | return mCharSequenceArray;
292 | }
293 |
294 | public void setCharSequenceArray(CharSequence[] charSequenceArray) {
295 | mCharSequenceArray = charSequenceArray;
296 | }
297 |
298 | public String getString() {
299 | return mString;
300 | }
301 |
302 | public void setString(String string) {
303 | mString = string;
304 | }
305 |
306 | public String[] getStringArray() {
307 | return mStringArray;
308 | }
309 |
310 | public void setStringArray(String[] stringArray) {
311 | mStringArray = stringArray;
312 | }
313 |
314 | public ArrayList getCharSequenceArrayList() {
315 | return mCharSequenceArrayList;
316 | }
317 |
318 | public void setCharSequenceArrayList(ArrayList charSequenceArrayList) {
319 | mCharSequenceArrayList = charSequenceArrayList;
320 | }
321 |
322 | public ArrayList getIntegerArrayList() {
323 | return mIntegerArrayList;
324 | }
325 |
326 | public void setIntegerArrayList(ArrayList integerArrayList) {
327 | mIntegerArrayList = integerArrayList;
328 | }
329 |
330 | public ArrayList getStringArrayList() {
331 | return mStringArrayList;
332 | }
333 |
334 | public void setStringArrayList(ArrayList stringArrayList) {
335 | mStringArrayList = stringArrayList;
336 | }
337 |
338 | public Bundle getBundle() {
339 | return mBundle;
340 | }
341 |
342 | public void setBundle(Bundle bundle) {
343 | mBundle = bundle;
344 | }
345 |
346 | public Parcelable[] getParcelableArray() {
347 | return mParcelableArray;
348 | }
349 |
350 | public void setParcelableArray(Parcelable[] parcelableArray) {
351 | mParcelableArray = parcelableArray;
352 | }
353 |
354 | public TestTypes.ParcelableImpl getParcelableImpl() {
355 | return mParcelableImpl;
356 | }
357 |
358 | public void setParcelableImpl(TestTypes.ParcelableImpl parcelableImpl) {
359 | mParcelableImpl = parcelableImpl;
360 | }
361 |
362 | public TestTypes.SerializableImpl getSerializableImpl() {
363 | return mSerializableImpl;
364 | }
365 |
366 | public void setSerializableImpl(TestTypes.SerializableImpl serializableImpl) {
367 | mSerializableImpl = serializableImpl;
368 | }
369 |
370 | public ArrayList getParcelableArrayList() {
371 | return mParcelableArrayList;
372 | }
373 |
374 | public void setParcelableArrayList(ArrayList parcelableArrayList) {
375 | mParcelableArrayList = parcelableArrayList;
376 | }
377 |
378 | public SparseArray getParcelableSparseArray() {
379 | return mParcelableSparseArray;
380 | }
381 |
382 | public void setParcelableSparseArray(SparseArray parcelableSparseArray) {
383 | mParcelableSparseArray = parcelableSparseArray;
384 | }
385 |
386 | public ParcelableImplExtension getParcelableImplExtension() {
387 | return mParcelableImplExtension;
388 | }
389 |
390 | public void setParcelableImplExtension(ParcelableImplExtension parcelableImplExtension) {
391 | mParcelableImplExtension = parcelableImplExtension;
392 | }
393 |
394 | public static class ParcelableImplExtension extends TestTypes.ParcelableImpl {
395 | private int mInt2;
396 |
397 | public ParcelableImplExtension(int anInt, int anInt2) {
398 | super(anInt);
399 | mInt2 = anInt2;
400 | }
401 |
402 | protected ParcelableImplExtension(Parcel in) {
403 | super(in);
404 | mInt2 = in.readInt();
405 | }
406 |
407 | @Override
408 | public boolean equals(Object o) {
409 | if (this == o) return true;
410 | if (o == null || getClass() != o.getClass()) return false;
411 | if (!super.equals(o)) return false;
412 |
413 | ParcelableImplExtension that = (ParcelableImplExtension) o;
414 |
415 | return mInt2 == that.mInt2;
416 | }
417 |
418 | @Override
419 | public int hashCode() {
420 | int result = super.hashCode();
421 | result = 31 * result + mInt2;
422 | return result;
423 | }
424 |
425 | @Override
426 | public void writeToParcel(Parcel dest, int flags) {
427 | super.writeToParcel(dest, flags);
428 | dest.writeInt(mInt2);
429 | }
430 |
431 | @Override
432 | public int describeContents() {
433 | return 0;
434 | }
435 |
436 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
437 | @Override
438 | public TestTypes.ParcelableImpl createFromParcel(Parcel in) {
439 | return new TestTypes.ParcelableImpl(in);
440 | }
441 |
442 | @Override
443 | public TestTypes.ParcelableImpl[] newArray(int size) {
444 | return new TestTypes.ParcelableImpl[size];
445 | }
446 | };
447 | }
448 |
449 | }
450 |
--------------------------------------------------------------------------------