Bug 1351573 - Add Leanplum SDK as module r?maliu,sebastian,nalexander draft
authorcnevinc <cnevinc@livemail.tw>
Thu, 11 May 2017 21:01:53 -0700
changeset 576729 f411aadf73aa8a3316be5f13314f605e57023e90
parent 576689 ad45e59c7683a1354c8b73566f653d515f8d9a42
child 628284 136c66a3696c57b3fa844d12b0a937ab00868cbe
push id58455
push userbmo:cnevinchen@gmail.com
push dateFri, 12 May 2017 04:19:06 +0000
reviewersmaliu, sebastian, nalexander
bugs1351573
milestone55.0a1
Bug 1351573 - Add Leanplum SDK as module r?maliu,sebastian,nalexander MozReview-Commit-ID: Fz9D7vnodGX
mobile/android/app/build.gradle
mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
mobile/android/leanplum/.gitignore
mobile/android/leanplum/.gradle/3.3/taskArtifacts/fileHashes.bin
mobile/android/leanplum/.gradle/3.3/taskArtifacts/fileSnapshots.bin
mobile/android/leanplum/.gradle/3.3/taskArtifacts/taskArtifacts.bin
mobile/android/leanplum/.gradle/3.3/taskArtifacts/taskArtifacts.lock
mobile/android/leanplum/AndroidSDK/AndroidManifest.xml
mobile/android/leanplum/AndroidSDK/build.gradle
mobile/android/leanplum/AndroidSDK/consumer-proguard-rules.pro
mobile/android/leanplum/AndroidSDK/lint.xml
mobile/android/leanplum/AndroidSDK/out.map
mobile/android/leanplum/AndroidSDK/proguard-rules.pro
mobile/android/leanplum/AndroidSDK/project.properties
mobile/android/leanplum/AndroidSDK/res/values/strings.xml
mobile/android/leanplum/AndroidSDK/src/com/leanplum/ActionArgs.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/ActionContext.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/CacheUpdateBlock.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/Leanplum.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumActivityHelper.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumApplication.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumCloudMessagingProvider.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumDeviceIdMode.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumEditorMode.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumException.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumGcmProvider.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumInbox.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumInboxMessage.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumInflater.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumLocalPushListenerService.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumLocationAccuracyType.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumManualProvider.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushInstanceIDService.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushListenerService.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushNotificationCustomizer.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushReceiver.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushRegistrationService.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushService.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumResources.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumUIEditor.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LocationManager.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/LocationManagerImplementation.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/Newsfeed.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/NewsfeedMessage.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/ReceiveTransitionsIntentService.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/UIEditorBridge.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/Var.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumAccountAuthenticatorActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumActionBarActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumActivityGroup.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumAliasActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumAppCompatActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumExpandableListActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumFragmentActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumLauncherActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumListActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumNativeActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumPreferenceActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumTabActivity.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/annotations/File.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/annotations/Parser.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/annotations/Variable.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/ActionCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/InboxChangedCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/NewsfeedChangedCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/PostponableAction.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/RegisterDeviceCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/RegisterDeviceFinishedCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/StartCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/VariableCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/VariablesChangedCallback.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/AESCrypt.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/ActionArg.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/ActionManager.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/BaseActionContext.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/CollectionUtil.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Constants.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/FileManager.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/HybiParser.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/JsonConverter.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumInternal.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumManifestHelper.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumManifestParser.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumMessageMatchFilter.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumUIEditorWrapper.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Log.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/OsHandler.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Registration.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Request.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/RequestFactory.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/ResourceQualifiers.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Socket.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/SocketIOClient.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Util.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/VarCache.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/WebSocketClient.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/Alert.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/BaseMessageDialog.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/BaseMessageOptions.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/CenterPopup.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/CenterPopupOptions.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/Confirm.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/HTMLOptions.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/HTMLTemplate.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/Interstitial.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/InterstitialOptions.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/MessageTemplates.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/OpenURL.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/WebInterstitial.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/WebInterstitialOptions.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/utils/BitmapUtil.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/utils/SharedPreferencesUtil.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/utils/SizeUtil.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/views/BackgroundImageView.java
mobile/android/leanplum/AndroidSDK/src/com/leanplum/views/CloseButton.java
mobile/android/leanplum/LICENSE
mobile/android/leanplum/README.md
mobile/android/leanplum/build.gradle
mobile/android/leanplum/build.sh
mobile/android/leanplum/gradle/wrapper/gradle-wrapper.properties
mobile/android/leanplum/gradlew
mobile/android/leanplum/gradlew.bat
mobile/android/leanplum/local.properties
mobile/android/leanplum/settings.gradle
settings.gradle
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -277,16 +277,17 @@ dependencies {
 
     testCompile 'junit:junit:4.12'
     testCompile 'org.robolectric:robolectric:3.1.2'
     testCompile 'org.simpleframework:simple-http:6.0.1'
     testCompile 'org.mockito:mockito-core:1.10.19'
 
     // Including the Robotium JAR directly can cause issues with dexing.
     androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.5.4'
+    compile project(path: ':leanplum')
 }
 
 // TODO: (bug 1261486): This impl is not robust -
 // we just wanted to land something.
 task checkstyle(type: Checkstyle) {
     configFile file("checkstyle.xml")
     // TODO: should use sourceSets from project instead of hard-coded str.
     source = ['../base/java/','../geckoview/src/main/java/']
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko;
 import android.app.Application;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.leanplum.Leanplum;
 import com.squareup.leakcanary.LeakCanary;
 import com.squareup.leakcanary.RefWatcher;
 
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.LocalBrowserDB;
 import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.home.HomePanelsManager;
@@ -153,16 +154,17 @@ public class GeckoApplication extends Ap
             GeckoNetworkManager.getInstance().start(this);
         }
 
         mInBackground = false;
     }
 
     @Override
     public void onCreate() {
+        Leanplum.start(this);
         Log.i(LOG_TAG, "zerdatime " + SystemClock.elapsedRealtime() +
               " - application start");
 
         // PRNG is a pseudorandom number generator.
         // We need to apply PRNG Fixes before any use of Java Cryptography Architecture.
         // We make use of various JCA methods in data providers for generating GUIDs, as part of FxA
         // flow and during syncing. Note that this is a no-op for devices running API>18, and so we
         // accept the performance penalty on older devices.
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/.gitignore
@@ -0,0 +1,162 @@
+## macOS
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+## Windows
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+## Linux
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+## Jetbrains
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# CMake
+cmake-build-debug/
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+## Android
+# Built application files
+*.apk
+*.ap_
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+.gradle/
+build/
+
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# Intellij
+*.iml
+.idea/workspace.xml
+
+# Keystore files
+*.jks
+
+
+## CUSTOM
+
+Release/
new file mode 100644
index 0000000000000000000000000000000000000000..1681c5032834c5a64a39addc2e577390d72545a4
GIT binary patch
literal 299669
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
FK>){Cwd4Q*
new file mode 100644
index 0000000000000000000000000000000000000000..1db4735c98e91882ebf0ead09e3d50587b75ccf2
GIT binary patch
literal 1410691
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
new file mode 100644
index 0000000000000000000000000000000000000000..907c0989da5297475b8f60bca3af6d9b28825669
GIT binary patch
literal 67314
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
R1QtOT3xAS>I+$S!{ttp0>GJ>p
new file mode 100644
index 0000000000000000000000000000000000000000..0c42f57499bab04d49147a5f117ac810c410713a
GIT binary patch
literal 17
Vc${N?bo0=M=6{T*8NfhP8URXX1?~U<
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/AndroidManifest.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.leanplum"
+    android:versionCode="1" android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="10" />
+
+    <!-- Minimum permissions needed for SDK to work -->
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <!-- Permissions for GCM -->
+    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
+    <permission android:name="${applicationId}.permission.C2D_MESSAGE"
+        android:protectionLevel="signature" />
+    <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
+
+    <application>
+
+        <!-- Leanplum Push Notification Receiver for GCM and FCM -->
+        <receiver android:name="com.leanplum.LeanplumPushReceiver" android:exported="false"
+            android:enabled="true">
+            <intent-filter>
+                <action android:name="com.leanplum.LeanplumPushListenerService" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true"
+            android:enabled="false" android:permission="com.google.android.c2dm.permission.SEND">
+            <intent-filter>
+                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
+                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
+                <category android:name="${applicationId}"/>
+            </intent-filter>
+        </receiver>
+
+        <!-- Leanplum Local Push Notification Service-->
+        <service android:name="com.leanplum.LeanplumLocalPushListenerService" />
+
+        <!-- Leanplum GCM Message Handling Service -->
+        <service android:name="com.leanplum.LeanplumPushListenerService" android:exported="false"
+            android:enabled="false">
+            <intent-filter>
+                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
+            </intent-filter>
+        </service>
+
+        <!-- Leanplum GCM Instance ID Service -->
+        <service android:name="com.leanplum.LeanplumPushInstanceIDService" android:exported="false"
+            android:enabled="false">
+            <intent-filter>
+                <action android:name="com.google.android.gms.iid.InstanceID" />
+            </intent-filter>
+        </service>
+
+        <!-- Leanplum GCM/FCM Registration Service -->
+        <service android:name="com.leanplum.LeanplumPushRegistrationService" />
+
+
+        <!-- Geofencing Service -->
+        <service android:name="com.leanplum.ReceiveTransitionsIntentService" />
+    </application>
+</manifest>
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/build.gradle
@@ -0,0 +1,64 @@
+apply plugin: 'com.android.library'
+
+allprojects {
+    gradle.projectsEvaluated {
+        tasks.withType(JavaCompile) {
+            options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+        }
+    }
+}
+
+dependencies {
+    compile "com.android.support:support-v4:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}"
+    compile "com.android.support:appcompat-v7:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}"
+    compile "com.google.android.gms:play-services-gcm:${mozconfig.substs.ANDROID_GOOGLE_PLAY_SERVICES_VERSION}"
+    compile "com.google.android.gms:play-services-location:${mozconfig.substs.ANDROID_GOOGLE_PLAY_SERVICES_VERSION}"
+}
+
+android {
+    compileSdkVersion 23
+    buildToolsVersion mozconfig.substs.ANDROID_BUILD_TOOLS_VERSION
+    useLibrary 'org.apache.http.legacy'
+    publishNonDefault true
+
+    defaultConfig {
+        consumerProguardFiles 'consumer-proguard-rules.pro'
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled true
+            proguardFiles 'proguard-rules.pro'
+
+        }
+        buildTypes.each {
+            def packageIdentifier = '\"' + (System.getenv("LEANPLUM_PACKAGE_IDENTIFIER") ?: "s") +
+                    '\"'
+            it.buildConfigField 'String', 'LEANPLUM_PACKAGE_IDENTIFIER', packageIdentifier
+        }
+    }
+
+    sourceSets {
+        main {
+            manifest.srcFile 'AndroidManifest.xml'
+            java.srcDirs = ['src']
+            resources.srcDirs = ['src']
+            aidl.srcDirs = ['src']
+            renderscript.srcDirs = ['src']
+            res.srcDirs = ['res']
+            assets.srcDirs = ['assets']
+        }
+
+        // Move the tests to tests/java, tests/res, etc...
+        instrumentTest.setRoot('tests')
+
+        // Move the build types to build-types/<type>
+        // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
+        // This moves them out of them default location under src/<type>/... which would
+        // conflict with src/ being used by the main source set.
+        // Adding new build types or product flavors should be accompanied
+        // by a similar customization.
+        debug.setRoot('build-types/debug')
+        release.setRoot('build-types/release')
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/consumer-proguard-rules.pro
@@ -0,0 +1,16 @@
+# Keep default Leanplum classes.
+-keepclassmembers class * {
+@com.leanplum.annotations.* <fields>;
+}
+
+-keep class com.leanplum.** { *; }
+-dontwarn com.leanplum.**
+
+# Keep bytebuddy classes.
+-keep class net.bytebuddy.** { *; }
+-dontwarn net.bytebuddy.**
+
+# Keep Support Library classes.
+-dontwarn android.support.v7.**
+-keep class android.support.v7.** { *; }
+-keep interface android.support.v7.** { *; }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/lint.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<lint>
+    <issue id="DefaultLocale">
+        <ignore path="src/com/leanplum/LeanplumResources.java" />
+        <ignore path="src/com/leanplum/ResourceQualifiers.java" />
+    </issue>
+</lint>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/out.map
@@ -0,0 +1,2012 @@
+com.leanplum.AESCrypt -> com.leanplum.a:
+    java.lang.String APP_ID_KEY_PREFIX -> a
+    java.lang.String APP_ID_KEY_SUFFIX -> b
+    java.lang.String appId -> c
+    java.lang.String token -> d
+    105:108:void <init>(java.lang.String,java.lang.String) -> <init>
+    111:111:java.lang.String appIdKeyPassword() -> a
+    120:137:java.lang.String encrypt(java.lang.String) -> a
+    141:149:java.lang.String decodePreference(android.content.SharedPreferences,java.lang.String,java.lang.String) -> a
+    1159:1192:java.lang.String decrypt(java.lang.String):159:192 -> a
+    1159:1192:java.lang.String decodePreference(android.content.SharedPreferences,java.lang.String,java.lang.String):145 -> a
+    201:205:java.lang.String encryptInternal(java.lang.String,java.lang.String) -> a
+    210:226:byte[] parseCiphertextInternal(java.lang.String) -> b
+    239:252:java.lang.String decryptInternal(java.lang.String,java.lang.String) -> b
+    268:293:byte[] performCryptOperation(int,java.lang.String,byte[]) -> a
+    92:95:void <clinit>() -> <clinit>
+com.leanplum.AESCrypt$1 -> com.leanplum.b:
+    int[] $SwitchMap$com$leanplum$AESCrypt$EncryptionType -> a
+    164:164:void <clinit>() -> <clinit>
+com.leanplum.AESCrypt$EncryptionType -> com.leanplum.c:
+    com.leanplum.AESCrypt$EncryptionType LEGACY_TOKEN -> a
+    com.leanplum.AESCrypt$EncryptionType APP_ID_KEY -> b
+    java.lang.String prefix -> c
+    java.lang.String prefixWithBracket -> d
+    com.leanplum.AESCrypt$EncryptionType[] $VALUES -> e
+    35:35:com.leanplum.AESCrypt$EncryptionType[] values() -> values
+    35:35:com.leanplum.AESCrypt$EncryptionType valueOf(java.lang.String) -> valueOf
+    62:66:void <init>(java.lang.String,int,int) -> <init>
+    76:86:android.util.Pair parseCipherText(java.lang.String) -> a
+    35:56:void <clinit>() -> <clinit>
+com.leanplum.ActionArg -> com.leanplum.d:
+    java.lang.String name -> a
+    java.lang.String kind -> b
+    java.lang.Object defaultValue -> c
+    boolean isAsset -> d
+    21:22:void <init>() -> <init>
+    25:29:com.leanplum.ActionArg argNamed(java.lang.String,java.lang.Object,java.lang.String) -> a
+    38:38:com.leanplum.ActionArg argNamed(java.lang.String,java.lang.Object) -> a
+    42:42:com.leanplum.ActionArg colorArgNamed(java.lang.String,int) -> a
+    46:52:com.leanplum.ActionArg fileArgNamed(java.lang.String,java.lang.String) -> a
+    56:60:com.leanplum.ActionArg assetArgNamed(java.lang.String,java.lang.String) -> b
+    64:67:com.leanplum.ActionArg actionArgNamed(java.lang.String,java.lang.String) -> c
+    71:71:java.lang.String name() -> a
+    75:75:java.lang.String kind() -> b
+    79:79:java.lang.Object defaultValue() -> c
+    83:86:java.io.InputStream defaultStream() -> d
+    1035:1036:boolean com.leanplum.GeofenceStatus.shouldTriggerEnteredGeofence(java.lang.Number,java.lang.Number):35:36 -> a
+    1040:1041:boolean com.leanplum.GeofenceStatus.shouldTriggerExitedGeofence(java.lang.Number,java.lang.Number):40:41 -> b
+    2024:2031:java.lang.String com.leanplum.JsonConverter.toJson(java.util.Map):24:31 -> a
+    2036:2043:java.util.Map com.leanplum.JsonConverter.fromJson(java.lang.String):36:43 -> a
+    2049:2064:org.json.JSONObject com.leanplum.JsonConverter.mapToJsonObject(java.util.Map):49:64 -> b
+    2069:2083:org.json.JSONArray com.leanplum.JsonConverter.listToJsonArray(java.lang.Iterable):69:83 -> a
+    2088:2107:java.util.Map com.leanplum.JsonConverter.mapFromJson(org.json.JSONObject):88:107 -> a
+    2112:2129:java.util.List com.leanplum.JsonConverter.listFromJson(org.json.JSONArray):112:129 -> a
+com.leanplum.ActionArgs -> com.leanplum.ActionArgs:
+    java.util.List args -> a
+    14:17:void <init>() -> <init>
+    28:33:com.leanplum.ActionArgs with(java.lang.String,java.lang.Object) -> with
+    42:47:com.leanplum.ActionArgs withColor(java.lang.String,int) -> withColor
+    57:62:com.leanplum.ActionArgs withFile(java.lang.String,java.lang.String) -> withFile
+    73:78:com.leanplum.ActionArgs withAsset(java.lang.String,java.lang.String) -> withAsset
+    87:92:com.leanplum.ActionArgs withAction(java.lang.String,java.lang.String) -> withAction
+    96:96:java.util.List getValue() -> a
+com.leanplum.ActionContext -> com.leanplum.ActionContext:
+    java.lang.String name -> a
+    java.lang.String messageId -> b
+    java.util.Map args -> c
+    com.leanplum.ActionContext parentContext -> d
+    int contentVersion -> e
+    java.lang.String key -> f
+    boolean preventRealtimeUpdating -> g
+    boolean isRooted -> h
+    boolean isPreview -> i
+    com.leanplum.ActionContext$ContextualValues contextualValues -> j
+    int priority -> k
+    51:52:void <init>(java.lang.String,java.util.Map,java.lang.String) -> <init>
+    27:60:void <init>(java.lang.String,java.util.Map,java.lang.String,int) -> <init>
+    63:64:void preventRealtimeUpdating() -> a
+    67:68:void setIsRooted(boolean) -> a
+    71:72:void setContextualValues(com.leanplum.ActionContext$ContextualValues) -> a
+    77:81:java.util.Map getDefinition(java.lang.String) -> a
+    90:94:java.util.Map defaultValues() -> g
+    1085:1085:java.util.Map getDefinition():85:85 -> g
+    1085:1085:java.util.Map defaultValues():90 -> g
+    107:108:void update() -> b
+    113:143:void updateArgs(java.util.Map,java.lang.String,java.util.Map) -> a
+    1099:1103:java.util.Map kinds():99:103 -> a
+    1099:1103:void updateArgs(java.util.Map,java.lang.String,java.util.Map):113 -> a
+    2085:2085:java.util.Map getDefinition():85:85 -> a
+    2085:2085:java.util.Map kinds():99 -> a
+    2085:2085:void updateArgs(java.util.Map,java.lang.String,java.util.Map):113 -> a
+    146:146:java.lang.String actionName() -> actionName
+    151:175:java.lang.Object objectNamed(java.lang.String) -> objectNamed
+    180:193:java.lang.String stringNamed(java.lang.String) -> stringNamed
+    2198:2215:java.lang.String fillTemplate(java.lang.String):198:215 -> stringNamed
+    2198:2215:java.lang.String stringNamed(java.lang.String):190 -> stringNamed
+    237:255:java.io.InputStream streamNamed(java.lang.String) -> streamNamed
+    2220:2232:java.lang.String getDefaultValue(java.lang.String):220:232 -> streamNamed
+    2220:2232:java.io.InputStream streamNamed(java.lang.String):242 -> streamNamed
+    260:272:boolean booleanNamed(java.lang.String) -> booleanNamed
+    277:289:java.lang.Number numberNamed(java.lang.String) -> numberNamed
+    295:303:java.util.Map getChildArgs(java.lang.String) -> b
+    307:328:void runActionNamed(java.lang.String) -> runActionNamed
+    332:372:void runTrackedActionNamed(java.lang.String) -> runTrackedActionNamed
+    376:388:void track(java.lang.String,double,java.util.Map) -> track
+    392:396:void muteFutureMessagesOfSameKind() -> muteFutureMessagesOfSameKind
+    399:399:int compareTo(com.leanplum.ActionContext) -> compareTo
+    2407:2407:int priority():407:407 -> compareTo
+    2407:2407:int compareTo(com.leanplum.ActionContext):399 -> compareTo
+    3407:3407:int priority():407:407 -> compareTo
+    3407:3407:int compareTo(com.leanplum.ActionContext):399 -> compareTo
+    403:403:java.lang.String messageId() -> c
+    407:407:int priority() -> d
+    411:411:java.util.Map args() -> e
+    415:416:void setIsPreview(boolean) -> b
+    419:419:boolean isPreview() -> f
+    18:18:int compareTo(java.lang.Object) -> compareTo
+com.leanplum.ActionContext$ContextualValues -> com.leanplum.e:
+    java.util.Map parameters -> a
+    java.lang.Object previousAttributeValue -> b
+    java.lang.Object attributeValue -> c
+    33:33:void <init>() -> <init>
+com.leanplum.ActionManager -> com.leanplum.f:
+    java.util.Map messageImpressionOccurrences -> b
+    java.util.Map messageTriggerOccurrences -> c
+    java.util.Map sessionOccurrences -> d
+    com.leanplum.ActionManager instance -> e
+    java.lang.String PUSH_NOTIFICATION_ACTION_NAME -> a
+    boolean loggedLocationManagerFailure -> f
+    54:57:com.leanplum.ActionManager instance() -> a
+    63:86:com.leanplum.LocationManager getLocationManager() -> b
+    89:94:void <init>() -> <init>
+    1097:1253:void listenForLocalNotifications():97:253 -> <init>
+    1097:1253:void <init>():90 -> <init>
+    257:269:java.util.Map getMessageImpressionOccurrences(java.lang.String) -> d
+    289:299:int getMessageTriggerOccurrences(java.lang.String) -> e
+    320:347:com.leanplum.ActionManager$MessageMatchResult shouldShowMessage(java.lang.String,java.util.Map,java.lang.String,java.lang.String,com.leanplum.ActionContext$ContextualValues) -> a
+    1352:1392:boolean matchesLimits(java.lang.String,java.util.Map):352:392 -> a
+    1352:1392:com.leanplum.ActionManager$MessageMatchResult shouldShowMessage(java.lang.String,java.util.Map,java.lang.String,java.lang.String,com.leanplum.ActionContext$ContextualValues):346 -> a
+    1397:1445:boolean matchesLimitTimes(int,int,java.lang.String,java.util.Map,java.lang.String):397:445 -> a
+    1397:1445:boolean matchesLimits(java.lang.String,java.util.Map):372 -> a
+    1397:1445:com.leanplum.ActionManager$MessageMatchResult shouldShowMessage(java.lang.String,java.util.Map,java.lang.String,java.lang.String,com.leanplum.ActionContext$ContextualValues):346 -> a
+    451:461:boolean matchedTriggers(java.lang.Object,java.lang.String,java.lang.String,com.leanplum.ActionContext$ContextualValues) -> a
+    1467:1513:boolean matchedTrigger(java.util.Map,java.lang.String,java.lang.String,com.leanplum.ActionContext$ContextualValues):467:513 -> a
+    1467:1513:boolean matchedTriggers(java.lang.Object,java.lang.String,java.lang.String,com.leanplum.ActionContext$ContextualValues):456 -> a
+    517:520:void recordMessageTrigger(java.lang.String) -> a
+    2303:2315:void saveMessageTriggerOccurrences(int,java.lang.String):303:315 -> a
+    2303:2315:void recordMessageTrigger(java.lang.String):519 -> a
+    524:563:void recordMessageImpression(java.lang.String) -> b
+    3273:3286:void saveMessageImpressionOccurrences(java.util.Map,java.lang.String):273:286 -> b
+    3273:3286:void recordMessageImpression(java.lang.String):562 -> b
+    566:580:void muteFutureMessagesOfKind(java.lang.String) -> c
+    585:602:void getForegroundandBackgroundRegionNames(java.util.Set,java.util.Set) -> a
+    607:618:void addRegionNamesFromTriggersToSet(java.util.Map,java.util.Set) -> a
+    43:60:void <clinit>() -> <clinit>
+com.leanplum.ActionManager$1 -> com.leanplum.g:
+    97:97:void <init>(com.leanplum.ActionManager) -> <init>
+    102:210:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.ActionManager$2 -> com.leanplum.h:
+    215:215:void <init>(com.leanplum.ActionManager) -> <init>
+    219:249:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.ActionManager$MessageMatchResult -> com.leanplum.i:
+    boolean matchedTrigger -> a
+    boolean matchedUnlessTrigger -> b
+    boolean matchedLimit -> c
+    47:47:void <init>() -> <init>
+com.leanplum.BuildConfig -> com.leanplum.BuildConfig:
+    boolean DEBUG -> DEBUG
+    java.lang.String APPLICATION_ID -> APPLICATION_ID
+    java.lang.String BUILD_TYPE -> BUILD_TYPE
+    java.lang.String FLAVOR -> FLAVOR
+    int VERSION_CODE -> VERSION_CODE
+    java.lang.String VERSION_NAME -> VERSION_NAME
+    6:6:void <init>() -> <init>
+com.leanplum.Constants -> com.leanplum.j:
+    java.lang.String API_HOST_NAME -> a
+    java.lang.String SOCKET_HOST -> b
+    int SOCKET_PORT -> c
+    boolean API_SSL -> d
+    int NETWORK_TIMEOUT_SECONDS -> e
+    int NETWORK_TIMEOUT_SECONDS_FOR_DOWNLOADS -> f
+    java.lang.String LEANPLUM_VERSION -> g
+    java.lang.String CLIENT -> h
+    java.lang.String defaultDeviceId -> i
+    boolean hashFilesToDetermineModifications -> j
+    boolean isDevelopmentModeEnabled -> k
+    boolean isTestMode -> l
+    boolean enableVerboseLoggingInDevelopmentMode -> m
+    boolean enableFileUploadingInDevelopmentMode -> n
+    boolean canDownloadContentMidSessionInProduction -> o
+    boolean isInPermanentFailureState -> p
+    java.lang.String API_SERVLET -> q
+    37:37:boolean isNoop() -> a
+    10:40:void <clinit>() -> <clinit>
+com.leanplum.FileManager -> com.leanplum.FileManager:
+    com.leanplum.FileManager$ResourceUpdateCallback updateCallback -> c
+    com.leanplum.Var resources -> a
+    boolean hasInited -> d
+    boolean initializing -> e
+    java.lang.Object initializingLock -> b
+    64:100:com.leanplum.FileManager$DownloadFileResult maybeDownloadFile(boolean,java.lang.String,java.lang.String,java.lang.Runnable) -> a
+    106:135:com.leanplum.FileManager$HashResults fileMD5HashCreateWithPath(java.io.InputStream) -> a
+    140:140:int getFileSize(java.lang.String) -> a
+    144:144:boolean fileExistsAtPath(java.lang.String) -> d
+    167:167:java.lang.String fileRelativeTo(java.lang.String,java.lang.String) -> a
+    171:174:java.lang.String fileRelativeToAppBundle(java.lang.String) -> b
+    1148:1148:java.lang.String appBundlePath():148:148 -> b
+    1148:1148:java.lang.String fileRelativeToAppBundle(java.lang.String):174 -> b
+    178:178:java.lang.String fileRelativeToLPBundle(java.lang.String) -> e
+    1162:1163:java.lang.String bundlePath():162:163 -> e
+    1162:1163:java.lang.String fileRelativeToLPBundle(java.lang.String):178 -> e
+    182:182:java.lang.String fileRelativeToDocuments(java.lang.String) -> c
+    2152:2153:java.lang.String documentsPath():152:153 -> c
+    2152:2153:java.lang.String fileRelativeToDocuments(java.lang.String):182 -> c
+    188:198:boolean isNewerLocally(java.util.Map,java.util.Map) -> a
+    202:203:void setResourceSyncFinishBlock(com.leanplum.FileManager$ResourceUpdateCallback) -> a
+    210:210:boolean initializing() -> a
+    214:214:boolean isResourceSyncingEnabled() -> b
+    219:298:void enableResourceSyncing(java.util.List,java.util.List) -> b
+    301:313:java.util.List compilePatterns(java.util.List) -> a
+    318:345:void enableResourceSyncing(java.util.List,java.util.List,boolean) -> a
+    350:384:java.lang.String fileValue(java.lang.String,java.lang.String,java.lang.Boolean) -> a
+    389:409:java.io.InputStream stream(boolean,java.lang.Boolean,java.lang.Boolean,java.lang.String,java.lang.String,byte[]) -> a
+    33:33:void access$000(java.util.List,java.util.List) -> a
+    39:43:void <clinit>() -> <clinit>
+com.leanplum.FileManager$1 -> com.leanplum.k:
+    java.lang.Runnable val$onComplete -> a
+    79:79:void <init>(java.lang.Runnable) -> <init>
+    82:85:void response(org.json.JSONObject) -> a
+com.leanplum.FileManager$2 -> com.leanplum.l:
+    java.lang.Runnable val$onComplete -> a
+    87:87:void <init>(java.lang.Runnable) -> <init>
+    90:93:void error$698b7e31() -> a
+com.leanplum.FileManager$3 -> com.leanplum.m:
+    java.util.List val$compiledIncludePatterns -> a
+    java.util.List val$compiledExcludePatterns -> b
+    328:328:void <init>(java.util.List,java.util.List) -> <init>
+    332:336:java.lang.Void doInBackground$10299ca() -> a
+    328:328:java.lang.Object doInBackground(java.lang.Object[]) -> doInBackground
+com.leanplum.FileManager$DownloadFileResult -> com.leanplum.FileManager$DownloadFileResult:
+    com.leanplum.FileManager$DownloadFileResult NONE -> NONE
+    com.leanplum.FileManager$DownloadFileResult EXISTS_IN_ASSETS -> EXISTS_IN_ASSETS
+    com.leanplum.FileManager$DownloadFileResult DOWNLOADING -> DOWNLOADING
+    com.leanplum.FileManager$DownloadFileResult[] $VALUES -> a
+    45:45:com.leanplum.FileManager$DownloadFileResult[] values() -> values
+    45:45:com.leanplum.FileManager$DownloadFileResult valueOf(java.lang.String) -> valueOf
+    45:45:void <init>(java.lang.String,int) -> <init>
+    45:48:void <clinit>() -> <clinit>
+com.leanplum.FileManager$HashResults -> com.leanplum.n:
+    java.lang.String hash -> a
+    int size -> b
+    55:58:void <init>(java.lang.String,int) -> <init>
+com.leanplum.FileManager$ResourceUpdateCallback -> com.leanplum.o:
+    2172:2176:void com.leanplum.Leanplum$11.onResourceSyncFinish():1172:1176 -> a
+    3168:3168:void com.leanplum.Leanplum$11.<init>():1168:1168 -> <init>
+com.leanplum.HybiParser -> com.leanplum.p:
+    com.leanplum.WebSocketClient mClient -> a
+    boolean mMasking -> b
+    int mStage -> c
+    boolean mFinal -> d
+    boolean mMasked -> e
+    int mOpcode -> f
+    int mLengthSize -> g
+    int mLength -> h
+    int mMode -> i
+    byte[] mMask -> j
+    byte[] mPayload -> k
+    boolean mClosed -> l
+    java.io.ByteArrayOutputStream mBuffer -> m
+    java.util.List OPCODES -> n
+    java.util.List FRAGMENTED_OPCODES -> o
+    40:85:void <init>(com.leanplum.WebSocketClient) -> <init>
+    88:94:byte[] mask(byte[],byte[],int) -> a
+    99:123:void start(com.leanplum.HybiParser$HappyDataInputStream) -> a
+    1126:1148:void parseOpcode(byte):126:148 -> a
+    1126:1148:void start(com.leanplum.HybiParser$HappyDataInputStream):103 -> a
+    1151:1160:void parseLength(byte):151:160 -> a
+    1151:1160:void start(com.leanplum.HybiParser$HappyDataInputStream):106 -> a
+    1163:1165:void parseExtendedLength(byte[]):163:165 -> a
+    1163:1165:void start(com.leanplum.HybiParser$HappyDataInputStream):109 -> a
+    1326:1330:int getInteger(byte[]):326:330 -> a
+    1326:1330:void parseExtendedLength(byte[]):163 -> a
+    1326:1330:void start(com.leanplum.HybiParser$HappyDataInputStream):109 -> a
+    1384:1393:long byteArrayToLong(byte[],int,int):384:393 -> a
+    1384:1393:int getInteger(byte[]):326 -> a
+    1384:1393:void parseExtendedLength(byte[]):163 -> a
+    1384:1393:void start(com.leanplum.HybiParser$HappyDataInputStream):109 -> a
+    2249:2302:void emitFrame():249:302 -> a
+    2249:2302:void start(com.leanplum.HybiParser$HappyDataInputStream):117 -> a
+    2305:2307:void reset():305:307 -> a
+    2305:2307:void emitFrame():264 -> a
+    2305:2307:void start(com.leanplum.HybiParser$HappyDataInputStream):117 -> a
+    2373:2373:byte[] slice(byte[],int):373:373 -> a
+    2373:2373:void emitFrame():286 -> a
+    2373:2373:void start(com.leanplum.HybiParser$HappyDataInputStream):117 -> a
+    3358:3369:byte[] copyOfRange(byte[],int,int):358:369 -> a
+    3358:3369:byte[] slice(byte[],int):373 -> a
+    3358:3369:void emitFrame():286 -> a
+    3358:3369:void start(com.leanplum.HybiParser$HappyDataInputStream):117 -> a
+    4176:4176:byte[] frame(byte[],int,int):176:176 -> a
+    4176:4176:void emitFrame():295 -> a
+    4176:4176:void start(com.leanplum.HybiParser$HappyDataInputStream):117 -> a
+    168:168:byte[] frame(java.lang.String) -> a
+    4180:4180:byte[] frame(java.lang.String,int,int):180:180 -> a
+    4180:4180:byte[] frame(java.lang.String):168 -> a
+    184:234:byte[] frame(java.lang.Object,int,int) -> a
+    311:313:java.lang.String encode(byte[]) -> a
+    319:321:byte[] decode(java.lang.String) -> b
+    77:81:void <clinit>() -> <clinit>
+com.leanplum.HybiParser$HappyDataInputStream -> com.leanplum.q:
+    398:399:void <init>(java.io.InputStream) -> <init>
+    402:420:byte[] readBytes(int) -> a
+com.leanplum.HybiParser$ProtocolError -> com.leanplum.r:
+    379:380:void <init>(java.lang.String) -> <init>
+com.leanplum.Leanplum -> com.leanplum.Leanplum:
+    int ACTION_KIND_MESSAGE -> ACTION_KIND_MESSAGE
+    int ACTION_KIND_ACTION -> ACTION_KIND_ACTION
+    java.lang.String PURCHASE_EVENT_NAME -> PURCHASE_EVENT_NAME
+    java.util.ArrayList startHandlers -> d
+    java.util.ArrayList startIssuedHandlers -> e
+    java.util.ArrayList variablesChangedHandlers -> f
+    java.util.ArrayList noDownloadsHandlers -> g
+    java.util.ArrayList onceNoDownloadsHandlers -> h
+    java.util.Map actionHandlers -> i
+    com.leanplum.callbacks.RegisterDeviceCallback registerDeviceHandler -> j
+    com.leanplum.callbacks.RegisterDeviceFinishedCallback registerDeviceFinishedHandler -> k
+    com.leanplum.ActionManager actionManager -> l
+    boolean calledStart -> a
+    boolean issuedStart -> m
+    boolean hasStarted -> n
+    boolean startSuccessful -> o
+    boolean hasStartedAndRegisteredAsDeveloper -> p
+    boolean isPaused -> b
+    com.leanplum.LeanplumDeviceIdMode deviceIdMode -> q
+    java.lang.String customDeviceId -> r
+    boolean userSpecifiedDeviceId -> s
+    boolean initializedMessageTemplates -> t
+    boolean startedInBackground -> c
+    boolean inForeground -> u
+    java.lang.Object inForegroundLock -> v
+    java.util.concurrent.ScheduledExecutorService heartbeatExecutor -> w
+    java.lang.Object heartbeatLock -> x
+    android.content.Context context -> y
+    java.util.Queue userAttributeChanges -> z
+    java.lang.Runnable gcmStartCallback -> A
+    61:61:void <init>() -> <init>
+    137:149:void setApiConnectionSettings(java.lang.String,java.lang.String,boolean) -> setApiConnectionSettings
+    157:168:void setSocketConnectionSettings(java.lang.String,int) -> setSocketConnectionSettings
+    180:181:void setFileHashingEnabledInDevelopmentMode(boolean) -> setFileHashingEnabledInDevelopmentMode
+    189:190:void setFileUploadingEnabledInDevelopmentMode(boolean) -> setFileUploadingEnabledInDevelopmentMode
+    196:197:void enableVerboseLoggingInDevelopmentMode() -> enableVerboseLoggingInDevelopmentMode
+    204:215:void setNetworkTimeout(int,int) -> setNetworkTimeout
+    225:226:void setCanDownloadContentMidSessionInProductionMode(boolean) -> setCanDownloadContentMidSessionInProductionMode
+    235:246:void setAppIdForDevelopmentMode(java.lang.String,java.lang.String) -> setAppIdForDevelopmentMode
+    255:266:void setAppIdForProductionMode(java.lang.String,java.lang.String) -> setAppIdForProductionMode
+    272:279:void setDeviceIdMode(com.leanplum.LeanplumDeviceIdMode) -> setDeviceIdMode
+    286:292:void setDeviceId(java.lang.String) -> setDeviceId
+    298:303:void setApplicationContext(android.content.Context) -> setApplicationContext
+    309:315:android.content.Context getContext() -> getContext
+    324:330:void setRegisterDeviceHandler(com.leanplum.callbacks.RegisterDeviceCallback,com.leanplum.callbacks.RegisterDeviceFinishedCallback) -> setRegisterDeviceHandler
+    339:347:void syncResources() -> syncResources
+    354:362:void syncResourcesAsync() -> syncResourcesAsync
+    382:386:void syncResources(java.util.List,java.util.List) -> syncResources
+    406:410:void syncResourcesAsync(java.util.List,java.util.List) -> syncResourcesAsync
+    416:416:boolean isResourceSyncingEnabled() -> isResourceSyncingEnabled
+    425:426:void start(android.content.Context) -> start
+    434:435:void start(android.content.Context,com.leanplum.callbacks.StartCallback) -> start
+    443:444:void start(android.content.Context,java.util.Map) -> start
+    452:453:void start(android.content.Context,java.lang.String) -> start
+    461:462:void start(android.content.Context,java.lang.String,com.leanplum.callbacks.StartCallback) -> start
+    470:471:void start(android.content.Context,java.lang.String,java.util.Map) -> start
+    480:481:void start(android.content.Context,java.lang.String,java.util.Map,com.leanplum.callbacks.StartCallback) -> start
+    486:587:void start(android.content.Context,java.lang.String,java.util.Map,com.leanplum.callbacks.StartCallback,java.lang.Boolean) -> a
+    872:884:void moveToForeground() -> m
+    890:918:void reset() -> reset
+    924:927:void setClient(java.lang.String,java.lang.String,java.lang.String) -> setClient
+    934:939:void maybeThrowException(java.lang.RuntimeException) -> a
+    950:985:java.util.Map validateAttributes(java.util.Map,java.lang.String,boolean) -> a
+    990:995:boolean isValidScalarValue(java.lang.Object,java.lang.String) -> a
+    1003:1026:void pause() -> a
+    1029:1031:void pauseInternal() -> n
+    3095:3100:void pauseHeartbeat():1095:1100 -> n
+    3095:3100:void pauseInternal():1030 -> n
+    1038:1061:void resume() -> b
+    1064:1074:void resumeInternal() -> o
+    3103:3104:void resumeHeartbeat():1103:1104 -> o
+    3103:3104:void resumeInternal():1073 -> o
+    1080:1092:void startHeartbeat() -> p
+    1143:1143:boolean hasStarted() -> hasStarted
+    1150:1150:com.leanplum.Newsfeed newsfeed() -> newsfeed
+    1158:1158:boolean hasStartedAndRegisteredAsDeveloper() -> hasStartedAndRegisteredAsDeveloper
+    1166:1182:void onHasStartedAndRegisteredAsDeveloper() -> c
+    1185:1188:void onHasStartedAndRegisteredAsDeveloperAndFinishedSyncing() -> q
+    1195:1212:void addStartResponseHandler(com.leanplum.callbacks.StartCallback) -> addStartResponseHandler
+    1218:1226:void removeStartResponseHandler(com.leanplum.callbacks.StartCallback) -> removeStartResponseHandler
+    1229:1236:void triggerStartResponse(boolean) -> a
+    1239:1251:void addStartIssuedHandler(java.lang.Runnable) -> a
+    1254:1261:void triggerStartIssued() -> r
+    1269:1280:void addVariablesChangedHandler(com.leanplum.callbacks.VariablesChangedCallback) -> addVariablesChangedHandler
+    1286:1294:void removeVariablesChangedHandler(com.leanplum.callbacks.VariablesChangedCallback) -> removeVariablesChangedHandler
+    1297:1302:void triggerVariablesChanged() -> s
+    1310:1323:void addVariablesChangedAndNoDownloadsPendingHandler(com.leanplum.callbacks.VariablesChangedCallback) -> addVariablesChangedAndNoDownloadsPendingHandler
+    1330:1339:void removeVariablesChangedAndNoDownloadsPendingHandler(com.leanplum.callbacks.VariablesChangedCallback) -> removeVariablesChangedAndNoDownloadsPendingHandler
+    1347:1361:void addOnceVariablesChangedAndNoDownloadsPendingHandler(com.leanplum.callbacks.VariablesChangedCallback) -> addOnceVariablesChangedAndNoDownloadsPendingHandler
+    1368:1377:void removeOnceVariablesChangedAndNoDownloadsPendingHandler(com.leanplum.callbacks.VariablesChangedCallback) -> removeOnceVariablesChangedAndNoDownloadsPendingHandler
+    1380:1391:void triggerVariablesChangedAndNoDownloadsPending() -> d
+    1402:1403:void defineAction(java.lang.String,int,com.leanplum.ActionArgs) -> defineAction
+    1422:1423:void defineAction(java.lang.String,int,com.leanplum.ActionArgs,com.leanplum.callbacks.ActionCallback) -> defineAction
+    1427:1454:void defineAction(java.lang.String,int,com.leanplum.ActionArgs,java.util.Map,com.leanplum.callbacks.ActionCallback) -> a
+    1462:1477:void onAction(java.lang.String,com.leanplum.callbacks.ActionCallback) -> onAction
+    1480:1481:void triggerAction(com.leanplum.ActionContext) -> a
+    1486:1510:void triggerAction(com.leanplum.ActionContext,com.leanplum.callbacks.VariablesChangedCallback) -> a
+    1514:1515:void maybePerformActions(java.lang.String,java.lang.String,int,java.lang.String,com.leanplum.ActionContext$ContextualValues) -> a
+    1520:1613:void maybePerformActions(java.lang.String[],java.lang.String,int,java.lang.String,com.leanplum.ActionContext$ContextualValues) -> a
+    1635:1648:void performTrackedAction(java.lang.String,java.lang.String) -> a
+    1654:1689:void setUserAttributes(java.lang.String,java.util.Map) -> setUserAttributes
+    1693:1701:void setUserAttributesInternal(java.lang.String,java.util.HashMap) -> b
+    1704:1726:void recordAttributeChanges() -> t
+    1732:1738:void setUserId(java.lang.String) -> setUserId
+    1744:1750:void setUserAttributes(java.util.Map) -> setUserAttributes
+    1756:1775:void setGcmRegistrationId(java.lang.String) -> a
+    1783:1816:void setTrafficSourceInfo(java.util.Map) -> setTrafficSourceInfo
+    1819:1820:void setTrafficSourceInfoInternal(java.util.HashMap) -> b
+    1841:1842:void track(java.lang.String,double,java.lang.String,java.util.Map) -> track
+    1846:1879:void track(java.lang.String,double,java.lang.String,java.util.Map,java.util.Map) -> a
+    3890:3904:void trackInternalWhenStarted(java.lang.String,java.util.Map,java.util.Map):1890:1904 -> a
+    3890:3904:void track(java.lang.String,double,java.lang.String,java.util.Map,java.util.Map):1875 -> a
+    1914:1931:void trackInternal(java.lang.String,java.util.Map,java.util.Map) -> c
+    1943:1945:void trackGooglePlayPurchase(java.lang.String,long,java.lang.String,java.lang.String,java.lang.String) -> trackGooglePlayPurchase
+    1958:1960:void trackGooglePlayPurchase(java.lang.String,long,java.lang.String,java.lang.String,java.lang.String,java.util.Map) -> trackGooglePlayPurchase
+    1976:1994:void trackGooglePlayPurchase(java.lang.String,java.lang.String,long,java.lang.String,java.lang.String,java.lang.String,java.util.Map) -> trackGooglePlayPurchase
+    2005:2006:void track(java.lang.String) -> track
+    2020:2021:void track(java.lang.String,double) -> track
+    2034:2035:void track(java.lang.String,java.lang.String) -> track
+    2048:2049:void track(java.lang.String,java.util.Map) -> track
+    2065:2066:void track(java.lang.String,double,java.util.Map) -> track
+    2082:2083:void track(java.lang.String,double,java.lang.String) -> track
+    2097:2138:void advanceTo(java.lang.String,java.lang.String,java.util.Map) -> advanceTo
+    2148:2155:void advanceToInternal(java.lang.String,java.util.Map,java.util.Map) -> d
+    2165:2166:void advanceTo(java.lang.String) -> advanceTo
+    2178:2179:void advanceTo(java.lang.String,java.lang.String) -> advanceTo
+    2191:2192:void advanceTo(java.lang.String,java.util.Map) -> advanceTo
+    2200:2226:void pauseState() -> pauseState
+    2229:2230:void pauseStateInternal() -> u
+    2236:2262:void resumeState() -> resumeState
+    2265:2266:void resumeStateInternal() -> v
+    2274:2275:void forceContentUpdate() -> forceContentUpdate
+    2287:2343:void forceContentUpdate(com.leanplum.callbacks.VariablesChangedCallback) -> forceContentUpdate
+    2350:2351:void enableTestMode() -> enableTestMode
+    2354:2354:boolean isTestModeEnabled() -> isTestModeEnabled
+    2362:2363:void setIsTestModeEnabled(boolean) -> setIsTestModeEnabled
+    2370:2376:java.lang.String pathForResource(java.lang.String) -> pathForResource
+    2385:2393:java.lang.Object objectForKeyPath(java.lang.Object[]) -> objectForKeyPath
+    2403:2413:java.lang.Object objectForKeyPathComponents(java.lang.Object[]) -> objectForKeyPathComponents
+    2421:2425:java.util.List variants() -> variants
+    49:49:void access$000() -> e
+    49:49:void access$100(java.lang.String,java.util.Map,boolean) -> a
+    4591:4674:void startHelper(java.lang.String,java.util.Map,boolean):591:674 -> a
+    4591:4674:void access$100(java.lang.String,java.util.Map,boolean):49 -> a
+    49:49:void access$200(org.json.JSONObject,java.util.List) -> a
+    4677:4702:void handleApiResponse(org.json.JSONObject,java.util.List):677:702 -> a
+    4677:4702:void access$200(org.json.JSONObject,java.util.List):49 -> a
+    4705:4869:void handleStartResponse(org.json.JSONObject):705:869 -> a
+    4705:4869:void handleApiResponse(org.json.JSONObject,java.util.List):699 -> a
+    4705:4869:void access$200(org.json.JSONObject,java.util.List):49 -> a
+    49:49:com.leanplum.callbacks.RegisterDeviceFinishedCallback access$300() -> f
+    49:49:void access$400() -> g
+    49:49:void access$500() -> h
+    49:49:void access$700() -> i
+    49:49:com.leanplum.ActionManager access$800() -> j
+    49:49:void access$900(java.lang.String,java.util.HashMap) -> a
+    49:49:void access$1000(java.util.HashMap) -> a
+    49:49:void access$1100(java.lang.String,java.util.Map,java.util.Map) -> a
+    49:49:void access$1200(java.lang.String,java.util.Map,java.util.Map) -> b
+    49:49:void access$1300() -> k
+    49:49:void access$1400() -> l
+    51:98:void <clinit>() -> <clinit>
+com.leanplum.Leanplum$12 -> com.leanplum.s:
+    com.leanplum.callbacks.ActionCallback val$callback -> a
+    com.leanplum.ActionContext val$context -> b
+    com.leanplum.callbacks.VariablesChangedCallback val$handledCallback -> c
+    java.util.concurrent.atomic.AtomicBoolean val$handled -> d
+    1499:1499:void <init>(com.leanplum.callbacks.ActionCallback,com.leanplum.ActionContext,com.leanplum.callbacks.VariablesChangedCallback,java.util.concurrent.atomic.AtomicBoolean) -> <init>
+    1502:1507:void run() -> run
+com.leanplum.Leanplum$13 -> com.leanplum.t:
+    java.lang.String val$messageId -> a
+    1558:1558:void <init>(java.lang.String) -> <init>
+    1563:1569:void variablesChanged() -> variablesChanged
+com.leanplum.Leanplum$14 -> com.leanplum.u:
+    com.leanplum.ActionContext val$actionContext -> a
+    1598:1598:void <init>(com.leanplum.ActionContext) -> <init>
+    1602:1606:void variablesChanged() -> variablesChanged
+com.leanplum.Leanplum$15 -> com.leanplum.v:
+    java.lang.String val$userId -> a
+    java.util.HashMap val$params -> b
+    1675:1675:void <init>(java.lang.String,java.util.HashMap) -> <init>
+    1679:1683:void run() -> run
+com.leanplum.Leanplum$16 -> com.leanplum.w:
+    java.lang.String val$registrationId -> a
+    1759:1759:void <init>(java.lang.String) -> <init>
+    1762:1772:void run() -> run
+com.leanplum.Leanplum$17 -> com.leanplum.x:
+    java.util.HashMap val$params -> a
+    1802:1802:void <init>(java.util.HashMap) -> <init>
+    1806:1810:void run() -> run
+com.leanplum.Leanplum$18 -> com.leanplum.y:
+    java.lang.String val$event -> a
+    java.util.Map val$params -> b
+    java.util.Map val$requestArgs -> c
+    1893:1893:void <init>(java.lang.String,java.util.Map,java.util.Map) -> <init>
+    1897:1901:void run() -> run
+com.leanplum.Leanplum$19 -> com.leanplum.z:
+    java.lang.String val$state -> a
+    java.util.Map val$validatedParams -> b
+    java.util.Map val$requestParams -> c
+    2124:2124:void <init>(java.lang.String,java.util.Map,java.util.Map) -> <init>
+    2128:2132:void run() -> run
+com.leanplum.Leanplum$20 -> com.leanplum.A:
+    2212:2212:void <init>() -> <init>
+    2216:2220:void run() -> run
+com.leanplum.Leanplum$21 -> com.leanplum.B:
+    2248:2248:void <init>() -> <init>
+    2252:2256:void run() -> run
+com.leanplum.Leanplum$22 -> com.leanplum.C:
+    com.leanplum.callbacks.VariablesChangedCallback val$callback -> a
+    2298:2298:void <init>(com.leanplum.callbacks.VariablesChangedCallback) -> <init>
+    2302:2329:void response(org.json.JSONObject) -> a
+com.leanplum.Leanplum$23 -> com.leanplum.D:
+    com.leanplum.callbacks.VariablesChangedCallback val$callback -> a
+    2331:2331:void <init>(com.leanplum.callbacks.VariablesChangedCallback) -> <init>
+    2334:2337:void error$698b7e31() -> a
+com.leanplum.Leanplum$3 -> com.leanplum.E:
+    java.lang.String val$userId -> a
+    java.util.Map val$validAttributes -> b
+    boolean val$actuallyInBackground -> c
+    573:573:void <init>(java.lang.String,java.util.Map,boolean) -> <init>
+    577:581:java.lang.Void doInBackground$10299ca() -> a
+    573:573:java.lang.Object doInBackground(java.lang.Object[]) -> doInBackground
+com.leanplum.Leanplum$5 -> com.leanplum.F:
+    773:773:void <init>() -> <init>
+    777:798:void onResponse(java.lang.String) -> onResponse
+    1017:1060:void com.leanplum.Registration.registerDevice(java.lang.String,com.leanplum.callbacks.StartCallback):17:60 -> onResponse
+    1017:1060:void onResponse(java.lang.String):778 -> onResponse
+com.leanplum.Leanplum$5$1 -> com.leanplum.G:
+    778:778:void <init>(com.leanplum.Leanplum$5) -> <init>
+    781:792:void onResponse(boolean) -> onResponse
+com.leanplum.Leanplum$6 -> com.leanplum.H:
+    android.content.Context val$currentContext -> a
+    805:805:void <init>(android.content.Context) -> <init>
+    809:824:void run() -> run
+com.leanplum.Leanplum$7 -> com.leanplum.I:
+    1015:1015:void <init>() -> <init>
+    1019:1023:void run() -> run
+com.leanplum.Leanplum$8 -> com.leanplum.J:
+    1050:1050:void <init>() -> <init>
+    1054:1058:void run() -> run
+com.leanplum.Leanplum$9 -> com.leanplum.K:
+    1082:1082:void <init>() -> <init>
+    1085:1089:void run() -> run
+com.leanplum.Leanplum$OsHandler -> com.leanplum.L:
+    com.leanplum.Leanplum$OsHandler instance -> a
+    android.os.Handler handler -> b
+    106:110:void <init>() -> <init>
+    113:113:java.lang.Boolean post(java.lang.Runnable) -> a
+    117:117:java.lang.Boolean postDelayed(java.lang.Runnable,long) -> a
+    121:124:com.leanplum.Leanplum$OsHandler getInstance() -> a
+com.leanplum.LeanplumActivityHelper -> com.leanplum.LeanplumActivityHelper:
+    boolean isActivityPaused -> a
+    boolean registeredCallbacks -> c
+    android.app.Activity currentActivity -> b
+    android.app.Activity activity -> d
+    com.leanplum.LeanplumResources res -> e
+    com.leanplum.LeanplumInflater inflater -> f
+    java.util.Queue pendingActions -> g
+    46:50:void <init>(android.app.Activity) -> <init>
+    56:56:android.app.Activity getCurrentActivity() -> getCurrentActivity
+    63:101:void enableLifecycleCallbacks(android.app.Application) -> enableLifecycleCallbacks
+    104:104:com.leanplum.LeanplumResources getLeanplumResources() -> getLeanplumResources
+    108:118:com.leanplum.LeanplumResources getLeanplumResources(android.content.res.Resources) -> getLeanplumResources
+    125:129:void setContentView(int) -> setContentView
+    140:146:void onPause() -> onPause
+    1132:1133:void onPause$63a22f9():132:133 -> onPause
+    1132:1133:void onPause():141 -> onPause
+    149:159:void onResume(android.app.Activity) -> d
+    1231:1238:void runPendingActions():231:238 -> d
+    1231:1238:void onResume(android.app.Activity):158 -> d
+    166:172:void onResume() -> onResume
+    182:193:void onStop(android.app.Activity) -> e
+    200:206:void onStop() -> onStop
+    214:224:void queueActionUponActive(com.leanplum.callbacks.VariablesChangedCallback) -> queueActionUponActive
+    25:25:void access$000(android.app.Activity) -> a
+    25:25:void access$100(android.app.Activity) -> b
+    25:25:void access$200(android.app.Activity) -> c
+    2132:2133:void onPause$63a22f9():132:133 -> c
+    2132:2133:void access$200(android.app.Activity):25 -> c
+    29:43:void <clinit>() -> <clinit>
+com.leanplum.LeanplumActivityHelper$1 -> com.leanplum.M:
+    67:67:void <init>() -> <init>
+    71:75:void onActivityStopped(android.app.Activity) -> onActivityStopped
+    80:84:void onActivityResumed(android.app.Activity) -> onActivityResumed
+    89:93:void onActivityPaused(android.app.Activity) -> onActivityPaused
+    95:95:void onActivityStarted(android.app.Activity) -> onActivityStarted
+    96:96:void onActivitySaveInstanceState(android.app.Activity,android.os.Bundle) -> onActivitySaveInstanceState
+    97:97:void onActivityDestroyed(android.app.Activity) -> onActivityDestroyed
+    98:98:void onActivityCreated(android.app.Activity,android.os.Bundle) -> onActivityCreated
+com.leanplum.LeanplumApplication -> com.leanplum.LeanplumApplication:
+    com.leanplum.LeanplumApplication instance -> a
+    15:15:void <init>() -> <init>
+    19:19:com.leanplum.LeanplumApplication getInstance() -> getInstance
+    23:23:android.content.Context getContext() -> getContext
+    28:32:void onCreate() -> onCreate
+    36:39:android.content.res.Resources getResources() -> getResources
+com.leanplum.LeanplumCompatibility -> com.leanplum.LeanplumCompatibility:
+    java.lang.String TYPE -> TYPE
+    java.lang.String EVENT_CATEGORY -> EVENT_CATEGORY
+    java.lang.String EVENT_ACTION -> EVENT_ACTION
+    java.lang.String EVENT_LABEL -> EVENT_LABEL
+    java.lang.String EVENT_VALUE -> EVENT_VALUE
+    java.lang.String EXCEPTION_DESCRIPTION -> EXCEPTION_DESCRIPTION
+    java.lang.String TRANSACTION_AFFILIATION -> TRANSACTION_AFFILIATION
+    java.lang.String ITEM_NAME -> ITEM_NAME
+    java.lang.String ITEM_CATEGORY -> ITEM_CATEGORY
+    java.lang.String SOCIAL_NETWORK -> SOCIAL_NETWORK
+    java.lang.String SOCIAL_ACTION -> SOCIAL_ACTION
+    java.lang.String SOCIAL_TARGET -> SOCIAL_TARGET
+    java.lang.String TIMING_NAME -> TIMING_NAME
+    java.lang.String TIMING_CATEGORY -> TIMING_CATEGORY
+    java.lang.String TIMING_LABEL -> TIMING_LABEL
+    java.lang.String TIMING_VALUE -> TIMING_VALUE
+    java.lang.String CAMPAIGN_SOURCE -> CAMPAIGN_SOURCE
+    java.lang.String CAMPAIGN_NAME -> CAMPAIGN_NAME
+    java.lang.String CAMPAIGN_MEDUIM -> CAMPAIGN_MEDUIM
+    java.lang.String CAMPAIGN_CONTENT -> CAMPAIGN_CONTENT
+    18:18:void <init>() -> <init>
+    44:45:void fTrack(java.lang.String) -> fTrack
+    51:56:void fTrack(java.lang.String,boolean) -> fTrack
+    62:63:void fTrack(java.lang.String,java.util.HashMap) -> fTrack
+    70:75:void fTrack(java.lang.String,java.util.HashMap,boolean) -> fTrack
+    81:85:void fTrack(java.lang.String,java.lang.String,java.lang.String) -> fTrack
+    92:171:void gaTrack(java.util.Map) -> gaTrack
+    175:182:java.lang.String getEventName(java.util.HashMap,java.util.List) -> a
+com.leanplum.LeanplumDeviceIdMode -> com.leanplum.LeanplumDeviceIdMode:
+    com.leanplum.LeanplumDeviceIdMode MD5_MAC_ADDRESS -> MD5_MAC_ADDRESS
+    com.leanplum.LeanplumDeviceIdMode ANDROID_ID -> ANDROID_ID
+    com.leanplum.LeanplumDeviceIdMode ADVERTISING_ID -> ADVERTISING_ID
+    com.leanplum.LeanplumDeviceIdMode[] $VALUES -> a
+    10:10:com.leanplum.LeanplumDeviceIdMode[] values() -> values
+    10:10:com.leanplum.LeanplumDeviceIdMode valueOf(java.lang.String) -> valueOf
+    10:10:void <init>(java.lang.String,int) -> <init>
+    10:31:void <clinit>() -> <clinit>
+com.leanplum.LeanplumException -> com.leanplum.LeanplumException:
+    13:14:void <init>(java.lang.String) -> <init>
+com.leanplum.LeanplumInflater -> com.leanplum.LeanplumInflater:
+    android.content.Context context -> a
+    com.leanplum.LeanplumResources res -> b
+    26:26:com.leanplum.LeanplumInflater from(android.content.Context) -> from
+    29:31:void <init>(android.content.Context) -> <init>
+    34:34:com.leanplum.LeanplumResources getLeanplumResources() -> getLeanplumResources
+    38:48:com.leanplum.LeanplumResources getLeanplumResources(android.content.res.Resources) -> getLeanplumResources
+    55:55:android.view.View inflate(int) -> inflate
+    62:62:android.view.View inflate(int,android.view.ViewGroup) -> inflate
+    69:113:android.view.View inflate(int,android.view.ViewGroup,boolean) -> inflate
+com.leanplum.LeanplumLocalPushListenerService -> com.leanplum.LeanplumLocalPushListenerService:
+    17:18:void <init>() -> <init>
+    23:34:void onHandleIntent(android.content.Intent) -> onHandleIntent
+com.leanplum.LeanplumPushInstanceIDService -> com.leanplum.LeanplumPushInstanceIDService:
+    16:16:void <init>() -> <init>
+    24:28:void onTokenRefresh() -> onTokenRefresh
+com.leanplum.LeanplumPushListenerService -> com.leanplum.LeanplumPushListenerService:
+    26:26:void <init>() -> <init>
+    36:43:void onMessageReceived(java.lang.String,android.os.Bundle) -> onMessageReceived
+com.leanplum.LeanplumPushNotificationCustomizer -> com.leanplum.LeanplumPushNotificationCustomizer:
+    void customize(android.support.v4.app.NotificationCompat$Builder,android.os.Bundle) -> customize
+com.leanplum.LeanplumPushReceiver -> com.leanplum.LeanplumPushReceiver:
+    25:25:void <init>() -> <init>
+    30:38:void onReceive(android.content.Context,android.content.Intent) -> onReceive
+com.leanplum.LeanplumPushRegistrationService -> com.leanplum.LeanplumPushRegistrationService:
+    java.lang.String existingRegistrationId -> a
+    30:31:void <init>() -> <init>
+    37:89:void onHandleIntent(android.content.Intent) -> onHandleIntent
+    20:20:java.lang.String access$000() -> a
+    20:20:java.lang.String access$002(java.lang.String) -> a
+com.leanplum.LeanplumPushRegistrationService$1 -> com.leanplum.N:
+    com.leanplum.LeanplumPushRegistrationService this$0 -> a
+    37:37:void <init>(com.leanplum.LeanplumPushRegistrationService) -> <init>
+    41:80:void run() -> run
+com.leanplum.LeanplumPushService -> com.leanplum.LeanplumPushService:
+    java.lang.String LEANPLUM_SENDER_ID -> LEANPLUM_SENDER_ID
+    java.lang.Class callbackClass -> a
+    java.lang.String gcmSenderIds -> b
+    java.lang.String gcmRegistrationId -> c
+    com.leanplum.LeanplumPushNotificationCustomizer customizer -> d
+    41:67:void <init>() -> <init>
+    77:78:void setDefaultCallbackClass(java.lang.Class) -> setDefaultCallbackClass
+    86:87:void setCustomizer(com.leanplum.LeanplumPushNotificationCustomizer) -> setCustomizer
+    96:97:void setGcmSenderId(java.lang.String) -> setGcmSenderId
+    105:113:void setGcmSenderIds(java.lang.String[]) -> setGcmSenderIds
+    120:120:boolean areActionsEmbedded(android.os.Bundle) -> a
+    125:186:void requireMessageContent(java.lang.String,com.leanplum.callbacks.VariablesChangedCallback) -> a
+    189:202:java.lang.String getMessageId(android.os.Bundle) -> b
+    206:228:void handleNotification(android.content.Context,android.os.Bundle) -> a
+    234:278:void showNotification(android.content.Context,android.os.Bundle) -> c
+    281:349:void openNotification(android.content.Context,android.os.Bundle) -> b
+    1116:1116:java.lang.Class getCallbackClass():116:116 -> b
+    1116:1116:void openNotification(android.content.Context,android.os.Bundle):284 -> b
+    1352:1357:android.content.Intent getActionIntent(android.content.Context):352:357 -> b
+    1352:1357:void openNotification(android.content.Context,android.os.Bundle):295 -> b
+    2116:2116:java.lang.Class getCallbackClass():116:116 -> b
+    2116:2116:android.content.Intent getActionIntent(android.content.Context):352 -> b
+    2116:2116:void openNotification(android.content.Context,android.os.Bundle):295 -> b
+    362:362:java.lang.String getGcmSenderIds() -> a
+    404:409:int getAppVersion(android.content.Context) -> a
+    428:436:void unregister() -> unregister
+    455:456:void setGcmRegistrationId(java.lang.String) -> setGcmRegistrationId
+    459:466:void onRegistrationIdReceived(android.content.Context,java.lang.String) -> a
+    2366:2366:java.lang.String getStoredRegistrationId(android.content.Context):366:366 -> a
+    2366:2366:void onRegistrationIdReceived(android.content.Context,java.lang.String):460 -> a
+    2419:2419:android.content.SharedPreferences getGcmPreferences(android.content.Context):419:419 -> a
+    2419:2419:java.lang.String getStoredRegistrationId(android.content.Context):366 -> a
+    2419:2419:void onRegistrationIdReceived(android.content.Context,java.lang.String):460 -> a
+    2475:2476:void sendRegistrationIdToBackend(java.lang.String):475:476 -> a
+    2475:2476:void onRegistrationIdReceived(android.content.Context,java.lang.String):463 -> a
+    2485:2499:void storeGcmPreferences(android.content.Context):485:499 -> a
+    2485:2499:void onRegistrationIdReceived(android.content.Context,java.lang.String):465 -> a
+    3419:3419:android.content.SharedPreferences getGcmPreferences(android.content.Context):419:419 -> a
+    3419:3419:void storeGcmPreferences(android.content.Context):485 -> a
+    3419:3419:void onRegistrationIdReceived(android.content.Context,java.lang.String):465 -> a
+    506:514:void onStart() -> b
+    3517:3549:void initPushService():517:549 -> b
+    3517:3549:void onStart():507 -> b
+    4377:4396:boolean needsGcmRegistration(android.content.Context):377:396 -> b
+    4377:4396:void initPushService():546 -> b
+    4377:4396:void onStart():507 -> b
+    4419:4419:android.content.SharedPreferences getGcmPreferences(android.content.Context):419:419 -> b
+    4419:4419:boolean needsGcmRegistration(android.content.Context):380 -> b
+    4419:4419:void initPushService():546 -> b
+    4419:4419:void onStart():507 -> b
+    4445:4448:void registerInBackground():445:448 -> b
+    4445:4448:void initPushService():547 -> b
+    4445:4448:void onStart():507 -> b
+    553:571:boolean checkPermission(java.lang.String,boolean,boolean) -> a
+    588:625:boolean checkComponent(com.leanplum.LeanplumPushService$ApplicationComponent,java.lang.String,boolean,java.lang.String,java.util.List,java.lang.String) -> a
+    630:651:java.lang.String getComponentError(com.leanplum.LeanplumPushService$ApplicationComponent,java.lang.String,boolean,java.lang.String,java.util.List,java.lang.String) -> b
+com.leanplum.LeanplumPushService$1 -> com.leanplum.O:
+    java.lang.String val$messageId -> b
+    com.leanplum.callbacks.VariablesChangedCallback val$onComplete -> a
+    125:125:void <init>(java.lang.String,com.leanplum.callbacks.VariablesChangedCallback) -> <init>
+    129:184:void variablesChanged() -> variablesChanged
+com.leanplum.LeanplumPushService$1$1 -> com.leanplum.P:
+    com.leanplum.LeanplumPushService$1 this$0 -> a
+    139:139:void <init>(com.leanplum.LeanplumPushService$1) -> <init>
+    143:171:void response(org.json.JSONObject) -> a
+com.leanplum.LeanplumPushService$1$2 -> com.leanplum.Q:
+    com.leanplum.LeanplumPushService$1 this$0 -> a
+    173:173:void <init>(com.leanplum.LeanplumPushService$1) -> <init>
+    176:177:void error$698b7e31() -> a
+com.leanplum.LeanplumPushService$2 -> com.leanplum.R:
+    android.os.Bundle val$notification -> a
+    304:304:void <init>(android.os.Bundle) -> <init>
+    308:347:void variablesChanged() -> variablesChanged
+com.leanplum.LeanplumPushService$2$1 -> com.leanplum.S:
+    java.lang.String val$messageId -> a
+    323:323:void <init>(com.leanplum.LeanplumPushService$2,java.lang.String) -> <init>
+    327:340:void variablesChanged() -> variablesChanged
+com.leanplum.LeanplumPushService$2$1$1 -> com.leanplum.T:
+    com.leanplum.LeanplumPushService$2$1 this$1 -> a
+    327:327:void <init>(com.leanplum.LeanplumPushService$2$1) -> <init>
+    331:335:void variablesChanged() -> variablesChanged
+com.leanplum.LeanplumPushService$ApplicationComponent -> com.leanplum.U:
+    com.leanplum.LeanplumPushService$ApplicationComponent SERVICE -> a
+    com.leanplum.LeanplumPushService$ApplicationComponent RECEIVER -> b
+    com.leanplum.LeanplumPushService$ApplicationComponent[] $VALUES -> c
+    67:67:com.leanplum.LeanplumPushService$ApplicationComponent[] values() -> values
+    67:67:com.leanplum.LeanplumPushService$ApplicationComponent valueOf(java.lang.String) -> valueOf
+    67:67:void <init>(java.lang.String,int) -> <init>
+    67:67:void <clinit>() -> <clinit>
+com.leanplum.LeanplumRequest -> com.leanplum.V:
+    long DEVELOPMENT_MAX_DELAY_MS -> a
+    java.lang.String appId -> b
+    java.lang.String accessKey -> c
+    java.lang.String deviceId -> d
+    java.lang.String userId -> e
+    java.util.Map fileTransferStatus -> f
+    int pendingDownloads -> g
+    com.leanplum.LeanplumRequest$NoPendingDownloadsCallback noPendingDownloadsBlock -> h
+    java.lang.String token -> i
+    java.lang.Object lock -> j
+    java.util.Map fileUploadSize -> k
+    java.util.Map fileUploadProgress -> l
+    java.lang.String fileUploadProgressString -> m
+    long lastSendTimeMs -> n
+    java.lang.Object uploadFileLock -> o
+    java.lang.String httpMethod -> p
+    java.lang.String apiMethod -> q
+    java.util.Map params -> r
+    com.leanplum.LeanplumRequest$ResponseCallback response -> s
+    com.leanplum.LeanplumRequest$ErrorCallback error -> t
+    boolean sent -> u
+    com.leanplum.LeanplumRequest$ApiResponseCallback apiResponse -> v
+    61:63:void setAppId(java.lang.String,java.lang.String) -> a
+    66:67:void setDeviceId(java.lang.String) -> a
+    70:71:void setUserId(java.lang.String) -> b
+    74:75:void setToken(java.lang.String) -> c
+    78:78:java.lang.String token() -> a
+    82:90:void loadToken() -> b
+    1074:1075:void setToken(java.lang.String):74:75 -> b
+    1074:1075:void loadToken():89 -> b
+    93:103:void saveToken() -> c
+    1078:1078:java.lang.String token():78:78 -> c
+    1078:1078:void saveToken():97 -> c
+    106:106:java.lang.String appId() -> d
+    110:110:java.lang.String deviceId() -> e
+    114:114:java.lang.String userId() -> f
+    126:133:void <init>(java.lang.String,java.lang.String,java.util.Map) -> <init>
+    136:136:com.leanplum.LeanplumRequest get(java.lang.String,java.util.Map) -> a
+    140:140:com.leanplum.LeanplumRequest post(java.lang.String,java.util.Map) -> b
+    144:145:void onResponse(com.leanplum.LeanplumRequest$ResponseCallback) -> a
+    148:149:void onError(com.leanplum.LeanplumRequest$ErrorCallback) -> a
+    152:153:void onApiResponse(com.leanplum.LeanplumRequest$ApiResponseCallback) -> a
+    156:167:java.util.Map createArgsDictionary() -> p
+    171:187:void saveRequestForLater(java.util.Map) -> a
+    190:210:void send() -> g
+    217:228:void sendIfDelayed() -> h
+    234:242:void sendIfDelayedHelper() -> i
+    245:252:void sendIfConnected() -> j
+    1343:1425:void sendNow():343:425 -> j
+    1343:1425:void sendIfConnected():246 -> j
+    1439:1439:java.util.List popUnsentRequests():439:439 -> j
+    1439:1439:void sendNow():357 -> j
+    1439:1439:void sendIfConnected():246 -> j
+    1491:1493:java.lang.String jsonEncodeUnsentRequests(java.util.List):491:493 -> j
+    1491:1493:void sendNow():363 -> j
+    1491:1493:void sendIfConnected():246 -> j
+    2255:2262:void triggerErrorCallback(java.lang.Exception):255:262 -> j
+    2255:2262:void sendIfConnected():250 -> j
+    2443:2443:java.util.List getUnsentRequests():443:443 -> j
+    2443:2443:void triggerErrorCallback(java.lang.Exception):259 -> j
+    2443:2443:void sendIfConnected():250 -> j
+    265:274:boolean attachApiKeys(java.util.Map) -> b
+    428:436:void sendEventually() -> k
+    447:487:java.util.List getUnsentRequests(boolean) -> a
+    497:508:void pushUnsentRequests(java.util.List) -> a
+    511:516:java.lang.String getSizeAsString(int) -> a
+    521:541:void printUploadProgress() -> q
+    544:652:void sendFilesNow(java.util.List,java.util.List) -> a
+    655:682:void downloadFile(java.lang.String) -> d
+    686:740:void downloadHelper(java.lang.String,java.lang.String,java.lang.String,java.util.Map) -> a
+    743:743:int numPendingDownloads() -> l
+    747:748:void onNoPendingDownloads(com.leanplum.LeanplumRequest$NoPendingDownloadsCallback) -> a
+    752:759:int numResponses(org.json.JSONObject) -> a
+    765:768:org.json.JSONObject getResponseAt(org.json.JSONObject,int) -> a
+    773:777:org.json.JSONObject getLastResponse(org.json.JSONObject) -> b
+    782:789:boolean isResponseSuccess(org.json.JSONObject) -> c
+    794:805:java.lang.String getResponseError(org.json.JSONObject) -> d
+    37:37:java.lang.String access$000(com.leanplum.LeanplumRequest) -> a
+    37:37:void access$100(com.leanplum.LeanplumRequest,org.json.JSONObject,java.util.List,java.lang.Exception) -> a
+    3295:3340:void parseResponseJson(org.json.JSONObject,java.util.List,java.lang.Exception):295:340 -> a
+    3295:3340:void access$100(com.leanplum.LeanplumRequest,org.json.JSONObject,java.util.List,java.lang.Exception):37 -> a
+    37:37:java.lang.Object access$200() -> m
+    37:37:com.leanplum.LeanplumRequest$ResponseCallback access$300(com.leanplum.LeanplumRequest) -> b
+    37:37:com.leanplum.LeanplumRequest$ErrorCallback access$400(com.leanplum.LeanplumRequest) -> c
+    37:37:java.util.Map access$500() -> n
+    37:37:void access$600() -> o
+    37:37:void access$700(com.leanplum.LeanplumRequest,java.lang.String,java.lang.String,java.lang.String,java.util.Map) -> a
+    39:58:void <clinit>() -> <clinit>
+com.leanplum.LeanplumRequest$1 -> com.leanplum.W:
+    com.leanplum.LeanplumRequest this$0 -> a
+    199:199:void <init>(com.leanplum.LeanplumRequest) -> <init>
+    203:207:void run() -> run
+com.leanplum.LeanplumRequest$2 -> com.leanplum.X:
+    com.leanplum.LeanplumRequest this$0 -> a
+    218:218:void <init>(com.leanplum.LeanplumRequest) -> <init>
+    222:226:void run() -> run
+com.leanplum.LeanplumRequest$3 -> com.leanplum.Y:
+    java.util.Map val$multiRequestArgs -> a
+    java.util.List val$requestsToSend -> b
+    com.leanplum.LeanplumRequest this$0 -> c
+    371:371:void <init>(com.leanplum.LeanplumRequest,java.util.Map,java.util.List) -> <init>
+    374:422:java.lang.Void doInBackground$10299ca() -> a
+    371:371:java.lang.Object doInBackground(java.lang.Object[]) -> doInBackground
+com.leanplum.LeanplumRequest$4 -> com.leanplum.Z:
+    java.util.List val$filesToUpload -> a
+    java.util.List val$streams -> b
+    java.util.Map val$dict -> c
+    com.leanplum.LeanplumRequest this$0 -> d
+    582:582:void <init>(com.leanplum.LeanplumRequest,java.util.List,java.util.List,java.util.Map) -> <init>
+    585:647:java.lang.Void doInBackground$10299ca() -> a
+    582:582:java.lang.Object doInBackground(java.lang.Object[]) -> doInBackground
+com.leanplum.LeanplumRequest$5 -> com.leanplum.aa:
+    java.lang.String val$path -> a
+    java.util.Map val$dict -> b
+    com.leanplum.LeanplumRequest this$0 -> c
+    670:670:void <init>(com.leanplum.LeanplumRequest,java.lang.String,java.util.Map) -> <init>
+    674:678:java.lang.Void doInBackground$10299ca() -> a
+    670:670:java.lang.Object doInBackground(java.lang.Object[]) -> doInBackground
+com.leanplum.LeanplumRequest$ApiResponseCallback -> com.leanplum.ab:
+    1663:1664:void com.leanplum.Leanplum$4.response(java.util.List,org.json.JSONObject):663:664 -> a
+    2660:2660:void com.leanplum.Leanplum$4.<init>():660:660 -> <init>
+com.leanplum.LeanplumRequest$ErrorCallback -> com.leanplum.ac:
+    void error$698b7e31() -> a
+com.leanplum.LeanplumRequest$NoPendingDownloadsCallback -> com.leanplum.ad:
+    1568:1569:void com.leanplum.Leanplum$2.noPendingDownloads():568:569 -> a
+    2565:2565:void com.leanplum.Leanplum$2.<init>():565:565 -> <init>
+com.leanplum.LeanplumRequest$ResponseCallback -> com.leanplum.ae:
+    void response(org.json.JSONObject) -> a
+com.leanplum.LeanplumResources -> com.leanplum.LeanplumResources:
+    23:24:void <init>(android.content.res.Resources) -> <init>
+    29:114:com.leanplum.Var getOverrideResource(int) -> a
+    120:136:android.graphics.drawable.Drawable getDrawable(int) -> getDrawable
+com.leanplum.LeanplumSocket -> com.leanplum.af:
+    com.leanplum.SocketIOClient sio -> a
+    boolean authSent -> b
+    java.util.Timer reconnectTimer -> c
+    boolean connected -> d
+    boolean connecting -> e
+    33:166:void <init>() -> <init>
+    169:171:void connect() -> a
+    1226:1256:void com.leanplum.SocketIOClient.connect():226:256 -> a
+    1226:1256:void connect():170 -> a
+    181:185:void sendEvent(java.lang.String,java.util.Map) -> a
+    29:29:boolean access$002(com.leanplum.LeanplumSocket,boolean) -> a
+    29:29:boolean access$102(com.leanplum.LeanplumSocket,boolean) -> b
+    29:29:boolean access$202(com.leanplum.LeanplumSocket,boolean) -> c
+    29:29:boolean access$200(com.leanplum.LeanplumSocket) -> a
+    29:29:com.leanplum.SocketIOClient access$300(com.leanplum.LeanplumSocket) -> b
+    29:29:void access$400(com.leanplum.LeanplumSocket) -> c
+    2174:2177:void reconnect():174:177 -> c
+    2174:2177:void access$400(com.leanplum.LeanplumSocket):29 -> c
+com.leanplum.LeanplumSocket$1 -> com.leanplum.ag:
+    com.leanplum.LeanplumSocket this$0 -> a
+    39:39:void <init>(com.leanplum.LeanplumSocket) -> <init>
+    43:44:void onError(java.lang.Exception) -> a
+    48:52:void onDisconnect$4f708078() -> a
+    56:74:void onConnect() -> b
+    80:149:void on(java.lang.String,org.json.JSONArray) -> a
+com.leanplum.LeanplumSocket$1$1 -> com.leanplum.ah:
+    java.lang.String val$email -> a
+    127:127:void <init>(com.leanplum.LeanplumSocket$1,java.lang.String) -> <init>
+    130:143:void run() -> run
+com.leanplum.LeanplumSocket$1$1$1 -> com.leanplum.ai:
+    com.leanplum.LeanplumSocket$1$1 this$2 -> a
+    130:130:void <init>(com.leanplum.LeanplumSocket$1$1) -> <init>
+    133:141:void variablesChanged() -> variablesChanged
+com.leanplum.LeanplumSocket$1$1$1$1 -> com.leanplum.aj:
+    137:137:void <init>(com.leanplum.LeanplumSocket$1$1$1) -> <init>
+    138:138:void onClick(android.content.DialogInterface,int) -> onClick
+com.leanplum.LeanplumSocket$2 -> com.leanplum.ak:
+    com.leanplum.LeanplumSocket this$0 -> a
+    156:156:void <init>(com.leanplum.LeanplumSocket) -> <init>
+    160:164:void run() -> run
+com.leanplum.LocationManager -> com.leanplum.al:
+    void updateGeofencing() -> updateGeofencing
+    void setRegionsData(java.util.Map,java.util.Set,java.util.Set) -> setRegionsData
+com.leanplum.LocationManagerImpl -> com.leanplum.LocationManagerImpl:
+    java.util.Map lastKnownState -> lastKnownState
+    java.util.Map stateBeforeBackground -> stateBeforeBackground
+    java.util.List allGeofences -> allGeofences
+    java.util.List backgroundGeofences -> backgroundGeofences
+    java.util.List trackedGeofenceIds -> trackedGeofenceIds
+    boolean isInBackground -> isInBackground
+    java.lang.String PERMISSION -> PERMISSION
+    java.lang.String METADATA -> METADATA
+    com.google.android.gms.common.api.GoogleApiClient googleApiClient -> googleApiClient
+    com.leanplum.LocationManagerImpl instance -> instance
+    64:67:com.leanplum.LocationManager instance() -> instance
+    70:74:void <init>() -> <init>
+    79:105:void setRegionsData(java.util.Map,java.util.Set,java.util.Set) -> setRegionsData
+    108:111:void updateGeofencing() -> updateGeofencing
+    114:126:void loadLastKnownRegionState() -> loadLastKnownRegionState
+    129:142:void saveLastKnownRegionState() -> saveLastKnownRegionState
+    145:159:com.google.android.gms.location.Geofence geofenceFromMap(java.util.Map,java.lang.String) -> geofenceFromMap
+    163:163:java.lang.String geofenceID(java.lang.String,java.lang.Integer) -> geofenceID
+    167:185:void startLocationClient() -> startLocationClient
+    188:189:boolean isPermissionGranted() -> isPermissionGranted
+    193:207:boolean isMetaDataSet() -> isMetaDataSet
+    212:256:void updateTrackedGeofences() -> updateTrackedGeofences
+    259:262:java.util.List getToBeTrackedGeofences() -> getToBeTrackedGeofences
+    267:292:void updateStatusForGeofences(java.util.List,int) -> updateStatusForGeofences
+    295:302:void maybePerformActions(com.google.android.gms.location.Geofence,java.lang.String) -> maybePerformActions
+    305:309:int getStatusForTransitionType(int) -> getStatusForTransitionType
+    314:317:java.lang.String getRegionName(java.lang.String) -> getRegionName
+    321:323:android.app.PendingIntent getTransitionPendingIntent() -> getTransitionPendingIntent
+    329:333:void onConnected(android.os.Bundle) -> onConnected
+    340:340:void onConnectionSuspended(int) -> onConnectionSuspended
+    344:347:void onConnectionFailed(com.google.android.gms.common.ConnectionResult) -> onConnectionFailed
+com.leanplum.Newsfeed -> com.leanplum.Newsfeed:
+    com.leanplum.Newsfeed instance -> a
+    int unreadCount -> b
+    java.util.Map messages -> c
+    boolean didLoad -> d
+    java.util.List newsfeedChangedHandlers -> e
+    java.lang.Object updatingLock -> f
+    33:45:void <init>() -> <init>
+    51:51:com.leanplum.Newsfeed getInstance() -> a
+    55:58:void updateUnreadCount(int) -> a
+    62:76:void updateNewsfeed(java.util.Map,int,boolean) -> a
+    79:95:void removeMessage(java.lang.String) -> a
+    98:103:void triggerNewsfeedChanged() -> e
+    107:137:void load() -> b
+    140:165:void save() -> f
+    168:221:void downloadMessages() -> c
+    227:227:int count() -> count
+    234:234:int unreadCount() -> unreadCount
+    243:256:java.util.List messagesIds() -> messagesIds
+    264:272:java.util.List allMessages() -> allMessages
+    280:287:java.util.List unreadMessages() -> unreadMessages
+    294:294:com.leanplum.NewsfeedMessage messageForId(java.lang.String) -> messageForId
+    301:307:void addNewsfeedChangedHandler(com.leanplum.callbacks.NewsfeedChangedCallback) -> addNewsfeedChangedHandler
+    313:316:void removeNewsfeedChangedHandler(com.leanplum.callbacks.NewsfeedChangedCallback) -> removeNewsfeedChangedHandler
+    319:323:void reset() -> d
+    28:28:void <clinit>() -> <clinit>
+com.leanplum.Newsfeed$1 -> com.leanplum.am:
+    com.leanplum.Newsfeed this$0 -> a
+    173:173:void <init>(com.leanplum.Newsfeed) -> <init>
+    177:218:void response(org.json.JSONObject) -> a
+com.leanplum.Newsfeed$2 -> com.leanplum.an:
+    com.leanplum.Newsfeed this$0 -> a
+    245:245:void <init>(com.leanplum.Newsfeed) -> <init>
+    245:245:int compare(java.lang.Object,java.lang.Object) -> compare
+    1248:1250:int compare(java.lang.String,java.lang.String):248:250 -> compare
+    1248:1250:int compare(java.lang.Object,java.lang.Object):245 -> compare
+com.leanplum.NewsfeedMessage -> com.leanplum.NewsfeedMessage:
+    java.lang.String messageId -> a
+    java.lang.Long deliveryTimestamp -> b
+    java.lang.Long expirationTimestamp -> c
+    boolean isRead -> d
+    com.leanplum.ActionContext context -> e
+    24:30:void <init>(java.lang.String,java.lang.Long,java.lang.Long,boolean,com.leanplum.ActionContext) -> <init>
+    34:44:com.leanplum.NewsfeedMessage constructNewsfeedMessage(java.lang.String,java.lang.Long,java.lang.Long,boolean,java.util.Map) -> a
+    1083:1083:boolean isValidMessageId(java.lang.String):83:83 -> a
+    1083:1083:com.leanplum.NewsfeedMessage constructNewsfeedMessage(java.lang.String,java.lang.Long,java.lang.Long,boolean,java.util.Map):34 -> a
+    48:53:java.util.Map toJsonMap() -> a
+    2066:2066:java.util.Map actionArgs():66:66 -> a
+    2066:2066:java.util.Map toJsonMap():51 -> a
+    58:62:com.leanplum.NewsfeedMessage createFromJsonMap(java.lang.String,java.util.Map) -> a
+    74:79:boolean isActive() -> b
+    90:90:java.lang.String messageId() -> messageId
+    97:97:java.lang.String title() -> title
+    104:104:java.lang.String subtitle() -> subtitle
+    111:111:java.util.Date deliveryTimestamp() -> deliveryTimestamp
+    118:121:java.util.Date expirationTimestamp() -> expirationTimestamp
+    128:128:boolean isRead() -> isRead
+    136:156:void read() -> read
+    2070:2071:void setIsRead(boolean):70:71 -> read
+    2070:2071:void read():141 -> read
+    163:167:void remove() -> remove
+com.leanplum.ReceiveTransitionsIntentService -> com.leanplum.ReceiveTransitionsIntentService:
+    22:23:void <init>() -> <init>
+    28:47:void onHandleIntent(android.content.Intent) -> onHandleIntent
+com.leanplum.Registration$1 -> com.leanplum.ao:
+    com.leanplum.callbacks.StartCallback val$callback -> a
+    20:20:void <init>(com.leanplum.callbacks.StartCallback) -> <init>
+    23:44:void response(org.json.JSONObject) -> a
+com.leanplum.Registration$1$1 -> com.leanplum.ap:
+    org.json.JSONObject val$response -> a
+    com.leanplum.Registration$1 this$0 -> b
+    23:23:void <init>(com.leanplum.Registration$1,org.json.JSONObject) -> <init>
+    27:42:void run() -> run
+com.leanplum.Registration$2 -> com.leanplum.aq:
+    com.leanplum.callbacks.StartCallback val$callback -> a
+    46:46:void <init>(com.leanplum.callbacks.StartCallback) -> <init>
+    49:57:void error$698b7e31() -> a
+com.leanplum.Registration$2$1 -> com.leanplum.ar:
+    com.leanplum.Registration$2 this$0 -> a
+    49:49:void <init>(com.leanplum.Registration$2) -> <init>
+    52:55:void run() -> run
+com.leanplum.RequestFactory -> com.leanplum.as:
+    com.leanplum.RequestFactory defaultFactory -> a
+    7:7:void <init>() -> <init>
+    11:14:com.leanplum.RequestFactory getInstance() -> a
+    19:19:com.leanplum.LeanplumRequest createRequest(java.lang.String,java.lang.String,java.util.Map) -> a
+com.leanplum.ResourceQualifiers -> com.leanplum.at:
+    java.util.Map qualifiers -> a
+    17:475:void <init>() -> <init>
+    478:493:com.leanplum.ResourceQualifiers fromFolder(java.lang.String) -> a
+com.leanplum.ResourceQualifiers$Qualifier -> com.leanplum.au:
+    com.leanplum.ResourceQualifiers$Qualifier MCC -> a
+    com.leanplum.ResourceQualifiers$Qualifier MNC -> b
+    com.leanplum.ResourceQualifiers$Qualifier LANGUAGE -> c
+    com.leanplum.ResourceQualifiers$Qualifier REGION -> d
+    com.leanplum.ResourceQualifiers$Qualifier LAYOUT_DIRECTION -> e
+    com.leanplum.ResourceQualifiers$Qualifier SMALLEST_WIDTH -> f
+    com.leanplum.ResourceQualifiers$Qualifier AVAILABLE_WIDTH -> g
+    com.leanplum.ResourceQualifiers$Qualifier AVAILABLE_HEIGHT -> h
+    com.leanplum.ResourceQualifiers$Qualifier SCREEN_SIZE -> i
+    com.leanplum.ResourceQualifiers$Qualifier SCREEN_ASPECT -> j
+    com.leanplum.ResourceQualifiers$Qualifier SCREEN_ORIENTATION -> k
+    com.leanplum.ResourceQualifiers$Qualifier UI_MODE -> l
+    com.leanplum.ResourceQualifiers$Qualifier NIGHT_MODE -> m
+    com.leanplum.ResourceQualifiers$Qualifier SCREEN_PIXEL_DENSITY -> n
+    com.leanplum.ResourceQualifiers$Qualifier TOUCHSCREEN_TYPE -> o
+    com.leanplum.ResourceQualifiers$Qualifier KEYBOARD_AVAILABILITY -> p
+    com.leanplum.ResourceQualifiers$Qualifier PRIMARY_TEXT_INPUTMETHOD -> q
+    com.leanplum.ResourceQualifiers$Qualifier NAVIGATION_KEY_AVAILABILITY -> r
+    com.leanplum.ResourceQualifiers$Qualifier PRIMARY_NON_TOUCH_NAVIGATION_METHOD -> s
+    com.leanplum.ResourceQualifiers$Qualifier PLATFORM_VERSION -> t
+    com.leanplum.ResourceQualifiers$QualifierFilter filter -> u
+    com.leanplum.ResourceQualifiers$Qualifier[] $VALUES -> v
+    26:26:com.leanplum.ResourceQualifiers$Qualifier[] values() -> values
+    26:26:com.leanplum.ResourceQualifiers$Qualifier valueOf(java.lang.String) -> valueOf
+    466:468:void <init>(java.lang.String,int,com.leanplum.ResourceQualifiers$QualifierFilter) -> <init>
+    471:471:com.leanplum.ResourceQualifiers$QualifierFilter getFilter() -> a
+    26:450:void <clinit>() -> <clinit>
+com.leanplum.ResourceQualifiers$Qualifier$1 -> com.leanplum.av:
+    27:27:void <init>() -> <init>
+    30:33:java.lang.Object getMatch(java.lang.String) -> a
+    37:37:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$10 -> com.leanplum.aw:
+    241:241:void <init>() -> <init>
+    244:249:java.lang.Object getMatch(java.lang.String) -> a
+    253:253:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$11 -> com.leanplum.ax:
+    256:256:void <init>() -> <init>
+    259:264:java.lang.Object getMatch(java.lang.String) -> a
+    268:268:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$12 -> com.leanplum.ay:
+    271:271:void <init>() -> <init>
+    276:285:java.lang.Object getMatch(java.lang.String) -> a
+    289:289:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$13 -> com.leanplum.az:
+    292:292:void <init>() -> <init>
+    295:300:java.lang.Object getMatch(java.lang.String) -> a
+    304:304:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$14 -> com.leanplum.aA:
+    307:307:void <init>() -> <init>
+    313:328:java.lang.Object getMatch(java.lang.String) -> a
+    332:332:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+    336:361:java.util.Map bestMatch$45308dd8(java.util.Map,android.util.DisplayMetrics) -> a
+com.leanplum.ResourceQualifiers$Qualifier$15 -> com.leanplum.aB:
+    364:364:void <init>() -> <init>
+    367:372:java.lang.Object getMatch(java.lang.String) -> a
+    376:376:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$16 -> com.leanplum.aC:
+    379:379:void <init>() -> <init>
+    382:389:java.lang.Object getMatch(java.lang.String) -> a
+    393:396:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$17 -> com.leanplum.aD:
+    399:399:void <init>() -> <init>
+    402:409:java.lang.Object getMatch(java.lang.String) -> a
+    413:413:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$18 -> com.leanplum.aE:
+    416:416:void <init>() -> <init>
+    419:424:java.lang.Object getMatch(java.lang.String) -> a
+    428:428:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$19 -> com.leanplum.aF:
+    431:431:void <init>() -> <init>
+    434:443:java.lang.Object getMatch(java.lang.String) -> a
+    447:447:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$2 -> com.leanplum.aG:
+    40:40:void <init>() -> <init>
+    43:46:java.lang.Object getMatch(java.lang.String) -> a
+    50:50:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$20 -> com.leanplum.aH:
+    450:450:void <init>() -> <init>
+    453:456:java.lang.Object getMatch(java.lang.String) -> a
+    460:460:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$3 -> com.leanplum.aI:
+    53:53:void <init>() -> <init>
+    56:59:java.lang.Object getMatch(java.lang.String) -> a
+    63:63:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$4 -> com.leanplum.aJ:
+    66:66:void <init>() -> <init>
+    69:72:java.lang.Object getMatch(java.lang.String) -> a
+    76:76:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$5 -> com.leanplum.aK:
+    79:79:void <init>() -> <init>
+    86:91:java.lang.Object getMatch(java.lang.String) -> a
+    95:95:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+com.leanplum.ResourceQualifiers$Qualifier$6 -> com.leanplum.aL:
+    98:98:void <init>() -> <init>
+    101:104:java.lang.Object getMatch(java.lang.String) -> a
+    109:115:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+    119:131:java.util.Map bestMatch$45308dd8(java.util.Map,android.util.DisplayMetrics) -> a
+com.leanplum.ResourceQualifiers$Qualifier$7 -> com.leanplum.aM:
+    134:134:void <init>() -> <init>
+    137:140:java.lang.Object getMatch(java.lang.String) -> a
+    145:151:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+    155:167:java.util.Map bestMatch$45308dd8(java.util.Map,android.util.DisplayMetrics) -> a
+com.leanplum.ResourceQualifiers$Qualifier$8 -> com.leanplum.aN:
+    170:170:void <init>() -> <init>
+    173:176:java.lang.Object getMatch(java.lang.String) -> a
+    181:187:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+    191:203:java.util.Map bestMatch$45308dd8(java.util.Map,android.util.DisplayMetrics) -> a
+com.leanplum.ResourceQualifiers$Qualifier$9 -> com.leanplum.aO:
+    206:206:void <init>() -> <init>
+    209:218:java.lang.Object getMatch(java.lang.String) -> a
+    222:222:boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+    226:238:java.util.Map bestMatch$45308dd8(java.util.Map,android.util.DisplayMetrics) -> a
+com.leanplum.ResourceQualifiers$QualifierFilter -> com.leanplum.aP:
+    18:18:void <init>() -> <init>
+    java.lang.Object getMatch(java.lang.String) -> a
+    boolean isMatch$25e29dd8(java.lang.Object,android.content.res.Configuration) -> a
+    22:22:java.util.Map bestMatch$45308dd8(java.util.Map,android.util.DisplayMetrics) -> a
+com.leanplum.SocketIOClient -> com.leanplum.aQ:
+    java.lang.String mURL -> a
+    com.leanplum.SocketIOClient$Handler mHandler -> b
+    java.lang.String mSession -> c
+    int mHeartbeat -> d
+    com.leanplum.WebSocketClient mClient -> e
+    android.os.Handler mSendHandler -> f
+    android.os.Looper mSendLooper -> g
+    62:66:void <init>(java.net.URI,com.leanplum.SocketIOClient$Handler) -> <init>
+    70:76:java.lang.String downloadUriAsString(org.apache.http.client.methods.HttpUriRequest) -> b
+    1093:1093:java.lang.String readToEnd(java.io.InputStream):93:93 -> b
+    1093:1093:java.lang.String downloadUriAsString(org.apache.http.client.methods.HttpUriRequest):74 -> b
+    81:89:byte[] readToEndAsArray(java.io.InputStream) -> a
+    100:110:void emit(java.lang.String,org.json.JSONArray) -> a
+    45:45:void access$000(com.leanplum.SocketIOClient) -> a
+    1213:1223:void cleanup():213:223 -> a
+    1213:1223:void access$000(com.leanplum.SocketIOClient):45 -> a
+    45:45:java.lang.String access$100(org.apache.http.client.methods.HttpUriRequest) -> a
+    45:45:void access$200(com.leanplum.SocketIOClient) -> b
+    2113:2206:void connectSession():113:206 -> b
+    2113:2206:void access$200(com.leanplum.SocketIOClient):45 -> b
+com.leanplum.SocketIOClient$1 -> com.leanplum.aR:
+    org.json.JSONObject val$event -> a
+    com.leanplum.SocketIOClient this$0 -> b
+    104:104:void <init>(com.leanplum.SocketIOClient,org.json.JSONObject) -> <init>
+    107:108:void run() -> run
+com.leanplum.SocketIOClient$2 -> com.leanplum.aS:
+    com.leanplum.SocketIOClient this$0 -> a
+    114:114:void <init>(com.leanplum.SocketIOClient) -> <init>
+    117:119:void onMessage$25e06fc() -> a
+    125:178:void onMessage(java.lang.String) -> a
+    182:184:void onError(java.lang.Exception) -> a
+    188:191:void onDisconnect(int,java.lang.String) -> a
+    195:203:void onConnect() -> b
+com.leanplum.SocketIOClient$2$1 -> com.leanplum.aT:
+    java.lang.String val$messageId -> a
+    com.leanplum.SocketIOClient$2 this$1 -> b
+    152:152:void <init>(com.leanplum.SocketIOClient$2,java.lang.String) -> <init>
+    155:156:void run() -> run
+com.leanplum.SocketIOClient$2$2 -> com.leanplum.aU:
+    com.leanplum.SocketIOClient$2 this$1 -> a
+    195:195:void <init>(com.leanplum.SocketIOClient$2) -> <init>
+    198:200:void run() -> run
+com.leanplum.SocketIOClient$3 -> com.leanplum.aV:
+    com.leanplum.SocketIOClient this$0 -> a
+    228:228:void <init>(com.leanplum.SocketIOClient) -> <init>
+    230:254:void run() -> run
+com.leanplum.SocketIOClient$Handler -> com.leanplum.aW:
+    void onConnect() -> b
+    void on(java.lang.String,org.json.JSONArray) -> a
+    void onDisconnect$4f708078() -> a
+    void onError(java.lang.Exception) -> a
+com.leanplum.Util -> com.leanplum.Util:
+    java.util.concurrent.Executor asyncExecutor -> a
+    java.lang.String appName -> b
+    boolean hasPlayServicesCalled -> c
+    boolean hasPlayServices -> d
+    112:115:void verboseLog(java.lang.String) -> a
+    118:126:java.lang.String md5(java.lang.String) -> d
+    130:136:java.lang.String checkDeviceId(java.lang.String,java.lang.String) -> a
+    140:170:java.lang.String getWifiMacAddressHash(android.content.Context) -> b
+    181:198:com.leanplum.Util$DeviceIdInfo getAdvertisingId(android.content.Context) -> c
+    202:212:java.lang.String getAndroidId(android.content.Context) -> d
+    226:237:boolean isValidForCharset(java.lang.String,java.lang.String) -> b
+    241:258:boolean isValidUserId(java.lang.String) -> b
+    262:289:boolean isValidDeviceId(java.lang.String) -> c
+    293:323:com.leanplum.Util$DeviceIdInfo getDeviceId(com.leanplum.LeanplumDeviceIdMode) -> a
+    1220:1222:java.lang.String generateRandomDeviceId():220:222 -> a
+    1220:1222:com.leanplum.Util$DeviceIdInfo getDeviceId(com.leanplum.LeanplumDeviceIdMode):323 -> a
+    327:335:java.lang.String getVersionName() -> a
+    339:347:java.lang.String getDeviceModel() -> b
+    352:361:java.lang.String getApplicationName(android.content.Context) -> a
+    365:372:java.lang.String capitalize(java.lang.String) -> e
+    377:377:java.lang.String getSystemName() -> c
+    381:381:java.lang.String getSystemVersion() -> d
+    385:388:boolean isSimulator() -> e
+    392:395:java.lang.String getDeviceName() -> f
+    399:407:java.lang.String getLocale() -> g
+    411:427:java.lang.String getQuery(java.util.List) -> a
+    437:455:java.net.HttpURLConnection operation(java.lang.String,java.lang.String,java.util.Map,java.lang.String,boolean,int) -> a
+    1460:1471:java.lang.String attachGetParameters(java.lang.String,java.util.Map):460:471 -> a
+    1460:1471:java.net.HttpURLConnection operation(java.lang.String,java.lang.String,java.util.Map,java.lang.String,boolean,int):438 -> a
+    477:492:void attachPostParameters(java.util.Map,java.net.HttpURLConnection) -> a
+    498:503:java.net.HttpURLConnection createHttpUrlConnection(java.lang.String,java.lang.String,java.lang.String,boolean,int) -> a
+    1510:1528:java.net.HttpURLConnection createHttpUrlConnection(java.lang.String,java.lang.String,boolean,int):510:528 -> a
+    1510:1528:java.net.HttpURLConnection createHttpUrlConnection(java.lang.String,java.lang.String,java.lang.String,boolean,int):503 -> a
+    2377:2377:java.lang.String getSystemName():377:377 -> a
+    2377:2377:java.net.HttpURLConnection createHttpUrlConnection(java.lang.String,java.lang.String,boolean,int):526 -> a
+    2377:2377:java.net.HttpURLConnection createHttpUrlConnection(java.lang.String,java.lang.String,java.lang.String,boolean,int):503 -> a
+    2381:2381:java.lang.String getSystemVersion():381:381 -> a
+    2381:2381:java.net.HttpURLConnection createHttpUrlConnection(java.lang.String,java.lang.String,boolean,int):527 -> a
+    2381:2381:java.net.HttpURLConnection createHttpUrlConnection(java.lang.String,java.lang.String,java.lang.String,boolean,int):503 -> a
+    549:610:java.net.HttpURLConnection uploadFilesOperation(java.lang.String,java.util.List,java.util.List,java.lang.String,java.lang.String,java.util.Map,java.lang.String,boolean,int) -> a
+    614:621:void saveResponse(java.net.URLConnection,java.io.OutputStream) -> a
+    640:647:org.json.JSONObject getJsonResponse(java.net.HttpURLConnection) -> a
+    2625:2635:java.lang.String getResponse(java.net.HttpURLConnection):625:635 -> a
+    2625:2635:org.json.JSONObject getJsonResponse(java.net.HttpURLConnection):640 -> a
+    652:665:boolean isConnected() -> h
+    671:681:java.lang.Object multiIndex(java.util.Map,java.lang.Object[]) -> a
+    685:690:void executeAsyncTask(android.os.AsyncTask,java.lang.Object[]) -> a
+    698:727:boolean hasPlayServices() -> i
+    731:731:boolean isInBackground() -> j
+    740:758:void initializePreLeanplumInstall(java.util.Map) -> a
+    2765:2772:void setInstallTime(java.util.Map,android.content.pm.PackageManager,java.lang.String):765:772 -> a
+    2765:2772:void initializePreLeanplumInstall(java.util.Map):748 -> a
+    2780:2787:void setUpdateTime(java.util.Map,android.content.pm.PackageManager,java.lang.String):780:787 -> a
+    2780:2787:void initializePreLeanplumInstall(java.util.Map):749 -> a
+    793:839:void handleException(java.lang.Throwable) -> a
+    845:854:java.util.Map newMap(java.lang.Object,java.lang.Object,java.lang.Object[]) -> a
+    73:80:void <clinit>() -> <clinit>
+com.leanplum.Util$DeviceIdInfo -> com.leanplum.Util$DeviceIdInfo:
+    java.lang.String id -> a
+    boolean limitAdTracking -> b
+    86:88:void <init>(java.lang.String) -> <init>
+    90:93:void <init>(java.lang.String,boolean) -> <init>
+com.leanplum.Var -> com.leanplum.Var:
+    java.lang.String name -> c
+    java.lang.String[] nameComponents -> d
+    java.lang.String stringValue -> a
+    java.lang.Double numberValue -> e
+    java.lang.Object defaultValue -> f
+    java.lang.Object value -> g
+    java.lang.String kind -> h
+    java.util.List fileReadyHandlers -> i
+    java.util.List valueChangedHandlers -> j
+    boolean fileIsPending -> k
+    boolean hadStarted -> l
+    boolean isAsset -> m
+    boolean isResource -> b
+    int size -> n
+    java.lang.String hash -> o
+    byte[] data -> p
+    boolean valueIsInAssets -> q
+    boolean isInternal -> r
+    int overrideResId -> s
+    boolean printedCallbackWarning -> t
+    52:58:void warnIfNotStarted() -> b
+    66:102:com.leanplum.Var define(java.lang.String,java.lang.Object,java.lang.String,com.leanplum.Var$VarInitializer) -> a
+    111:111:com.leanplum.Var define(java.lang.String,java.lang.Object) -> define
+    115:115:com.leanplum.Var define(java.lang.String,java.lang.Object,java.lang.String) -> define
+    119:119:com.leanplum.Var defineColor(java.lang.String,int) -> defineColor
+    123:123:com.leanplum.Var defineFile(java.lang.String,java.lang.String) -> defineFile
+    127:127:com.leanplum.Var defineAsset(java.lang.String,java.lang.String) -> defineAsset
+    137:137:com.leanplum.Var defineResource(java.lang.String,java.lang.String,int,java.lang.String,byte[]) -> a
+    37:148:void <init>() -> <init>
+    154:154:java.lang.String name() -> name
+    158:158:java.lang.String[] nameComponents() -> nameComponents
+    165:165:java.lang.String kind() -> kind
+    169:169:java.lang.Object defaultValue() -> defaultValue
+    173:174:java.lang.Object value() -> value
+    178:178:int overrideResId() -> overrideResId
+    182:183:void setOverrideResId(int) -> setOverrideResId
+    187:220:void cacheComputedValues() -> c
+    226:275:void update() -> a
+    1278:1284:void triggerValueChanged():278:284 -> a
+    1278:1284:void update():246 -> a
+    287:298:void addValueChangedHandler(com.leanplum.callbacks.VariableCallback) -> addValueChangedHandler
+    301:304:void removeValueChangedHandler(com.leanplum.callbacks.VariableCallback) -> removeValueChangedHandler
+    307:314:void triggerFileIsReady() -> d
+    317:327:void addFileReadyHandler(com.leanplum.callbacks.VariableCallback) -> addFileReadyHandler
+    330:337:void removeFileReadyHandler(com.leanplum.callbacks.VariableCallback) -> removeFileReadyHandler
+    341:348:java.lang.String fileValue() -> fileValue
+    352:365:java.lang.Object objectForKeyPath(java.lang.Object[]) -> objectForKeyPath
+    371:381:int count() -> count
+    385:386:java.lang.Number numberValue() -> numberValue
+    390:391:java.lang.String stringValue() -> stringValue
+    396:408:java.io.InputStream stream() -> stream
+    414:421:java.io.InputStream defaultStream() -> defaultStream
+    427:427:java.lang.String toString() -> toString
+    27:27:boolean access$002(com.leanplum.Var,boolean) -> a
+    27:27:int access$102(com.leanplum.Var,int) -> a
+    27:27:java.lang.String access$202(com.leanplum.Var,java.lang.String) -> a
+    27:27:byte[] access$302(com.leanplum.Var,byte[]) -> a
+    27:27:void access$400(com.leanplum.Var) -> a
+com.leanplum.Var$1 -> com.leanplum.aX:
+    127:127:void <init>() -> <init>
+    130:131:void init(com.leanplum.Var) -> a
+com.leanplum.Var$2 -> com.leanplum.aY:
+    int val$size -> a
+    java.lang.String val$hash -> b
+    byte[] val$data -> c
+    137:137:void <init>(int,java.lang.String,byte[]) -> <init>
+    140:144:void init(com.leanplum.Var) -> a
+com.leanplum.Var$3 -> com.leanplum.aZ:
+    com.leanplum.Var this$0 -> a
+    254:254:void <init>(com.leanplum.Var) -> <init>
+    257:258:void run() -> run
+com.leanplum.Var$VarInitializer -> com.leanplum.ba:
+    void init(com.leanplum.Var) -> a
+com.leanplum.VarCache -> com.leanplum.bb:
+    java.util.Map vars -> b
+    java.util.Map fileAttributes -> c
+    java.util.Map fileStreams -> d
+    java.util.Map valuesFromClient -> a
+    java.util.Map defaultKinds -> e
+    java.util.Map actionDefinitions -> f
+    java.util.Map diffs -> g
+    java.util.Map regions -> h
+    java.util.Map messageDiffs -> i
+    java.util.Map devModeValuesFromServer -> j
+    java.util.Map devModeFileAttributesFromServer -> k
+    java.util.Map devModeActionDefinitionsFromServer -> l
+    java.util.List variants -> m
+    com.leanplum.VarCache$CacheUpdateBlock updateBlock -> n
+    boolean hasReceivedDiffs -> o
+    java.util.Map messages -> p
+    java.lang.Object merged -> q
+    boolean silent -> r
+    int contentVersion -> s
+    java.util.Map userAttributes -> t
+    java.util.regex.Pattern NAME_COMPONENT_PATTERN -> u
+    69:74:java.lang.String[] getNameComponents(java.lang.String) -> a
+    79:97:java.lang.Object traverse(java.lang.Object,java.lang.Object,boolean) -> a
+    103:133:boolean registerFile(java.lang.String,java.lang.String,java.io.InputStream,boolean,java.lang.String,int) -> a
+    140:147:void updateValues(java.lang.String,java.lang.String[],java.lang.Object,java.lang.String,java.util.Map,java.util.Map) -> a
+    150:156:void registerVariable(com.leanplum.Var) -> a
+    160:160:com.leanplum.Var getVariable(java.lang.String) -> b
+    170:246:java.lang.Object mergeHelper(java.lang.Object,java.lang.Object) -> a
+    251:255:java.lang.Object getMergedValueFromComponentArray(java.lang.Object[],java.lang.Object) -> a
+    259:259:java.lang.Object getMergedValueFromComponentArray(java.lang.Object[]) -> a
+    264:264:java.util.Map diffs() -> a
+    268:268:java.util.Map messageDiffs() -> b
+    276:276:boolean hasReceivedDiffs() -> c
+    280:328:void loadDiffs() -> d
+    331:362:void saveDiffs() -> e
+    368:380:int getResIdFromPath(java.lang.String) -> c
+    389:402:void fileVariableFinish() -> p
+    410:475:void applyVariableDiffs(java.util.Map,java.util.Map,java.util.Map,java.util.List) -> a
+    1164:1167:void computeMergedDictionary():164:167 -> a
+    1164:1167:void applyVariableDiffs(java.util.Map,java.util.Map,java.util.Map,java.util.List):412 -> a
+    1505:1509:void triggerHasReceivedDiffs():505:509 -> a
+    1505:1509:void applyVariableDiffs(java.util.Map,java.util.Map,java.util.Map,java.util.List):473 -> a
+    478:478:int contentVersion() -> f
+    512:512:boolean sendVariablesIfChanged() -> g
+    516:516:boolean sendActionsIfChanged() -> h
+    520:543:boolean sendContentIfChanged(boolean,boolean) -> a
+    2484:2501:boolean areActionDefinitionsEqual(java.util.Map,java.util.Map):484:501 -> a
+    2484:2501:boolean sendContentIfChanged(boolean,boolean):525 -> a
+    549:620:void maybeUploadNewFiles() -> i
+    627:628:void setSilent(boolean) -> a
+    631:631:boolean silent() -> j
+    636:639:void setDevModeValuesFromServer(java.util.Map,java.util.Map,java.util.Map) -> a
+    642:643:void onUpdate(com.leanplum.VarCache$CacheUpdateBlock) -> a
+    646:646:java.util.List variants() -> k
+    650:650:java.util.Map actionDefinitions() -> l
+    654:654:java.util.Map messages() -> m
+    660:675:void registerActionDefinition(java.lang.String,int,java.util.List,java.util.Map) -> a
+    678:700:java.lang.String kindFromValue(java.lang.Object) -> a
+    704:717:java.util.Map userAttributes() -> n
+    721:737:void saveUserAttributes() -> o
+    38:66:void <clinit>() -> <clinit>
+com.leanplum.VarCache$CacheUpdateBlock -> com.leanplum.bc:
+    1559:1563:void com.leanplum.Leanplum$1.updateCache():559:563 -> a
+    2556:2556:void com.leanplum.Leanplum$1.<init>():556:556 -> <init>
+com.leanplum.WebSocketClient -> com.leanplum.bd:
+    java.net.URI mURI -> a
+    com.leanplum.WebSocketClient$Listener mListener -> b
+    java.net.Socket mSocket -> c
+    java.lang.Thread mThread -> d
+    android.os.HandlerThread mHandlerThread -> e
+    android.os.Handler mHandler -> f
+    java.util.List mExtraHeaders -> g
+    com.leanplum.HybiParser mParser -> h
+    java.lang.Object mSendLock -> i
+    62:79:void <init>(java.net.URI,com.leanplum.WebSocketClient$Listener,java.util.List) -> <init>
+    82:82:com.leanplum.WebSocketClient$Listener getListener() -> a
+    86:162:void connect() -> b
+    165:181:void disconnect() -> c
+    184:185:void send(java.lang.String) -> a
+    231:247:void sendFrame(byte[]) -> a
+    50:50:java.net.URI access$000(com.leanplum.WebSocketClient) -> a
+    50:50:javax.net.ssl.SSLSocketFactory access$100(com.leanplum.WebSocketClient) -> b
+    1258:1260:javax.net.ssl.SSLSocketFactory getSSLSocketFactory():258:260 -> b
+    1258:1260:javax.net.ssl.SSLSocketFactory access$100(com.leanplum.WebSocketClient):50 -> b
+    50:50:java.net.Socket access$202(com.leanplum.WebSocketClient,java.net.Socket) -> a
+    50:50:java.net.Socket access$200(com.leanplum.WebSocketClient) -> c
+    50:50:java.lang.String access$300(com.leanplum.WebSocketClient) -> d
+    2223:2227:java.lang.String createSecret():223:227 -> d
+    2223:2227:java.lang.String access$300(com.leanplum.WebSocketClient):50 -> d
+    50:50:java.util.List access$400(com.leanplum.WebSocketClient) -> e
+    50:50:java.lang.String access$500(com.leanplum.WebSocketClient,com.leanplum.HybiParser$HappyDataInputStream) -> a
+    3204:3219:java.lang.String readLine(com.leanplum.HybiParser$HappyDataInputStream):204:219 -> a
+    3204:3219:java.lang.String access$500(com.leanplum.WebSocketClient,com.leanplum.HybiParser$HappyDataInputStream):50 -> a
+    50:50:org.apache.http.StatusLine access$600(com.leanplum.WebSocketClient,java.lang.String) -> a
+    4192:4195:org.apache.http.StatusLine parseStatusLine(java.lang.String):192:195 -> a
+    4192:4195:org.apache.http.StatusLine access$600(com.leanplum.WebSocketClient,java.lang.String):50 -> a
+    50:50:org.apache.http.Header access$700(com.leanplum.WebSocketClient,java.lang.String) -> b
+    4199:4199:org.apache.http.Header parseHeader(java.lang.String):199:199 -> b
+    4199:4199:org.apache.http.Header access$700(com.leanplum.WebSocketClient,java.lang.String):50 -> b
+    50:50:com.leanplum.WebSocketClient$Listener access$800(com.leanplum.WebSocketClient) -> f
+    50:50:com.leanplum.HybiParser access$900(com.leanplum.WebSocketClient) -> g
+    50:50:java.lang.Object access$1000(com.leanplum.WebSocketClient) -> h
+com.leanplum.WebSocketClient$1 -> com.leanplum.be:
+    com.leanplum.WebSocketClient this$0 -> a
+    90:90:void <init>(com.leanplum.WebSocketClient) -> <init>
+    94:159:void run() -> run
+com.leanplum.WebSocketClient$2 -> com.leanplum.bf:
+    com.leanplum.WebSocketClient this$0 -> a
+    166:166:void <init>(com.leanplum.WebSocketClient) -> <init>
+    170:178:void run() -> run
+com.leanplum.WebSocketClient$3 -> com.leanplum.bg:
+    byte[] val$frame -> a
+    com.leanplum.WebSocketClient this$0 -> b
+    231:231:void <init>(com.leanplum.WebSocketClient,byte[]) -> <init>
+    235:245:void run() -> run
+com.leanplum.WebSocketClient$Listener -> com.leanplum.bh:
+    void onConnect() -> b
+    void onMessage(java.lang.String) -> a
+    void onMessage$25e06fc() -> a
+    void onDisconnect(int,java.lang.String) -> a
+    void onError(java.lang.Exception) -> a
+LeanplumAccountAuthenticatorActivity -> LeanplumAccountAuthenticatorActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumActionBarActivity -> LeanplumActionBarActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    12:12:void <init>() -> <init>
+    16:19:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    24:26:void onPause() -> onPause
+    30:32:void onStop() -> onStop
+    36:38:void onResume() -> onResume
+    42:45:android.content.res.Resources getResources() -> getResources
+    50:55:void setContentView(int) -> setContentView
+LeanplumActivity -> LeanplumActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumActivityGroup -> LeanplumActivityGroup:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    12:12:void <init>() -> <init>
+    16:19:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    24:26:void onPause() -> onPause
+    30:32:void onStop() -> onStop
+    36:38:void onResume() -> onResume
+    42:45:android.content.res.Resources getResources() -> getResources
+    50:55:void setContentView(int) -> setContentView
+LeanplumAliasActivity -> LeanplumAliasActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumAppCompatActivity -> LeanplumAppCompatActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumExpandableListActivity -> LeanplumExpandableListActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumFragmentActivity -> LeanplumFragmentActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumLauncherActivity -> LeanplumLauncherActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumListActivity -> LeanplumListActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumNativeActivity -> LeanplumNativeActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+LeanplumPreferenceActivity -> LeanplumPreferenceActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+com.leanplum.activities.LeanplumSherlockActivity -> com.leanplum.activities.LeanplumSherlockActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+com.leanplum.activities.LeanplumSherlockExpandableListActivity -> com.leanplum.activities.LeanplumSherlockExpandableListActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    16:19:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    24:26:void onPause() -> onPause
+    30:32:void onStop() -> onStop
+    36:38:void onResume() -> onResume
+    42:45:android.content.res.Resources getResources() -> getResources
+    50:55:void setContentView(int) -> setContentView
+com.leanplum.activities.LeanplumSherlockFragmentActivity -> com.leanplum.activities.LeanplumSherlockFragmentActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    11:11:void <init>() -> <init>
+    15:18:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    23:25:void onPause() -> onPause
+    29:31:void onStop() -> onStop
+    35:37:void onResume() -> onResume
+    41:44:android.content.res.Resources getResources() -> getResources
+    49:54:void setContentView(int) -> setContentView
+com.leanplum.activities.LeanplumSherlockPreferenceActivity -> com.leanplum.activities.LeanplumSherlockPreferenceActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    10:10:void <init>() -> <init>
+    14:17:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    22:24:void onPause() -> onPause
+    28:30:void onStop() -> onStop
+    34:36:void onResume() -> onResume
+    40:43:android.content.res.Resources getResources() -> getResources
+    48:53:void setContentView(int) -> setContentView
+LeanplumTabActivity -> LeanplumTabActivity:
+    com.leanplum.LeanplumActivityHelper helper -> a
+    12:12:void <init>() -> <init>
+    16:19:com.leanplum.LeanplumActivityHelper getHelper() -> a
+    24:26:void onPause() -> onPause
+    30:32:void onStop() -> onStop
+    36:38:void onResume() -> onResume
+    42:45:android.content.res.Resources getResources() -> getResources
+    50:55:void setContentView(int) -> setContentView
+com.leanplum.annotations.File -> com.leanplum.annotations.File:
+    java.lang.String group() -> group
+    java.lang.String name() -> name
+com.leanplum.annotations.Parser -> com.leanplum.annotations.Parser:
+    19:19:void <init>() -> <init>
+    26:54:void defineVariable(java.lang.Object,java.lang.String,java.lang.Object,java.lang.String,java.lang.reflect.Field) -> a
+    96:102:void parseVariables(java.lang.Object[]) -> parseVariables
+    109:115:void parseVariablesForClasses(java.lang.Class[]) -> parseVariablesForClasses
+    119:181:void parseVariablesHelper(java.lang.Object,java.lang.Class) -> a
+    1061:1089:void defineFileVariable(java.lang.Object,java.lang.String,java.lang.String,java.lang.reflect.Field):61:89 -> a
+    1061:1089:void parseVariablesHelper(java.lang.Object,java.lang.Class):175 -> a
+com.leanplum.annotations.Parser$1 -> com.leanplum.annotations.a:
+    java.lang.ref.WeakReference val$weakInstance -> a
+    boolean val$hasInstance -> b
+    java.lang.reflect.Field val$field -> c
+    com.leanplum.Var val$var -> d
+    29:29:void <init>(java.lang.ref.WeakReference,boolean,java.lang.reflect.Field,com.leanplum.Var) -> <init>
+    32:52:void handle(com.leanplum.Var) -> handle
+com.leanplum.annotations.Parser$2 -> com.leanplum.annotations.b:
+    java.lang.ref.WeakReference val$weakInstance -> a
+    boolean val$hasInstance -> b
+    java.lang.reflect.Field val$field -> c
+    com.leanplum.Var val$var -> d
+    64:64:void <init>(java.lang.ref.WeakReference,boolean,java.lang.reflect.Field,com.leanplum.Var) -> <init>
+    67:87:void handle(com.leanplum.Var) -> handle
+com.leanplum.annotations.Variable -> com.leanplum.annotations.Variable:
+    java.lang.String group() -> group
+    java.lang.String name() -> name
+com.leanplum.callbacks.ActionCallback -> com.leanplum.callbacks.ActionCallback:
+    11:11:void <init>() -> <init>
+    boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.callbacks.NewsfeedChangedCallback -> com.leanplum.callbacks.NewsfeedChangedCallback:
+    10:10:void <init>() -> <init>
+    12:13:void run() -> run
+    void newsfeedChanged() -> newsfeedChanged
+com.leanplum.callbacks.RegisterDeviceCallback -> com.leanplum.callbacks.RegisterDeviceCallback:
+    com.leanplum.callbacks.RegisterDeviceCallback$EmailCallback callback -> a
+    9:10:void <init>() -> <init>
+    27:28:void setResponseHandler(com.leanplum.callbacks.RegisterDeviceCallback$EmailCallback) -> setResponseHandler
+    31:32:void run() -> run
+    void onResponse(com.leanplum.callbacks.RegisterDeviceCallback$EmailCallback) -> onResponse
+com.leanplum.callbacks.RegisterDeviceCallback$EmailCallback -> com.leanplum.callbacks.RegisterDeviceCallback$EmailCallback:
+    java.lang.String email -> a
+    10:10:void <init>() -> <init>
+    14:15:void setResponseHandler(java.lang.String) -> setResponseHandler
+    18:19:void run() -> run
+    void onResponse(java.lang.String) -> onResponse
+com.leanplum.callbacks.RegisterDeviceFinishedCallback -> com.leanplum.callbacks.RegisterDeviceFinishedCallback:
+    boolean success -> a
+    9:9:void <init>() -> <init>
+    13:14:void setSuccess(boolean) -> setSuccess
+    17:18:void run() -> run
+    void onResponse(boolean) -> onResponse
+com.leanplum.callbacks.StartCallback -> com.leanplum.callbacks.StartCallback:
+    boolean success -> a
+    10:10:void <init>() -> <init>
+    14:15:void setSuccess(boolean) -> setSuccess
+    18:19:void run() -> run
+    void onResponse(boolean) -> onResponse
+com.leanplum.callbacks.VariableCallback -> com.leanplum.callbacks.VariableCallback:
+    com.leanplum.Var variable -> a
+    11:11:void <init>() -> <init>
+    15:16:void setVariable(com.leanplum.Var) -> setVariable
+    19:20:void run() -> run
+    void handle(com.leanplum.Var) -> handle
+com.leanplum.callbacks.VariablesChangedCallback -> com.leanplum.callbacks.VariablesChangedCallback:
+    9:9:void <init>() -> <init>
+    11:12:void run() -> run
+    void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.Alert -> com.leanplum.messagetemplates.a:
+com.leanplum.messagetemplates.Alert$1 -> com.leanplum.messagetemplates.b:
+    34:34:void <init>() -> <init>
+    38:58:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.messagetemplates.Alert$1$1 -> com.leanplum.messagetemplates.c:
+    com.leanplum.ActionContext val$context -> a
+    38:38:void <init>(com.leanplum.messagetemplates.Alert$1,com.leanplum.ActionContext) -> <init>
+    41:56:void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.Alert$1$1$1 -> com.leanplum.messagetemplates.d:
+    com.leanplum.messagetemplates.Alert$1$1 this$1 -> a
+    49:49:void <init>(com.leanplum.messagetemplates.Alert$1$1) -> <init>
+    51:52:void onClick(android.content.DialogInterface,int) -> onClick
+com.leanplum.messagetemplates.BaseMessageDialog -> com.leanplum.messagetemplates.BaseMessageDialog:
+    android.widget.RelativeLayout dialogView -> a
+    com.leanplum.messagetemplates.BaseMessageOptions options -> options
+    com.leanplum.messagetemplates.WebInterstitialOptions webOptions -> webOptions
+    boolean isWeb -> b
+    boolean isClosing -> c
+    45:81:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions) -> <init>
+    1344:1349:int getTheme(android.app.Activity):344:349 -> <init>
+    1344:1349:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):49 -> <init>
+    2147:2215:android.widget.RelativeLayout createContainerView(android.app.Activity,boolean):147:215 -> <init>
+    2147:2215:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):62 -> <init>
+    2226:2246:android.widget.ImageView createBackgroundImageView(android.content.Context,boolean):226:246 -> <init>
+    2226:2246:android.widget.RelativeLayout createContainerView(android.app.Activity,boolean):193 -> <init>
+    2226:2246:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):62 -> <init>
+    2250:2268:android.widget.RelativeLayout createTitleView(android.content.Context):250:268 -> <init>
+    2250:2268:android.widget.RelativeLayout createContainerView(android.app.Activity,boolean):196 -> <init>
+    2250:2268:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):62 -> <init>
+    2314:2340:android.widget.TextView createAcceptButton(android.content.Context):314:340 -> <init>
+    2314:2340:android.widget.RelativeLayout createContainerView(android.app.Activity,boolean):200 -> <init>
+    2314:2340:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):62 -> <init>
+    3272:3280:android.widget.TextView createMessageView(android.content.Context):272:280 -> <init>
+    3272:3280:android.widget.RelativeLayout createContainerView(android.app.Activity,boolean):204 -> <init>
+    3272:3280:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):62 -> <init>
+    3284:3310:android.webkit.WebView createWebView(android.content.Context):284:310 -> <init>
+    3284:3310:android.widget.RelativeLayout createContainerView(android.app.Activity,boolean):211 -> <init>
+    3284:3310:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):62 -> <init>
+    4122:4142:com.leanplum.views.CloseButton createCloseButton(android.app.Activity,boolean,android.view.View):122:142 -> <init>
+    4122:4142:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):67 -> <init>
+    5084:5087:android.view.animation.Animation createFadeInAnimation():84:87 -> <init>
+    5084:5087:void <init>(android.app.Activity,boolean,com.leanplum.messagetemplates.BaseMessageOptions,com.leanplum.messagetemplates.WebInterstitialOptions):73 -> <init>
+    99:119:void cancel() -> cancel
+    5091:5094:android.view.animation.Animation createFadeOutAnimation():91:94 -> cancel
+    5091:5094:void cancel():103 -> cancel
+    219:221:android.graphics.drawable.shapes.Shape createRoundRect(int) -> a
+    41:41:void access$001(com.leanplum.messagetemplates.BaseMessageDialog) -> a
+    41:41:boolean access$100(com.leanplum.messagetemplates.BaseMessageDialog) -> b
+com.leanplum.messagetemplates.BaseMessageDialog$1 -> com.leanplum.messagetemplates.e:
+    com.leanplum.messagetemplates.BaseMessageDialog this$0 -> a
+    104:104:void <init>(com.leanplum.messagetemplates.BaseMessageDialog) -> <init>
+    105:105:void onAnimationStart(android.view.animation.Animation) -> onAnimationStart
+    106:106:void onAnimationRepeat(android.view.animation.Animation) -> onAnimationRepeat
+    109:116:void onAnimationEnd(android.view.animation.Animation) -> onAnimationEnd
+com.leanplum.messagetemplates.BaseMessageDialog$1$1 -> com.leanplum.messagetemplates.f:
+    com.leanplum.messagetemplates.BaseMessageDialog$1 this$1 -> a
+    110:110:void <init>(com.leanplum.messagetemplates.BaseMessageDialog$1) -> <init>
+    113:114:void run() -> run
+com.leanplum.messagetemplates.BaseMessageDialog$2 -> com.leanplum.messagetemplates.g:
+    com.leanplum.messagetemplates.BaseMessageDialog this$0 -> a
+    136:136:void <init>(com.leanplum.messagetemplates.BaseMessageDialog) -> <init>
+    139:140:void onClick(android.view.View) -> onClick
+com.leanplum.messagetemplates.BaseMessageDialog$3 -> com.leanplum.messagetemplates.h:
+    com.leanplum.messagetemplates.BaseMessageDialog this$0 -> a
+    288:288:void <init>(com.leanplum.messagetemplates.BaseMessageDialog) -> <init>
+    291:306:boolean shouldOverrideUrlLoading(android.webkit.WebView,java.lang.String) -> shouldOverrideUrlLoading
+com.leanplum.messagetemplates.BaseMessageDialog$4 -> com.leanplum.messagetemplates.i:
+    com.leanplum.messagetemplates.BaseMessageDialog this$0 -> a
+    331:331:void <init>(com.leanplum.messagetemplates.BaseMessageDialog) -> <init>
+    334:338:void onClick(android.view.View) -> onClick
+com.leanplum.messagetemplates.BaseMessageOptions -> com.leanplum.messagetemplates.BaseMessageOptions:
+    com.leanplum.ActionContext context -> context
+    java.lang.String title -> title
+    int titleColor -> titleColor
+    java.lang.String messageText -> messageText
+    int messageColor -> messageColor
+    android.graphics.Bitmap backgroundImage -> backgroundImage
+    int backgroundColor -> backgroundColor
+    java.lang.String acceptButtonText -> acceptButtonText
+    int acceptButtonBackgroundColor -> acceptButtonBackgroundColor
+    int acceptButtonTextColor -> acceptButtonTextColor
+    34:54:void <init>(com.leanplum.ActionContext) -> <init>
+    57:57:int getBackgroundColor() -> getBackgroundColor
+    61:62:void setBackgroundColor(int) -> setBackgroundColor
+    65:65:java.lang.String getAcceptButtonText() -> getAcceptButtonText
+    69:70:void setAcceptButtonText(java.lang.String) -> setAcceptButtonText
+    73:73:java.lang.String getTitle() -> getTitle
+    77:78:void setTitle(java.lang.String) -> setTitle
+    81:81:int getTitleColor() -> getTitleColor
+    85:86:void setTitleColor(int) -> setTitleColor
+    89:89:java.lang.String getMessageText() -> getMessageText
+    93:94:void setMessageText(java.lang.String) -> setMessageText
+    97:97:int getMessageColor() -> getMessageColor
+    101:102:void setMessageColor(int) -> setMessageColor
+    105:105:android.graphics.Bitmap getBackgroundImage() -> getBackgroundImage
+    109:109:android.graphics.Bitmap getBackgroundImageRounded(int) -> getBackgroundImageRounded
+    113:114:void setBackgroundImage(android.graphics.Bitmap) -> setBackgroundImage
+    117:117:int getAcceptButtonBackgroundColor() -> getAcceptButtonBackgroundColor
+    121:122:void setAcceptButtonBackgroundColor(int) -> setAcceptButtonBackgroundColor
+    125:125:int getAcceptButtonTextColor() -> getAcceptButtonTextColor
+    129:130:void setAcceptButtonTextColor(int) -> setAcceptButtonTextColor
+    133:134:void accept() -> accept
+    137:148:com.leanplum.ActionArgs toArgs(android.content.Context) -> toArgs
+com.leanplum.messagetemplates.CenterPopup -> com.leanplum.messagetemplates.CenterPopup:
+    22:24:void <init>(android.app.Activity,com.leanplum.messagetemplates.CenterPopupOptions) -> <init>
+    27:49:void register(android.content.Context) -> register
+com.leanplum.messagetemplates.CenterPopup$1 -> com.leanplum.messagetemplates.j:
+    28:28:void <init>() -> <init>
+    31:46:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.messagetemplates.CenterPopup$1$1 -> com.leanplum.messagetemplates.k:
+    com.leanplum.ActionContext val$context -> a
+    32:32:void <init>(com.leanplum.messagetemplates.CenterPopup$1,com.leanplum.ActionContext) -> <init>
+    35:44:void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.CenterPopup$1$1$1 -> com.leanplum.messagetemplates.l:
+    com.leanplum.messagetemplates.CenterPopup$1$1 this$1 -> a
+    35:35:void <init>(com.leanplum.messagetemplates.CenterPopup$1$1) -> <init>
+    38:42:void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.CenterPopupOptions -> com.leanplum.messagetemplates.CenterPopupOptions:
+    int width -> a
+    int height -> b
+    20:23:void <init>(com.leanplum.ActionContext) -> <init>
+    1030:1031:void setWidth(int):30:31 -> <init>
+    1030:1031:void <init>(com.leanplum.ActionContext):21 -> <init>
+    1038:1039:void setHeight(int):38:39 -> <init>
+    1038:1039:void <init>(com.leanplum.ActionContext):22 -> <init>
+    26:26:int getWidth() -> getWidth
+    34:34:int getHeight() -> getHeight
+    42:44:com.leanplum.ActionArgs toArgs(android.content.Context) -> toArgs
+    15:15:void accept() -> accept
+    15:15:int getAcceptButtonTextColor() -> getAcceptButtonTextColor
+    15:15:int getAcceptButtonBackgroundColor() -> getAcceptButtonBackgroundColor
+    15:15:android.graphics.Bitmap getBackgroundImageRounded(int) -> getBackgroundImageRounded
+    15:15:android.graphics.Bitmap getBackgroundImage() -> getBackgroundImage
+    15:15:int getMessageColor() -> getMessageColor
+    15:15:java.lang.String getMessageText() -> getMessageText
+    15:15:int getTitleColor() -> getTitleColor
+    15:15:java.lang.String getTitle() -> getTitle
+    15:15:java.lang.String getAcceptButtonText() -> getAcceptButtonText
+    15:15:int getBackgroundColor() -> getBackgroundColor
+com.leanplum.messagetemplates.Confirm -> com.leanplum.messagetemplates.m:
+com.leanplum.messagetemplates.Confirm$1 -> com.leanplum.messagetemplates.n:
+    36:36:void <init>() -> <init>
+    40:66:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.messagetemplates.Confirm$1$1 -> com.leanplum.messagetemplates.o:
+    com.leanplum.ActionContext val$context -> a
+    40:40:void <init>(com.leanplum.messagetemplates.Confirm$1,com.leanplum.ActionContext) -> <init>
+    43:64:void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.Confirm$1$1$1 -> com.leanplum.messagetemplates.p:
+    com.leanplum.messagetemplates.Confirm$1$1 this$1 -> a
+    57:57:void <init>(com.leanplum.messagetemplates.Confirm$1$1) -> <init>
+    59:60:void onClick(android.content.DialogInterface,int) -> onClick
+com.leanplum.messagetemplates.Confirm$1$1$2 -> com.leanplum.messagetemplates.q:
+    com.leanplum.messagetemplates.Confirm$1$1 this$1 -> a
+    51:51:void <init>(com.leanplum.messagetemplates.Confirm$1$1) -> <init>
+    53:54:void onClick(android.content.DialogInterface,int) -> onClick
+com.leanplum.messagetemplates.Interstitial -> com.leanplum.messagetemplates.Interstitial:
+    22:24:void <init>(android.app.Activity,com.leanplum.messagetemplates.InterstitialOptions) -> <init>
+    27:50:void register(android.content.Context) -> register
+com.leanplum.messagetemplates.Interstitial$1 -> com.leanplum.messagetemplates.r:
+    29:29:void <init>() -> <init>
+    32:47:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.messagetemplates.Interstitial$1$1 -> com.leanplum.messagetemplates.s:
+    com.leanplum.ActionContext val$context -> a
+    33:33:void <init>(com.leanplum.messagetemplates.Interstitial$1,com.leanplum.ActionContext) -> <init>
+    36:45:void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.Interstitial$1$1$1 -> com.leanplum.messagetemplates.t:
+    com.leanplum.messagetemplates.Interstitial$1$1 this$1 -> a
+    36:36:void <init>(com.leanplum.messagetemplates.Interstitial$1$1) -> <init>
+    39:43:void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.InterstitialOptions -> com.leanplum.messagetemplates.InterstitialOptions:
+    16:18:void <init>(com.leanplum.ActionContext) -> <init>
+    21:22:com.leanplum.ActionArgs toArgs(android.content.Context) -> toArgs
+    14:14:void accept() -> accept
+    14:14:int getAcceptButtonTextColor() -> getAcceptButtonTextColor
+    14:14:int getAcceptButtonBackgroundColor() -> getAcceptButtonBackgroundColor
+    14:14:android.graphics.Bitmap getBackgroundImageRounded(int) -> getBackgroundImageRounded
+    14:14:android.graphics.Bitmap getBackgroundImage() -> getBackgroundImage
+    14:14:int getMessageColor() -> getMessageColor
+    14:14:java.lang.String getMessageText() -> getMessageText
+    14:14:int getTitleColor() -> getTitleColor
+    14:14:java.lang.String getTitle() -> getTitle
+    14:14:java.lang.String getAcceptButtonText() -> getAcceptButtonText
+    14:14:int getBackgroundColor() -> getBackgroundColor
+com.leanplum.messagetemplates.MessageTemplates -> com.leanplum.messagetemplates.MessageTemplates:
+    java.lang.Boolean registered -> a
+    11:44:void <init>() -> <init>
+    66:70:java.lang.String getApplicationName(android.content.Context) -> a
+    74:84:void register(android.content.Context) -> register
+    1031:1056:void com.leanplum.messagetemplates.OpenURL.register():31:56 -> register
+    1031:1056:void register(android.content.Context):78 -> register
+    2028:2061:void com.leanplum.messagetemplates.Alert.register(android.content.Context):28:61 -> register
+    2028:2061:void register(android.content.Context):79 -> register
+    3028:3069:void com.leanplum.messagetemplates.Confirm.register(android.content.Context):28:69 -> register
+    3028:3069:void register(android.content.Context):80 -> register
+    63:63:void <clinit>() -> <clinit>
+com.leanplum.messagetemplates.OpenURL$1 -> com.leanplum.messagetemplates.u:
+    33:33:void <init>() -> <init>
+    36:52:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.messagetemplates.WebInterstitial -> com.leanplum.messagetemplates.WebInterstitial:
+    23:25:void <init>(android.app.Activity,com.leanplum.messagetemplates.WebInterstitialOptions) -> <init>
+    28:44:void register(android.content.Context) -> register
+com.leanplum.messagetemplates.WebInterstitial$1 -> com.leanplum.messagetemplates.v:
+    29:29:void <init>() -> <init>
+    32:41:boolean onResponse(com.leanplum.ActionContext) -> onResponse
+com.leanplum.messagetemplates.WebInterstitial$1$1 -> com.leanplum.messagetemplates.w:
+    com.leanplum.ActionContext val$context -> a
+    32:32:void <init>(com.leanplum.messagetemplates.WebInterstitial$1,com.leanplum.ActionContext) -> <init>
+    35:39:void variablesChanged() -> variablesChanged
+com.leanplum.messagetemplates.WebInterstitialOptions -> com.leanplum.messagetemplates.WebInterstitialOptions:
+    java.lang.String url -> a
+    java.lang.String closeUrl -> b
+    boolean hasDismissButton -> c
+    20:24:void <init>(com.leanplum.ActionContext) -> <init>
+    1031:1032:void setUrl(java.lang.String):31:32 -> <init>
+    1031:1032:void <init>(com.leanplum.ActionContext):21 -> <init>
+    1039:1040:void setHasDismissButton(boolean):39:40 -> <init>
+    1039:1040:void <init>(com.leanplum.ActionContext):22 -> <init>
+    1047:1048:void setCloseUrl(java.lang.String):47:48 -> <init>
+    1047:1048:void <init>(com.leanplum.ActionContext):23 -> <init>
+    27:27:java.lang.String getUrl() -> getUrl
+    35:35:boolean hasDismissButton() -> hasDismissButton
+    43:43:java.lang.String getCloseUrl() -> getCloseUrl
+    51:54:com.leanplum.ActionArgs toArgs(android.content.Context) -> toArgs
+com.leanplum.utils.BitmapUtil -> com.leanplum.utils.BitmapUtil:
+    19:19:void <init>() -> <init>
+    21:44:android.graphics.Bitmap getRoundedCornerBitmap(android.graphics.Bitmap,int) -> getRoundedCornerBitmap
+    49:51:void stateBackgroundDarkerByPercentage(android.view.View,int,int) -> stateBackgroundDarkerByPercentage
+    54:64:int getDarker(int,int) -> getDarker
+    69:74:void stateBackground(android.view.View,int,int) -> stateBackground
+    78:96:android.graphics.drawable.Drawable getBackground(int,int) -> getBackground
+com.leanplum.utils.SizeUtil -> com.leanplum.utils.SizeUtil:
+    int dp2 -> dp2
+    int dp30 -> dp30
+    int dp5 -> dp5
+    int dp20 -> dp20
+    int dp18 -> dp18
+    int dp16 -> dp16
+    int dp14 -> dp14
+    int dp10 -> dp10
+    int dp7 -> dp7
+    int dp100 -> dp100
+    int dp200 -> dp200
+    int dp250 -> dp250
+    int dp50 -> dp50
+    int textSize0_2 -> textSize0_2
+    int textSize0_1 -> textSize0_1
+    int textSize0 -> textSize0
+    int textSize1 -> textSize1
+    int textSize2 -> textSize2
+    boolean hasInited -> a
+    14:14:void <init>() -> <init>
+    38:55:void init(android.content.Context) -> init
+    58:62:int dpToPx(android.content.Context,int) -> dpToPx
+    66:70:int pxToDp(android.content.Context,int) -> pxToDp
+    74:76:int spToPx(android.content.Context,int) -> spToPx
+    80:82:int pxToSp(android.content.Context,int) -> pxToSp
+    86:97:int getStatusBarHeight(android.app.Activity) -> getStatusBarHeight
+    35:35:void <clinit>() -> <clinit>
+com.leanplum.views.BackgroundImageView -> com.leanplum.views.BackgroundImageView:
+    android.graphics.Paint paint -> a
+    boolean fullscreen -> b
+    android.graphics.Matrix emptyMatrix -> c
+    boolean loadedBitmap -> d
+    26:34:void <init>(android.content.Context,android.util.AttributeSet,int) -> <init>
+    26:39:void <init>(android.content.Context,android.util.AttributeSet) -> <init>
+    26:45:void <init>(android.content.Context,boolean) -> <init>
+    48:51:void init$faab20d() -> a
+    55:67:void onDraw(android.graphics.Canvas) -> onDraw
+    70:79:android.graphics.Bitmap loadBitmapFromView(android.view.View) -> loadBitmapFromView
+com.leanplum.views.CloseButton -> com.leanplum.views.CloseButton:
+    android.graphics.Paint circlePaint -> a
+    android.graphics.Paint circlePressedPaint -> b
+    android.graphics.Paint linePaint -> c
+    float size -> d
+    float x1 -> e
+    float y1 -> f
+    float x2 -> g
+    float y2 -> h
+    boolean isPressed -> i
+    20:33:void <init>(android.content.Context) -> <init>
+    20:38:void <init>(android.content.Context,android.util.AttributeSet) -> <init>
+    41:58:void initLabelView$faab20d() -> a
+    62:62:boolean performClick() -> performClick
+    67:77:boolean onTouchEvent(android.view.MotionEvent) -> onTouchEvent
+    82:84:void onMeasure(int,int) -> onMeasure
+    88:93:void onDraw(android.graphics.Canvas) -> onDraw
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/proguard-rules.pro
@@ -0,0 +1,347 @@
+-dontwarn com.actionbarsherlock.**
+
+-dontnote
+-keepparameternames
+-keepattributes EnclosingMethod
+
+# Keep - Library. Keep all public and protected classes, fields, and methods.
+-keep public class com.leanplum.*,
+    com.leanplum.activities.*,
+    com.leanplum.annotations.*,
+    com.leanplum.callbacks.*,
+    com.leanplum.messagetemplates.*,
+    com.leanplum.utils.*,
+    com.leanplum.views.*
+{
+    public protected <fields>;
+    public protected <methods>;
+}
+
+# Also keep - Enumerations. Keep the special static methods that are required in
+# enumeration classes.
+-keepclassmembers enum  * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+# Also keep - Database drivers. Keep all implementations of java.sql.Driver.
+-keep class * extends java.sql.Driver
+
+
+# Keep names - Native method names. Keep all native class/method names.
+-keepclasseswithmembers,allowshrinking class * {
+    native <methods>;
+}
+
+# Remove - System method calls. Remove all invocations of System
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.System {
+    public static long currentTimeMillis();
+    static java.lang.Class getCallerClass();
+    public static int identityHashCode(java.lang.Object);
+    public static java.lang.SecurityManager getSecurityManager();
+    public static java.util.Properties getProperties();
+    public static java.lang.String getProperty(java.lang.String);
+    public static java.lang.String getenv(java.lang.String);
+    public static java.lang.String mapLibraryName(java.lang.String);
+    public static java.lang.String getProperty(java.lang.String,java.lang.String);
+}
+
+# Remove - Math method calls. Remove all invocations of Math
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.Math {
+    public static double sin(double);
+    public static double cos(double);
+    public static double tan(double);
+    public static double asin(double);
+    public static double acos(double);
+    public static double atan(double);
+    public static double toRadians(double);
+    public static double toDegrees(double);
+    public static double exp(double);
+    public static double log(double);
+    public static double log10(double);
+    public static double sqrt(double);
+    public static double cbrt(double);
+    public static double IEEEremainder(double,double);
+    public static double ceil(double);
+    public static double floor(double);
+    public static double rint(double);
+    public static double atan2(double,double);
+    public static double pow(double,double);
+    public static int round(float);
+    public static long round(double);
+    public static double random();
+    public static int abs(int);
+    public static long abs(long);
+    public static float abs(float);
+    public static double abs(double);
+    public static int max(int,int);
+    public static long max(long,long);
+    public static float max(float,float);
+    public static double max(double,double);
+    public static int min(int,int);
+    public static long min(long,long);
+    public static float min(float,float);
+    public static double min(double,double);
+    public static double ulp(double);
+    public static float ulp(float);
+    public static double signum(double);
+    public static float signum(float);
+    public static double sinh(double);
+    public static double cosh(double);
+    public static double tanh(double);
+    public static double hypot(double,double);
+    public static double expm1(double);
+    public static double log1p(double);
+}
+
+# Remove - Number method calls. Remove all invocations of Number
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.* extends java.lang.Number {
+    public static java.lang.String toString(byte);
+    public static java.lang.Byte valueOf(byte);
+    public static byte parseByte(java.lang.String);
+    public static byte parseByte(java.lang.String,int);
+    public static java.lang.Byte valueOf(java.lang.String,int);
+    public static java.lang.Byte valueOf(java.lang.String);
+    public static java.lang.Byte decode(java.lang.String);
+    public int compareTo(java.lang.Byte);
+    public static java.lang.String toString(short);
+    public static short parseShort(java.lang.String);
+    public static short parseShort(java.lang.String,int);
+    public static java.lang.Short valueOf(java.lang.String,int);
+    public static java.lang.Short valueOf(java.lang.String);
+    public static java.lang.Short valueOf(short);
+    public static java.lang.Short decode(java.lang.String);
+    public static short reverseBytes(short);
+    public int compareTo(java.lang.Short);
+    public static java.lang.String toString(int,int);
+    public static java.lang.String toHexString(int);
+    public static java.lang.String toOctalString(int);
+    public static java.lang.String toBinaryString(int);
+    public static java.lang.String toString(int);
+    public static int parseInt(java.lang.String,int);
+    public static int parseInt(java.lang.String);
+    public static java.lang.Integer valueOf(java.lang.String,int);
+    public static java.lang.Integer valueOf(java.lang.String);
+    public static java.lang.Integer valueOf(int);
+    public static java.lang.Integer getInteger(java.lang.String);
+    public static java.lang.Integer getInteger(java.lang.String,int);
+    public static java.lang.Integer getInteger(java.lang.String,java.lang.Integer);
+    public static java.lang.Integer decode(java.lang.String);
+    public static int highestOneBit(int);
+    public static int lowestOneBit(int);
+    public static int numberOfLeadingZeros(int);
+    public static int numberOfTrailingZeros(int);
+    public static int bitCount(int);
+    public static int rotateLeft(int,int);
+    public static int rotateRight(int,int);
+    public static int reverse(int);
+    public static int signum(int);
+    public static int reverseBytes(int);
+    public int compareTo(java.lang.Integer);
+    public static java.lang.String toString(long,int);
+    public static java.lang.String toHexString(long);
+    public static java.lang.String toOctalString(long);
+    public static java.lang.String toBinaryString(long);
+    public static java.lang.String toString(long);
+    public static long parseLong(java.lang.String,int);
+    public static long parseLong(java.lang.String);
+    public static java.lang.Long valueOf(java.lang.String,int);
+    public static java.lang.Long valueOf(java.lang.String);
+    public static java.lang.Long valueOf(long);
+    public static java.lang.Long decode(java.lang.String);
+    public static java.lang.Long getLong(java.lang.String);
+    public static java.lang.Long getLong(java.lang.String,long);
+    public static java.lang.Long getLong(java.lang.String,java.lang.Long);
+    public static long highestOneBit(long);
+    public static long lowestOneBit(long);
+    public static int numberOfLeadingZeros(long);
+    public static int numberOfTrailingZeros(long);
+    public static int bitCount(long);
+    public static long rotateLeft(long,int);
+    public static long rotateRight(long,int);
+    public static long reverse(long);
+    public static int signum(long);
+    public static long reverseBytes(long);
+    public int compareTo(java.lang.Long);
+    public static java.lang.String toString(float);
+    public static java.lang.String toHexString(float);
+    public static java.lang.Float valueOf(java.lang.String);
+    public static java.lang.Float valueOf(float);
+    public static float parseFloat(java.lang.String);
+    public static boolean isNaN(float);
+    public static boolean isInfinite(float);
+    public static int floatToIntBits(float);
+    public static int floatToRawIntBits(float);
+    public static float intBitsToFloat(int);
+    public static int compare(float,float);
+    public boolean isNaN();
+    public boolean isInfinite();
+    public int compareTo(java.lang.Float);
+    public static java.lang.String toString(double);
+    public static java.lang.String toHexString(double);
+    public static java.lang.Double valueOf(java.lang.String);
+    public static java.lang.Double valueOf(double);
+    public static double parseDouble(java.lang.String);
+    public static boolean isNaN(double);
+    public static boolean isInfinite(double);
+    public static long doubleToLongBits(double);
+    public static long doubleToRawLongBits(double);
+    public static double longBitsToDouble(long);
+    public static int compare(double,double);
+    public boolean isNaN();
+    public boolean isInfinite();
+    public int compareTo(java.lang.Double);
+    public <init>(byte);
+    public <init>(short);
+    public <init>(int);
+    public <init>(long);
+    public <init>(float);
+    public <init>(double);
+    public <init>(java.lang.String);
+    public byte byteValue();
+    public short shortValue();
+    public int intValue();
+    public long longValue();
+    public float floatValue();
+    public double doubleValue();
+    public int compareTo(java.lang.Object);
+    public boolean equals(java.lang.Object);
+    public int hashCode();
+    public java.lang.String toString();
+}
+
+# Remove - String method calls. Remove all invocations of String
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.String {
+    public <init>();
+    public <init>(byte[]);
+    public <init>(byte[],int);
+    public <init>(byte[],int,int);
+    public <init>(byte[],int,int,int);
+    public <init>(byte[],int,int,java.lang.String);
+    public <init>(byte[],java.lang.String);
+    public <init>(char[]);
+    public <init>(char[],int,int);
+    public <init>(java.lang.String);
+    public <init>(java.lang.StringBuffer);
+    public static java.lang.String copyValueOf(char[]);
+    public static java.lang.String copyValueOf(char[],int,int);
+    public static java.lang.String valueOf(boolean);
+    public static java.lang.String valueOf(char);
+    public static java.lang.String valueOf(char[]);
+    public static java.lang.String valueOf(char[],int,int);
+    public static java.lang.String valueOf(double);
+    public static java.lang.String valueOf(float);
+    public static java.lang.String valueOf(int);
+    public static java.lang.String valueOf(java.lang.Object);
+    public static java.lang.String valueOf(long);
+    public boolean contentEquals(java.lang.StringBuffer);
+    public boolean endsWith(java.lang.String);
+    public boolean equalsIgnoreCase(java.lang.String);
+    public boolean equals(java.lang.Object);
+    public boolean matches(java.lang.String);
+    public boolean regionMatches(boolean,int,java.lang.String,int,int);
+    public boolean regionMatches(int,java.lang.String,int,int);
+    public boolean startsWith(java.lang.String);
+    public boolean startsWith(java.lang.String,int);
+    public byte[] getBytes();
+    public byte[] getBytes(java.lang.String);
+    public char charAt(int);
+    public char[] toCharArray();
+    public int compareToIgnoreCase(java.lang.String);
+    public int compareTo(java.lang.Object);
+    public int compareTo(java.lang.String);
+    public int hashCode();
+    public int indexOf(int);
+    public int indexOf(int,int);
+    public int indexOf(java.lang.String);
+    public int indexOf(java.lang.String,int);
+    public int lastIndexOf(int);
+    public int lastIndexOf(int,int);
+    public int lastIndexOf(java.lang.String);
+    public int lastIndexOf(java.lang.String,int);
+    public int length();
+    public java.lang.CharSequence subSequence(int,int);
+    public java.lang.String concat(java.lang.String);
+    public java.lang.String replaceAll(java.lang.String,java.lang.String);
+    public java.lang.String replace(char,char);
+    public java.lang.String replaceFirst(java.lang.String,java.lang.String);
+    public java.lang.String[] split(java.lang.String);
+    public java.lang.String[] split(java.lang.String,int);
+    public java.lang.String substring(int);
+    public java.lang.String substring(int,int);
+    public java.lang.String toLowerCase();
+    public java.lang.String toLowerCase(java.util.Locale);
+    public java.lang.String toString();
+    public java.lang.String toUpperCase();
+    public java.lang.String toUpperCase(java.util.Locale);
+    public java.lang.String trim();
+}
+
+# Remove - StringBuffer method calls. Remove all invocations of StringBuffer
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.StringBuffer {
+    public <init>();
+    public <init>(int);
+    public <init>(java.lang.String);
+    public <init>(java.lang.CharSequence);
+    public java.lang.String toString();
+    public char charAt(int);
+    public int capacity();
+    public int codePointAt(int);
+    public int codePointBefore(int);
+    public int indexOf(java.lang.String,int);
+    public int lastIndexOf(java.lang.String);
+    public int lastIndexOf(java.lang.String,int);
+    public int length();
+    public java.lang.String substring(int);
+    public java.lang.String substring(int,int);
+}
+
+# Remove - StringBuilder method calls. Remove all invocations of StringBuilder
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.StringBuilder {
+    public <init>();
+    public <init>(int);
+    public <init>(java.lang.String);
+    public <init>(java.lang.CharSequence);
+    public java.lang.String toString();
+    public char charAt(int);
+    public int capacity();
+    public int codePointAt(int);
+    public int codePointBefore(int);
+    public int indexOf(java.lang.String,int);
+    public int lastIndexOf(java.lang.String);
+    public int lastIndexOf(java.lang.String,int);
+    public int length();
+    public java.lang.String substring(int);
+    public java.lang.String substring(int,int);
+}
+
+-keepattributes *Annotation*
+-keepattributes Signature
+-keepattributes Exceptions
+
+-keep class com.leanplum.Leanplum {
+    static void reset();
+    static void setClient(java.lang.String, java.lang.String, java.lang.String);
+}
+
+-keep class com.leanplum.utils.BitmapUtil { public private protected *; }
+
+-keep class com.leanplum.LocationManagerImplementation { *; }
+
+-keep class com.leanplum.messagetemplates.BaseMessageOptions { *; }
+
+-dontwarn android.support.v7.**
+-keep class android.support.v7.** { *; }
+-keep interface android.support.v7.** { *; }
+
+-printmapping out.map
+-renamesourcefileattribute SourceFile
+-keepattributes SourceFile,LineNumberTable
+
+-optimizations !code/allocation/variable
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/project.properties
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-rules.pro:proguard-rules.pro
+# Project target.
+#
+target=android-23
+android.library=true
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">Android SDK</string>
+
+</resources>
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/ActionArgs.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import com.leanplum.internal.ActionArg;
+import com.leanplum.internal.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents arguments for a message or action.
+ *
+ * @author Andrew First
+ */
+public class ActionArgs {
+  private List<ActionArg<?>> args = new ArrayList<>();
+
+  /**
+   * Adds a basic argument of type T.
+   *
+   * @param <T> Type of the argument. Can be Boolean, Byte, Short, Integer, Long, Float, Double,
+   * Character, String, List, or Map.
+   * @param name The name of the argument.
+   * @param defaultValue The default value of the argument.
+   */
+  public <T> ActionArgs with(String name, T defaultValue) {
+    if (name == null) {
+      Log.e("with - Invalid name parameter provided.");
+      return this;
+    }
+    args.add(ActionArg.argNamed(name, defaultValue));
+    return this;
+  }
+
+  /**
+   * Adds a color argument with an integer value.
+   *
+   * @param name The name of the argument.
+   * @param defaultValue The integer value representing the color.
+   */
+  public ActionArgs withColor(String name, int defaultValue) {
+    if (name == null) {
+      Log.e("withColor - Invalid name parameter provided.");
+      return this;
+    }
+    args.add(ActionArg.colorArgNamed(name, defaultValue));
+    return this;
+  }
+
+  /**
+   * Adds a file argument.
+   *
+   * @param name The name of the argument.
+   * @param defaultFilename The path of the default file value. Use null to indicate no default
+   * value.
+   */
+  public ActionArgs withFile(String name, String defaultFilename) {
+    if (name == null) {
+      Log.e("withFile - Invalid name parameter provided.");
+      return this;
+    }
+    args.add(ActionArg.fileArgNamed(name, defaultFilename));
+    return this;
+  }
+
+  /**
+   * Adds an asset argument. Same as {@link ActionArgs#withFile} except that the filename is
+   * relative to the assets directory.
+   *
+   * @param name The name of the argument.
+   * @param defaultFilename The path of the default file value relative to the assets directory. Use
+   * null to indicate no default value.
+   */
+  public ActionArgs withAsset(String name, String defaultFilename) {
+    if (name == null) {
+      Log.e("withAsset - Invalid name parameter provided.");
+      return this;
+    }
+    args.add(ActionArg.assetArgNamed(name, defaultFilename));
+    return this;
+  }
+
+  /**
+   * Adds an action argument.
+   *
+   * @param name The name of the argument.
+   * @param defaultValue The default action name. Use null to indicate no action.
+   */
+  public ActionArgs withAction(String name, String defaultValue) {
+    if (name == null) {
+      Log.e("withAction - Invalid name parameter provided.");
+      return this;
+    }
+    args.add(ActionArg.actionArgNamed(name, defaultValue));
+    return this;
+  }
+
+  List<ActionArg<?>> getValue() {
+    return args;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/ActionContext.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+import com.leanplum.internal.ActionManager;
+import com.leanplum.internal.BaseActionContext;
+import com.leanplum.internal.CollectionUtil;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.FileManager;
+import com.leanplum.internal.JsonConverter;
+import com.leanplum.internal.LeanplumInternal;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+import com.leanplum.internal.VarCache;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The context in which an action or message is executed.
+ *
+ * @author Andrew First
+ */
+public class ActionContext extends BaseActionContext implements Comparable<ActionContext> {
+  private final String name;
+  private ActionContext parentContext;
+  private final int contentVersion;
+  private String key;
+  private boolean preventRealtimeUpdating = false;
+  private ContextualValues contextualValues;
+
+  public static class ContextualValues {
+    /**
+     * Parameters from the triggering event or state.
+     */
+    public Map<String, ?> parameters;
+
+    /**
+     * Arguments from the triggering event or state.
+     */
+    public Map<String, Object> arguments;
+
+    /**
+     * The previous user attribute value.
+     */
+    public Object previousAttributeValue;
+
+    /**
+     * The current user attribute value.
+     */
+    public Object attributeValue;
+  }
+
+  public ActionContext(String name, Map<String, Object> args, String messageId) {
+    this(name, args, messageId, null, Constants.Messaging.DEFAULT_PRIORITY);
+  }
+
+  public ActionContext(String name, Map<String, Object> args, final String messageId,
+      final String originalMessageId, int priority) {
+    super(messageId, originalMessageId);
+    this.name = name;
+    this.args = args;
+    this.contentVersion = VarCache.contentVersion();
+    this.priority = priority;
+  }
+
+  public void preventRealtimeUpdating() {
+    preventRealtimeUpdating = true;
+  }
+
+  public void setContextualValues(ContextualValues values) {
+    contextualValues = values;
+  }
+
+  public ContextualValues getContextualValues() {
+    return contextualValues;
+  }
+
+  private static Map<String, Object> getDefinition(String name) {
+    Map<String, Object> definition = CollectionUtil.uncheckedCast(
+        VarCache.actionDefinitions().get(name));
+    if (definition == null) {
+      return new HashMap<>();
+    }
+    return definition;
+  }
+
+  private Map<String, Object> getDefinition() {
+    return getDefinition(name);
+  }
+
+  private Map<String, Object> defaultValues() {
+    Map<String, Object> values = CollectionUtil.uncheckedCast(getDefinition().get("values"));
+    if (values == null) {
+      return new HashMap<>();
+    }
+    return values;
+  }
+
+  private Map<String, String> kinds() {
+    Map<String, String> kinds = CollectionUtil.uncheckedCast(getDefinition().get("kinds"));
+    if (kinds == null) {
+      return new HashMap<>();
+    }
+    return kinds;
+  }
+
+  public void update() {
+    this.updateArgs(args, "", defaultValues());
+  }
+
+  @SuppressWarnings("unchecked")
+  private void updateArgs(Map<String, Object> args,
+      String prefix, Map<String, Object> defaultValues) {
+    Map<String, String> kinds = kinds();
+    for (Map.Entry<String, Object> entry : args.entrySet()) {
+      String arg = entry.getKey();
+      Object value = entry.getValue();
+      Object defaultValue = defaultValues != null ? defaultValues.get(arg) : null;
+      String kind = kinds.get(prefix + arg);
+      if ((kind == null || !kind.equals(Constants.Kinds.ACTION)) && value instanceof Map &&
+          !((Map<String, ?>) value).containsKey(Constants.Values.ACTION_ARG)) {
+        Map<String, Object> defaultValueMap = (defaultValue instanceof Map) ?
+            (Map<String, Object>) defaultValue : null;
+        this.updateArgs((Map<String, Object>) value, prefix + arg + ".", defaultValueMap);
+      } else {
+        if (kind != null && kind.equals(Constants.Kinds.FILE) ||
+            arg.contains(Constants.Values.FILE_PREFIX)) {
+          FileManager.maybeDownloadFile(false, value.toString(),
+              defaultValue != null ? defaultValue.toString() : null, null, null);
+
+          // Need to check for null because server actions like push notifications aren't
+          // defined in the SDK, and so there's no associated metadata.
+        } else if (kind == null || kind.equals(Constants.Kinds.ACTION)) {
+          Object actionArgsObj = objectNamed(prefix + arg);
+          if (!(actionArgsObj instanceof Map)) {
+            continue;
+          }
+          Map<String, Object> actionArgs = (Map<String, Object>) actionArgsObj;
+          ActionContext context = new ActionContext(
+              (String) actionArgs.get(Constants.Values.ACTION_ARG),
+              actionArgs, messageId);
+          context.update();
+        }
+      }
+    }
+  }
+
+  public String actionName() {
+    return name;
+  }
+
+  public <T> T objectNamed(String name) {
+    if (TextUtils.isEmpty(name)) {
+      Log.e("objectNamed - Invalid name parameter provided.");
+      return null;
+    }
+    try {
+      if (!preventRealtimeUpdating && VarCache.contentVersion() > contentVersion) {
+        ActionContext parent = parentContext;
+        if (parent != null) {
+          args = parent.getChildArgs(key);
+        } else if (messageId != null) {
+          // This is sort of a best effort to display the most recent version of the message, if
+          // this happens to be null, it probably means that it got changed somehow in between the
+          // time when it was activated and displayed (e.g. by forceContentUpdate), in which case
+          // we just ignore it and display the latest stable version.
+          Map<String, Object> message = CollectionUtil.uncheckedCast(VarCache.messages().get
+              (messageId));
+          if (message != null) {
+            args = CollectionUtil.uncheckedCast(message.get(Constants.Keys.VARS));
+          }
+        }
+      }
+      return VarCache.getMergedValueFromComponentArray(
+          VarCache.getNameComponents(name), args);
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return null;
+    }
+  }
+
+  public String stringNamed(String name) {
+    if (TextUtils.isEmpty(name)) {
+      Log.e("stringNamed - Invalid name parameter provided.");
+      return null;
+    }
+    Object object = objectNamed(name);
+    if (object == null) {
+      return null;
+    }
+    try {
+      return fillTemplate(object.toString());
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return object.toString();
+    }
+  }
+
+  private String fillTemplate(String value) {
+    if (contextualValues == null || value == null || !value.contains("##")) {
+      return value;
+    }
+    if (contextualValues.parameters != null) {
+      Map<String, ?> parameters = contextualValues.parameters;
+      for (Map.Entry<String, ?> entry : parameters.entrySet()) {
+        String placeholder = "##Parameter " + entry.getKey() + "##";
+        value = value.replace(placeholder, "" + entry.getValue());
+      }
+    }
+    if (contextualValues.previousAttributeValue != null) {
+      value = value.replace("##Previous Value##",
+          contextualValues.previousAttributeValue.toString());
+    }
+    if (contextualValues.attributeValue != null) {
+      value = value.replace("##Value##", contextualValues.attributeValue.toString());
+    }
+    return value;
+  }
+
+  private String getDefaultValue(String name) {
+    String[] components = name.split("\\.");
+    Map<String, Object> defaultValues = defaultValues();
+    for (int i = 0; i < components.length; i++) {
+      if (defaultValues == null) {
+        return null;
+      }
+      if (i == components.length - 1) {
+        Object value = defaultValues.get(components[i]);
+        return value == null ? null : value.toString();
+      }
+      defaultValues = CollectionUtil.uncheckedCast(defaultValues.get(components[i]));
+    }
+    return null;
+  }
+
+  public InputStream streamNamed(String name) {
+    try {
+      if (TextUtils.isEmpty(name)) {
+        Log.e("streamNamed - Invalid name parameter provided.");
+        return null;
+      }
+      String stringValue = stringNamed(name);
+      String defaultValue = getDefaultValue(name);
+      if ((stringValue == null || stringValue.length() == 0) &&
+          (defaultValue == null || defaultValue.length() == 0)) {
+        return null;
+      }
+      InputStream stream = FileManager.stream(false, null, null,
+          FileManager.fileValue(stringValue, defaultValue, null), defaultValue, null);
+      if (stream == null) {
+        Log.e("Could not open stream named " + name);
+      }
+      return stream;
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return null;
+    }
+  }
+
+  public boolean booleanNamed(String name) {
+    if (TextUtils.isEmpty(name)) {
+      Log.e("booleanNamed - Invalid name parameter provided.");
+      return false;
+    }
+    Object object = objectNamed(name);
+    try {
+      if (object == null) {
+        return false;
+      } else if (object instanceof Boolean) {
+        return (Boolean) object;
+      }
+      return convertToBoolean(object.toString());
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return false;
+    }
+  }
+
+  /**
+   * In contrast to Boolean.valueOf this function also converts 1, yes or similar string values
+   * correctly to Boolean, e.g.: "1", "yes", "true", "on" --> true; "0", "no", "false", "off" -->
+   * false; else null.
+   *
+   * @param value the text to convert to Boolean.
+   * @return Boolean
+   */
+  private static boolean convertToBoolean(String value) {
+    return "1".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value) ||
+        "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value);
+  }
+
+  public Number numberNamed(String name) {
+    if (TextUtils.isEmpty(name)) {
+      Log.e("numberNamed - Invalid name parameter provided.");
+      return null;
+    }
+    Object object = objectNamed(name);
+    try {
+      if (object == null || TextUtils.isEmpty(object.toString())) {
+        return 0.0;
+      }
+      if (object instanceof Number) {
+        return (Number) object;
+      }
+      return Double.valueOf(object.toString());
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return 0.0;
+    }
+  }
+
+  private Map<String, Object> getChildArgs(String name) {
+    Object actionArgsObj = objectNamed(name);
+    if (!(actionArgsObj instanceof Map)) {
+      return null;
+    }
+    Map<String, Object> actionArgs = CollectionUtil.uncheckedCast(actionArgsObj);
+    Map<String, Object> defaultArgs = CollectionUtil.uncheckedCast(getDefinition(
+        (String) actionArgs.get(Constants.Values.ACTION_ARG)).get("values"));
+    actionArgs = CollectionUtil.uncheckedCast(VarCache.mergeHelper(defaultArgs, actionArgs));
+    return actionArgs;
+  }
+
+  public void runActionNamed(String name) {
+    if (TextUtils.isEmpty(name)) {
+      Log.e("runActionNamed - Invalid name parameter provided.");
+      return;
+    }
+    Map<String, Object> args = getChildArgs(name);
+    if (args == null) {
+      return;
+    }
+
+    // Checks if action "Chain to Existing Message" started.
+    if (!isChainToExistingMessageStarted(args, name)) {
+      // Try to start action "Chain to a new Message".
+      Object messageAction = args.get(Constants.Values.ACTION_ARG);
+      if (messageAction != null) {
+        createActionContextForMessageId(messageAction.toString(), args, messageId, name);
+      }
+    }
+  }
+
+  /**
+   * Return true if here was an action for this message and we started it.
+   */
+  private boolean createActionContextForMessageId(String messageAction, Map<String, Object>
+      messageArgs, String messageId, String name) {
+    try {
+      ActionContext actionContext = new ActionContext(messageAction,
+          messageArgs, messageId);
+      actionContext.contextualValues = contextualValues;
+      actionContext.preventRealtimeUpdating = preventRealtimeUpdating;
+      actionContext.isRooted = isRooted;
+      actionContext.parentContext = this;
+      actionContext.key = name;
+      LeanplumInternal.triggerAction(actionContext);
+      return true;
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+    return false;
+  }
+
+  /**
+   * Return true if here was action "Chain to Existing Message" and we started it.
+   */
+  private boolean isChainToExistingMessageStarted(Map<String, Object> args, String name) {
+    if (args == null) {
+      return false;
+    }
+
+    String messageId = (String) args.get(Constants.Values.CHAIN_MESSAGE_ARG);
+    Object actionType = args.get(Constants.Values.ACTION_ARG);
+    if (messageId != null && Constants.Values.CHAIN_MESSAGE_ACTION_NAME.equals(actionType)) {
+      Map<String, Object> messages = VarCache.messages();
+      if (messages != null && messages.containsKey(messageId)) {
+        Map<String, Object> message = CollectionUtil.uncheckedCast(messages.get(messageId));
+        if (message != null) {
+          Map<String, Object> messageArgs = CollectionUtil.uncheckedCast(
+              message.get(Constants.Keys.VARS));
+          Object messageAction = message.get("action");
+          return messageAction != null && createActionContextForMessageId(messageAction.toString(),
+              messageArgs, messageId, name);
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Prefix given event with all parent actionContext names to while filtering out the string
+   * "action" (used in ExperimentVariable names but filtered out from event names).
+   *
+   * @param eventName Current event.
+   * @return Prefixed event name with all parent actions.
+   */
+  private String eventWithParentEventNames(String eventName) {
+    StringBuilder fullEventName = new StringBuilder();
+    ActionContext context = this;
+    List<ActionContext> parents = new ArrayList<>();
+    while (context.parentContext != null) {
+      parents.add(context);
+      context = context.parentContext;
+    }
+    for (int i = parents.size() - 1; i >= -1; i--) {
+      if (fullEventName.length() > 0) {
+        fullEventName.append(' ');
+      }
+      String actionName;
+      if (i > -1) {
+        actionName = parents.get(i).key;
+      } else {
+        actionName = eventName;
+      }
+      if (actionName == null) {
+        fullEventName = new StringBuilder("");
+        break;
+      }
+      actionName = actionName.replace(" action", "");
+      fullEventName.append(actionName);
+    }
+
+    return fullEventName.toString();
+  }
+
+  /**
+   * Run the action with the given variable name, and track a message event with the name.
+   *
+   * @param name Action variable name to run.
+   */
+  public void runTrackedActionNamed(String name) {
+    try {
+      if (!Constants.isNoop() && messageId != null && isRooted) {
+        if (TextUtils.isEmpty(name)) {
+          Log.e("runTrackedActionNamed - Invalid name parameter provided.");
+          return;
+        }
+        trackMessageEvent(name, 0.0, null, null);
+      }
+      runActionNamed(name);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Track a message event with the given parameters. Any parent event names will be prepended to
+   * given event name.
+   *
+   * @param event Name of event.
+   * @param value Value for event.
+   * @param info Info for event.
+   * @param params Dictionary of params for event.
+   */
+  public void trackMessageEvent(String event, double value, String info,
+      Map<String, Object> params) {
+    try {
+      if (!Constants.isNoop() && this.messageId != null) {
+        if (TextUtils.isEmpty(event)) {
+          Log.e("trackMessageEvent - Invalid event parameter provided.");
+          return;
+        }
+
+        event = eventWithParentEventNames(event);
+        if (TextUtils.isEmpty(event)) {
+          Log.e("trackMessageEvent - Failed to generate parent action names.");
+          return;
+        }
+
+        Map<String, String> requestArgs = new HashMap<>();
+        requestArgs.put(Constants.Params.MESSAGE_ID, messageId);
+        LeanplumInternal.track(event, value, info, params, requestArgs);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  public void track(String event, double value, Map<String, Object> params) {
+    try {
+      if (!Constants.isNoop() && this.messageId != null) {
+        if (TextUtils.isEmpty(event)) {
+          Log.e("track - Invalid event parameter provided.");
+          return;
+        }
+        Map<String, String> requestArgs = new HashMap<>();
+        requestArgs.put(Constants.Params.MESSAGE_ID, messageId);
+        LeanplumInternal.track(event, value, null, params, requestArgs);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  public void muteFutureMessagesOfSameKind() {
+    try {
+      ActionManager.getInstance().muteFutureMessagesOfKind(messageId);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  public int compareTo(@NonNull ActionContext other) {
+    return priority - other.getPriority();
+  }
+
+  /**
+   * Returns path to requested file.
+   */
+  public static String filePath(String stringValue) {
+    return FileManager.fileValue(stringValue);
+  }
+
+  public static JSONObject mapToJsonObject(Map<String, ?> map) throws JSONException {
+    return JsonConverter.mapToJsonObject(map);
+  }
+
+  public static <T> Map<String, T> mapFromJson(JSONObject jsonObject) throws JSONException {
+    return JsonConverter.mapFromJson(jsonObject);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/CacheUpdateBlock.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+/**
+ * Update block that will be triggered on new content.
+ *
+ * @author Ben Marten
+ */
+public interface CacheUpdateBlock {
+  void updateCache();
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/Leanplum.java
@@ -0,0 +1,2049 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+import android.os.AsyncTask;
+import android.support.v4.app.NotificationCompat;
+import android.text.TextUtils;
+
+import com.leanplum.ActionContext.ContextualValues;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.RegisterDeviceCallback;
+import com.leanplum.callbacks.RegisterDeviceFinishedCallback;
+import com.leanplum.callbacks.StartCallback;
+import com.leanplum.callbacks.VariablesChangedCallback;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.FileManager;
+import com.leanplum.internal.JsonConverter;
+import com.leanplum.internal.LeanplumInternal;
+import com.leanplum.internal.LeanplumMessageMatchFilter;
+import com.leanplum.internal.LeanplumUIEditorWrapper;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.OsHandler;
+import com.leanplum.internal.Registration;
+import com.leanplum.internal.Request;
+import com.leanplum.internal.Util;
+import com.leanplum.internal.Util.DeviceIdInfo;
+import com.leanplum.internal.VarCache;
+import com.leanplum.messagetemplates.MessageTemplates;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Leanplum Android SDK.
+ *
+ * @author Andrew First, Ben Marten
+ */
+public class Leanplum {
+  public static final int ACTION_KIND_MESSAGE = 1;
+  public static final int ACTION_KIND_ACTION = 1 << 1;
+
+  /**
+   * Default event name to use for Purchase events.
+   */
+  public static final String PURCHASE_EVENT_NAME = "Purchase";
+
+  private static final ArrayList<StartCallback> startHandlers = new ArrayList<>();
+  private static final ArrayList<VariablesChangedCallback> variablesChangedHandlers =
+      new ArrayList<>();
+  private static final ArrayList<VariablesChangedCallback> noDownloadsHandlers =
+      new ArrayList<>();
+  private static final ArrayList<VariablesChangedCallback> onceNoDownloadsHandlers =
+      new ArrayList<>();
+  private static RegisterDeviceCallback registerDeviceHandler;
+  private static RegisterDeviceFinishedCallback registerDeviceFinishedHandler;
+
+  private static LeanplumDeviceIdMode deviceIdMode = LeanplumDeviceIdMode.MD5_MAC_ADDRESS;
+  private static String customDeviceId;
+  private static boolean userSpecifiedDeviceId;
+  private static boolean initializedMessageTemplates = false;
+  private static boolean locationCollectionEnabled = true;
+
+  private static ScheduledExecutorService heartbeatExecutor;
+  private static final Object heartbeatLock = new Object();
+
+  private static Context context;
+
+  private static Runnable pushStartCallback;
+
+  private Leanplum() {
+  }
+
+  /**
+   * Optional. Sets the API server. The API path is of the form http[s]://hostname/servletName
+   *
+   * @param hostName The name of the API host, such as www.leanplum.com
+   * @param servletName The name of the API servlet, such as api
+   * @param ssl Whether to use SSL
+   */
+  public static void setApiConnectionSettings(String hostName, String servletName, boolean ssl) {
+    if (TextUtils.isEmpty(hostName)) {
+      Log.e("setApiConnectionSettings - Empty hostname parameter provided.");
+      return;
+    }
+    if (TextUtils.isEmpty(servletName)) {
+      Log.e("setApiConnectionSettings - Empty servletName parameter provided.");
+      return;
+    }
+
+    Constants.API_HOST_NAME = hostName;
+    Constants.API_SERVLET = servletName;
+    Constants.API_SSL = ssl;
+  }
+
+  /**
+   * Optional. Sets the socket server path for Development mode. Path is of the form hostName:port
+   *
+   * @param hostName The host name of the socket server.
+   * @param port The port to connect to.
+   */
+  public static void setSocketConnectionSettings(String hostName, int port) {
+    if (TextUtils.isEmpty(hostName)) {
+      Log.e("setSocketConnectionSettings - Empty hostName parameter provided.");
+      return;
+    }
+    if (port < 1 || port > 65535) {
+      Log.e("setSocketConnectionSettings - Invalid port parameter provided.");
+      return;
+    }
+
+    Constants.SOCKET_HOST = hostName;
+    Constants.SOCKET_PORT = port;
+  }
+
+  /**
+   * Optional. By default, Leanplum will hash file variables to determine if they're modified and
+   * need to be uploaded to the server. Use this method to override this setting.
+   *
+   * @param enabled Setting this to false will reduce startup latency in development mode, but it's
+   * possible that Leanplum will always have the most up-to-date versions of your resources.
+   * (Default: true)
+   */
+  public static void setFileHashingEnabledInDevelopmentMode(boolean enabled) {
+    Constants.hashFilesToDetermineModifications = enabled;
+  }
+
+  /**
+   * Optional. Whether to enable file uploading in development mode.
+   *
+   * @param enabled Whether or not files should be uploaded. (Default: true)
+   */
+  public static void setFileUploadingEnabledInDevelopmentMode(boolean enabled) {
+    Constants.enableFileUploadingInDevelopmentMode = enabled;
+  }
+
+  /**
+   * Optional. Enables verbose logging in development mode.
+   */
+  public static void enableVerboseLoggingInDevelopmentMode() {
+    Constants.enableVerboseLoggingInDevelopmentMode = true;
+  }
+
+  /**
+   * Optional. Adjusts the network timeouts. The default timeout is 10 seconds for requests, and 15
+   * seconds for file downloads.
+   */
+  public static void setNetworkTimeout(int seconds, int downloadSeconds) {
+    if (seconds < 0) {
+      Log.e("setNetworkTimeout - Invalid seconds parameter provided.");
+      return;
+    }
+    if (downloadSeconds < 0) {
+      Log.e("setNetworkTimeout - Invalid downloadSeconds parameter provided.");
+      return;
+    }
+
+    Constants.NETWORK_TIMEOUT_SECONDS = seconds;
+    Constants.NETWORK_TIMEOUT_SECONDS_FOR_DOWNLOADS = downloadSeconds;
+  }
+
+  /**
+   * Advanced: Whether new variables can be downloaded mid-session. By default, this is disabled.
+   * Currently, if this is enabled, new variables can only be downloaded if a push notification is
+   * sent while the app is running, and the notification's metadata hasn't be downloaded yet.
+   */
+  public static void setCanDownloadContentMidSessionInProductionMode(boolean value) {
+    Constants.canDownloadContentMidSessionInProduction = value;
+  }
+
+  /**
+   * Must call either this or {@link Leanplum#setAppIdForProductionMode} before issuing any calls to
+   * the API, including start.
+   *
+   * @param appId Your app ID.
+   * @param accessKey Your development key.
+   */
+  public static void setAppIdForDevelopmentMode(String appId, String accessKey) {
+    if (TextUtils.isEmpty(appId)) {
+      Log.e("setAppIdForDevelopmentMode - Empty appId parameter provided.");
+      return;
+    }
+    if (TextUtils.isEmpty(accessKey)) {
+      Log.e("setAppIdForDevelopmentMode - Empty accessKey parameter provided.");
+      return;
+    }
+
+    Constants.isDevelopmentModeEnabled = true;
+    Request.setAppId(appId, accessKey);
+  }
+
+  /**
+   * Must call either this or {@link Leanplum#setAppIdForDevelopmentMode} before issuing any calls
+   * to the API, including start.
+   *
+   * @param appId Your app ID.
+   * @param accessKey Your production key.
+   */
+  public static void setAppIdForProductionMode(String appId, String accessKey) {
+    if (TextUtils.isEmpty(appId)) {
+      Log.e("setAppIdForProductionMode - Empty appId parameter provided.");
+      return;
+    }
+    if (TextUtils.isEmpty(accessKey)) {
+      Log.e("setAppIdForProductionMode - Empty accessKey parameter provided.");
+      return;
+    }
+
+    Constants.isDevelopmentModeEnabled = false;
+    Request.setAppId(appId, accessKey);
+  }
+
+  /**
+   * Enable interface editing via Leanplum.com Visual Editor.
+   */
+  @Deprecated
+  public static void allowInterfaceEditing() {
+    if (Constants.isDevelopmentModeEnabled) {
+      throw new LeanplumException("Leanplum UI Editor has moved to a separate package. " +
+          "Please remove this method call and include this line in your build.gradle: " +
+          "compile 'com.leanplum:UIEditor:+'");
+    }
+  }
+
+  /**
+   * Enable screen tracking.
+   */
+  public static void trackAllAppScreens() {
+    LeanplumInternal.enableAutomaticScreenTracking();
+  }
+
+  /**
+   * Whether screen tracking is enabled or not.
+   *
+   * @return Boolean - true if enabled
+   */
+  public static boolean isScreenTrackingEnabled() {
+    return LeanplumInternal.getIsScreenTrackingEnabled();
+  }
+
+  /**
+   * Whether interface editing is enabled or not.
+   *
+   * @return Boolean - true if enabled
+   */
+  public static boolean isInterfaceEditingEnabled() {
+    return LeanplumUIEditorWrapper.isUIEditorAvailable();
+  }
+
+  /**
+   * Sets the type of device ID to use. Default: {@link LeanplumDeviceIdMode#MD5_MAC_ADDRESS}
+   */
+  public static void setDeviceIdMode(LeanplumDeviceIdMode mode) {
+    if (mode == null) {
+      Log.e("setDeviceIdMode - Invalid mode parameter provided.");
+      return;
+    }
+
+    deviceIdMode = mode;
+    userSpecifiedDeviceId = true;
+  }
+
+  /**
+   * (Advanced) Sets a custom device ID. Normally, you should use setDeviceIdMode to change the type
+   * of device ID provided.
+   */
+  public static void setDeviceId(String deviceId) {
+    if (TextUtils.isEmpty(deviceId)) {
+      Log.w("setDeviceId - Empty deviceId parameter provided.");
+    }
+
+    customDeviceId = deviceId;
+    userSpecifiedDeviceId = true;
+  }
+
+  /**
+   * Sets the application context. This should be the first call to Leanplum.
+   */
+  public static void setApplicationContext(Context context) {
+    if (context == null) {
+      Log.w("setApplicationContext - Null context parameter provided.");
+    }
+
+    Leanplum.context = context;
+  }
+
+  /**
+   * Gets the application context.
+   */
+  public static Context getContext() {
+    if (context == null) {
+      Log.e("Your application context is not set. "
+          + "You should call Leanplum.setApplicationContext(this) or "
+          + "LeanplumActivityHelper.enableLifecycleCallbacks(this) in your application's "
+          + "onCreate method, or have your application extend LeanplumApplication.");
+    }
+    return context;
+  }
+
+  /**
+   * Called when the device needs to be registered in development mode.
+   */
+  @Deprecated
+  public static void setRegisterDeviceHandler(RegisterDeviceCallback handler,
+      RegisterDeviceFinishedCallback finishHandler) {
+    if (handler == null && finishHandler == null) {
+      Log.w("setRegisterDeviceHandler - Invalid handler parameter provided.");
+    }
+
+    registerDeviceHandler = handler;
+    registerDeviceFinishedHandler = finishHandler;
+  }
+
+  /**
+   * Syncs resources between Leanplum and the current app. You should only call this once, and
+   * before {@link Leanplum#start}. syncResourcesAsync should be used instead unless file variables
+   * need to be defined early
+   */
+  public static void syncResources() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    try {
+      FileManager.enableResourceSyncing(null, null, false);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Syncs resources between Leanplum and the current app. You should only call this once, and
+   * before {@link Leanplum#start}.
+   */
+  public static void syncResourcesAsync() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    try {
+      FileManager.enableResourceSyncing(null, null, true);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Syncs resources between Leanplum and the current app. You should only call this once, and
+   * before {@link Leanplum#start}. syncResourcesAsync should be used instead unless file variables
+   * need to be defined early
+   *
+   * @param patternsToInclude Limit paths to only those matching at least one pattern in this list.
+   * Supply null to indicate no inclusion patterns. Paths start with the folder name within the res
+   * folder, e.g. "layout/main.xml".
+   * @param patternsToExclude Exclude paths matching at least one of these patterns. Supply null to
+   * indicate no exclusion patterns.
+   */
+  public static void syncResources(
+      List<String> patternsToInclude,
+      List<String> patternsToExclude) {
+    try {
+      FileManager.enableResourceSyncing(patternsToInclude, patternsToExclude, false);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Syncs resources between Leanplum and the current app. You should only call this once, and
+   * before {@link Leanplum#start}. syncResourcesAsync should be used instead unless file variables
+   * need to be defined early
+   *
+   * @param patternsToInclude Limit paths to only those matching at least one pattern in this list.
+   * Supply null to indicate no inclusion patterns. Paths start with the folder name within the res
+   * folder, e.g. "layout/main.xml".
+   * @param patternsToExclude Exclude paths matching at least one of these patterns. Supply null to
+   * indicate no exclusion patterns.
+   */
+  public static void syncResourcesAsync(
+      List<String> patternsToInclude,
+      List<String> patternsToExclude) {
+    try {
+      FileManager.enableResourceSyncing(patternsToInclude, patternsToExclude, true);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Returns true if resource syncing is enabled. Resource syncing may not be fully initialized.
+   */
+  public static boolean isResourceSyncingEnabled() {
+    return FileManager.isResourceSyncingEnabled();
+  }
+
+  /**
+   * Call this when your application starts. This will initiate a call to Leanplum's servers to get
+   * the values of the variables used in your app.
+   */
+  public static void start(Context context) {
+    start(context, null, null, null, null);
+  }
+
+  /**
+   * Call this when your application starts. This will initiate a call to Leanplum's servers to get
+   * the values of the variables used in your app.
+   */
+  public static void start(Context context, StartCallback callback) {
+    start(context, null, null, callback, null);
+  }
+
+  /**
+   * Call this when your application starts. This will initiate a call to Leanplum's servers to get
+   * the values of the variables used in your app.
+   */
+  public static void start(Context context, Map<String, ?> userAttributes) {
+    start(context, null, userAttributes, null, null);
+  }
+
+  /**
+   * Call this when your application starts. This will initiate a call to Leanplum's servers to get
+   * the values of the variables used in your app.
+   */
+  public static void start(Context context, String userId) {
+    start(context, userId, null, null, null);
+  }
+
+  /**
+   * Call this when your application starts. This will initiate a call to Leanplum's servers to get
+   * the values of the variables used in your app.
+   */
+  public static void start(Context context, String userId, StartCallback callback) {
+    start(context, userId, null, callback, null);
+  }
+
+  /**
+   * Call this when your application starts. This will initiate a call to Leanplum's servers to get
+   * the values of the variables used in your app.
+   */
+  public static void start(Context context, String userId, Map<String, ?> userAttributes) {
+    start(context, userId, userAttributes, null, null);
+  }
+
+  /**
+   * Call this when your application starts. This will initiate a call to Leanplum's servers to get
+   * the values of the variables used in your app.
+   */
+  public static synchronized void start(final Context context, String userId,
+      Map<String, ?> attributes, StartCallback response) {
+    start(context, userId, attributes, response, null);
+  }
+
+  static synchronized void start(final Context context, final String userId,
+      final Map<String, ?> attributes, StartCallback response, final Boolean isBackground) {
+    try {
+      OsHandler.getInstance();
+
+      if (context instanceof Activity) {
+        LeanplumActivityHelper.currentActivity = (Activity) context;
+      }
+
+      // Detect if app is in background automatically if isBackground is not set.
+      final boolean actuallyInBackground;
+      if (isBackground == null) {
+        actuallyInBackground = LeanplumActivityHelper.currentActivity == null ||
+            LeanplumActivityHelper.isActivityPaused();
+      } else {
+        actuallyInBackground = isBackground;
+      }
+
+      if (Constants.isNoop()) {
+        LeanplumInternal.setHasStarted(true);
+        LeanplumInternal.setStartSuccessful(true);
+        triggerStartResponse(true);
+        triggerVariablesChanged();
+        triggerVariablesChangedAndNoDownloadsPending();
+        VarCache.applyVariableDiffs(
+            new HashMap<String, Object>(),
+            new HashMap<String, Object>(),
+            VarCache.getUpdateRuleDiffs(),
+            VarCache.getEventRuleDiffs(),
+            new HashMap<String, Object>(),
+            new ArrayList<Map<String, Object>>());
+        LeanplumInbox.getInstance().update(new HashMap<String, LeanplumInboxMessage>(), 0, false);
+        return;
+      }
+
+      if (response != null) {
+        addStartResponseHandler(response);
+      }
+
+      if (context != null) {
+        Leanplum.setApplicationContext(context.getApplicationContext());
+      }
+
+      if (LeanplumInternal.hasCalledStart()) {
+        if (!actuallyInBackground && LeanplumInternal.hasStartedInBackground()) {
+          // Move to foreground.
+          LeanplumInternal.setStartedInBackground(false);
+          LeanplumInternal.moveToForeground();
+        } else {
+          Log.i("Already called start");
+        }
+        return;
+      }
+
+      initializedMessageTemplates = true;
+      MessageTemplates.register(Leanplum.getContext());
+
+      LeanplumInternal.setStartedInBackground(actuallyInBackground);
+
+      final Map<String, ?> validAttributes = LeanplumInternal.validateAttributes(attributes,
+          "userAttributes", true);
+      LeanplumInternal.setCalledStart(true);
+
+      if (validAttributes != null) {
+        LeanplumInternal.getUserAttributeChanges().add(validAttributes);
+      }
+
+      Request.loadToken();
+      VarCache.setSilent(true);
+      VarCache.loadDiffs();
+      VarCache.setSilent(false);
+      LeanplumInbox.getInstance().load();
+
+      // Setup class members.
+      VarCache.onUpdate(new CacheUpdateBlock() {
+        @Override
+        public void updateCache() {
+          triggerVariablesChanged();
+          if (Request.numPendingDownloads() == 0) {
+            triggerVariablesChangedAndNoDownloadsPending();
+          }
+        }
+      });
+      Request.onNoPendingDownloads(new Request.NoPendingDownloadsCallback() {
+        @Override
+        public void noPendingDownloads() {
+          triggerVariablesChangedAndNoDownloadsPending();
+        }
+      });
+
+      // Reduce latency by running the rest of the start call in a background thread.
+      Util.executeAsyncTask(new AsyncTask<Void, Void, Void>() {
+        @Override
+        protected Void doInBackground(Void... params) {
+          try {
+            startHelper(userId, validAttributes, actuallyInBackground);
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+          return null;
+        }
+      });
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  private static void startHelper(
+      String userId, final Map<String, ?> attributes, final boolean isBackground) {
+    LeanplumPushService.onStart();
+
+    Boolean limitAdTracking = null;
+    String deviceId = Request.deviceId();
+    if (deviceId == null) {
+      if (!userSpecifiedDeviceId && Constants.defaultDeviceId != null) {
+        deviceId = Constants.defaultDeviceId;
+      } else if (customDeviceId != null) {
+        deviceId = customDeviceId;
+      } else {
+        DeviceIdInfo deviceIdInfo = Util.getDeviceId(deviceIdMode);
+        deviceId = deviceIdInfo.id;
+        limitAdTracking = deviceIdInfo.limitAdTracking;
+      }
+      Request.setDeviceId(deviceId);
+    }
+
+    if (userId == null) {
+      userId = Request.userId();
+      if (userId == null) {
+        userId = Request.deviceId();
+      }
+    }
+    Request.setUserId(userId);
+
+    // Setup parameters.
+    String versionName = Util.getVersionName();
+    if (versionName == null) {
+      versionName = "";
+    }
+
+    TimeZone localTimeZone = TimeZone.getDefault();
+    Date now = new Date();
+    int timezoneOffsetSeconds = localTimeZone.getOffset(now.getTime()) / 1000;
+
+    HashMap<String, Object> params = new HashMap<>();
+    params.put(Constants.Params.INCLUDE_DEFAULTS, Boolean.toString(false));
+    if (isBackground) {
+      params.put(Constants.Params.BACKGROUND, Boolean.toString(true));
+    }
+    params.put(Constants.Params.VERSION_NAME, versionName);
+    params.put(Constants.Params.DEVICE_NAME, Util.getDeviceName());
+    params.put(Constants.Params.DEVICE_MODEL, Util.getDeviceModel());
+    params.put(Constants.Params.DEVICE_SYSTEM_NAME, Util.getSystemName());
+    params.put(Constants.Params.DEVICE_SYSTEM_VERSION, Util.getSystemVersion());
+    params.put(Constants.Keys.TIMEZONE, localTimeZone.getID());
+    params.put(Constants.Keys.TIMEZONE_OFFSET_SECONDS, Integer.toString(timezoneOffsetSeconds));
+    params.put(Constants.Keys.LOCALE, Util.getLocale());
+    params.put(Constants.Keys.COUNTRY, Constants.Values.DETECT);
+    params.put(Constants.Keys.REGION, Constants.Values.DETECT);
+    params.put(Constants.Keys.CITY, Constants.Values.DETECT);
+    params.put(Constants.Keys.LOCATION, Constants.Values.DETECT);
+    if (Boolean.TRUE.equals(limitAdTracking)) {
+      params.put(Constants.Params.LIMIT_TRACKING, limitAdTracking.toString());
+    }
+    if (attributes != null) {
+      params.put(Constants.Params.USER_ATTRIBUTES, JsonConverter.toJson(attributes));
+    }
+    if (Constants.isDevelopmentModeEnabled) {
+      params.put(Constants.Params.DEV_MODE, Boolean.TRUE.toString());
+    }
+
+    // Get the current inbox messages on the device.
+    params.put(Constants.Params.INBOX_MESSAGES, LeanplumInbox.getInstance().messagesIds());
+
+    Util.initializePreLeanplumInstall(params);
+
+    // Issue start API call.
+    Request req = Request.post(Constants.Methods.START, params);
+    req.onApiResponse(new Request.ApiResponseCallback() {
+      @Override
+      public void response(List<Map<String, Object>> requests, JSONObject response) {
+        Leanplum.handleApiResponse(response, requests);
+      }
+    });
+
+    if (isBackground) {
+      req.sendEventually();
+    } else {
+      req.sendIfConnected();
+    }
+
+    LeanplumInternal.triggerStartIssued();
+  }
+
+  private static void handleApiResponse(JSONObject response, List<Map<String, Object>> requests) {
+    boolean hasStartResponse = false;
+    JSONObject lastStartResponse = null;
+
+    // Find and handle the last start response.
+    try {
+      int numResponses = Request.numResponses(response);
+      for (int i = requests.size() - 1; i >= 0; i--) {
+        Map<String, Object> request = requests.get(i);
+        if (Constants.Methods.START.equals(request.get(Constants.Params.ACTION))) {
+          if (i < numResponses) {
+            lastStartResponse = Request.getResponseAt(response, i);
+          }
+          hasStartResponse = true;
+          break;
+        }
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+
+    if (hasStartResponse) {
+      if (!LeanplumInternal.hasStarted()) {
+        Leanplum.handleStartResponse(lastStartResponse);
+      }
+    }
+  }
+
+  private static void handleStartResponse(JSONObject response) {
+    boolean success = Request.isResponseSuccess(response);
+    if (!success) {
+      try {
+        LeanplumInternal.setHasStarted(true);
+        LeanplumInternal.setStartSuccessful(false);
+
+        // Load the variables that were stored on the device from the last session.
+        VarCache.loadDiffs();
+
+        triggerStartResponse(false);
+      } catch (Throwable t) {
+        Util.handleException(t);
+      }
+    } else {
+      try {
+        LeanplumInternal.setHasStarted(true);
+        LeanplumInternal.setStartSuccessful(true);
+
+        JSONObject values = response.optJSONObject(Constants.Keys.VARS);
+        if (values == null) {
+          Log.e("No variable values were received from the server. " +
+              "Please contact us to investigate.");
+        }
+
+        JSONObject messages = response.optJSONObject(Constants.Keys.MESSAGES);
+        if (messages == null) {
+          Log.d("No messages received from the server.");
+        }
+
+        JSONObject regions = response.optJSONObject(Constants.Keys.REGIONS);
+        if (regions == null) {
+          Log.d("No regions received from the server.");
+        }
+
+        JSONArray variants = response.optJSONArray(Constants.Keys.VARIANTS);
+        if (variants == null) {
+          Log.d("No variants received from the server.");
+        }
+
+        String token = response.optString(Constants.Keys.TOKEN, null);
+        Request.setToken(token);
+        Request.saveToken();
+
+        applyContentInResponse(response, true);
+
+        VarCache.saveUserAttributes();
+        triggerStartResponse(true);
+
+        if (response.optBoolean(Constants.Keys.SYNC_INBOX, false)) {
+          LeanplumInbox.getInstance().downloadMessages();
+        }
+
+        if (response.optBoolean(Constants.Keys.LOGGING_ENABLED, false)) {
+          Constants.loggingEnabled = true;
+        }
+
+        // Allow bidirectional realtime variable updates.
+        if (Constants.isDevelopmentModeEnabled) {
+
+          final Context currentContext = (
+              LeanplumActivityHelper.currentActivity != context &&
+                  LeanplumActivityHelper.currentActivity != null) ?
+              LeanplumActivityHelper.currentActivity
+              : context;
+
+          // Register device.
+          if (!response.optBoolean(
+              Constants.Keys.IS_REGISTERED) && registerDeviceHandler != null) {
+            registerDeviceHandler.setResponseHandler(new RegisterDeviceCallback.EmailCallback() {
+              @Override
+              public void onResponse(String email) {
+                try {
+                  if (email != null) {
+                    Registration.registerDevice(email, new StartCallback() {
+                      @Override
+                      public void onResponse(boolean success) {
+                        if (registerDeviceFinishedHandler != null) {
+                          registerDeviceFinishedHandler.setSuccess(success);
+                          OsHandler.getInstance().post(registerDeviceFinishedHandler);
+                        }
+                        if (success) {
+                          try {
+                            LeanplumInternal.onHasStartedAndRegisteredAsDeveloper();
+                          } catch (Throwable t) {
+                            Util.handleException(t);
+                          }
+                        }
+                      }
+                    });
+                  }
+                } catch (Throwable t) {
+                  Util.handleException(t);
+                }
+              }
+            });
+            OsHandler.getInstance().post(registerDeviceHandler);
+          }
+
+          // Show device is already registered.
+          if (response.optBoolean(Constants.Keys.IS_REGISTERED_FROM_OTHER_APP)) {
+            OsHandler.getInstance().post(new Runnable() {
+              @Override
+              public void run() {
+                try {
+                  NotificationCompat.Builder mBuilder =
+                      new NotificationCompat.Builder(currentContext)
+                          .setSmallIcon(android.R.drawable.star_on)
+                          .setContentTitle("Leanplum")
+                          .setContentText("Your device is registered.");
+                  mBuilder.setContentIntent(PendingIntent.getActivity(
+                      currentContext.getApplicationContext(), 0, new Intent(), 0));
+                  NotificationManager mNotificationManager =
+                      (NotificationManager) currentContext.getSystemService(
+                          Context.NOTIFICATION_SERVICE);
+                  // mId allows you to update the notification later on.
+                  mNotificationManager.notify(0, mBuilder.build());
+                } catch (Throwable t) {
+                  Log.i("Device is registered.");
+                }
+              }
+            });
+          }
+
+          boolean isRegistered = response.optBoolean(Constants.Keys.IS_REGISTERED);
+
+          // Check for updates.
+          final String latestVersion = response.optString(Constants.Keys.LATEST_VERSION, null);
+          if (isRegistered && latestVersion != null) {
+            Log.i("An update to Leanplum Android SDK, " + latestVersion +
+                ", is available. Go to leanplum.com to download it.");
+          }
+
+          JSONObject valuesFromCode = response.optJSONObject(Constants.Keys.VARS_FROM_CODE);
+          if (valuesFromCode == null) {
+            valuesFromCode = new JSONObject();
+          }
+
+          JSONObject actionDefinitions =
+              response.optJSONObject(Constants.Params.ACTION_DEFINITIONS);
+          if (actionDefinitions == null) {
+            actionDefinitions = new JSONObject();
+          }
+
+          JSONObject fileAttributes = response.optJSONObject(Constants.Params.FILE_ATTRIBUTES);
+          if (fileAttributes == null) {
+            fileAttributes = new JSONObject();
+          }
+
+          VarCache.setDevModeValuesFromServer(
+              JsonConverter.mapFromJson(valuesFromCode),
+              JsonConverter.mapFromJson(fileAttributes),
+              JsonConverter.mapFromJson(actionDefinitions));
+
+          if (isRegistered) {
+            LeanplumInternal.onHasStartedAndRegisteredAsDeveloper();
+          }
+        }
+
+        LeanplumInternal.moveToForeground();
+        startHeartbeat();
+      } catch (Throwable t) {
+        Util.handleException(t);
+      }
+    }
+  }
+
+  /**
+   * Applies the variables, messages, or update rules in a start or getVars response.
+   *
+   * @param response The response containing content.
+   * @param alwaysApply Always apply the content regardless of whether the content changed.
+   */
+  private static void applyContentInResponse(JSONObject response, boolean alwaysApply) {
+    Map<String, Object> values = JsonConverter.mapFromJsonOrDefault(
+        response.optJSONObject(Constants.Keys.VARS));
+    Map<String, Object> messages = JsonConverter.mapFromJsonOrDefault(
+        response.optJSONObject(Constants.Keys.MESSAGES));
+    List<Map<String, Object>> updateRules = JsonConverter.listFromJsonOrDefault(
+        response.optJSONArray(Constants.Keys.UPDATE_RULES));
+    List<Map<String, Object>> eventRules = JsonConverter.listFromJsonOrDefault(
+        response.optJSONArray(Constants.Keys.EVENT_RULES));
+    Map<String, Object> regions = JsonConverter.mapFromJsonOrDefault(
+        response.optJSONObject(Constants.Keys.REGIONS));
+    List<Map<String, Object>> variants = JsonConverter.listFromJsonOrDefault(
+        response.optJSONArray(Constants.Keys.VARIANTS));
+
+    if (alwaysApply
+        || !values.equals(VarCache.getDiffs())
+        || !messages.equals(VarCache.getMessageDiffs())
+        || !updateRules.equals(VarCache.getUpdateRuleDiffs())
+        || !eventRules.equals(VarCache.getEventRuleDiffs())
+        || !regions.equals(VarCache.regions())) {
+      VarCache.applyVariableDiffs(values, messages, updateRules,
+          eventRules, regions, variants);
+    }
+  }
+
+  /**
+   * Used by wrapper SDKs like Unity to override the SDK client name and version.
+   */
+  static void setClient(String client, String sdkVersion, String defaultDeviceId) {
+    Constants.CLIENT = client;
+    Constants.LEANPLUM_VERSION = sdkVersion;
+    Constants.defaultDeviceId = defaultDeviceId;
+  }
+
+  /**
+   * Call this when your activity pauses. This is called from LeanplumActivityHelper.
+   */
+  static void pause() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call pause before calling start");
+      return;
+    }
+    LeanplumInternal.setIsPaused(true);
+
+    if (LeanplumInternal.isPaused()) {
+      pauseInternal();
+    } else {
+      LeanplumInternal.addStartIssuedHandler(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            pauseInternal();
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+        }
+      });
+    }
+  }
+
+  private static void pauseInternal() {
+    Request.post(Constants.Methods.PAUSE_SESSION, null).sendIfConnected();
+    pauseHeartbeat();
+  }
+
+  /**
+   * Call this when your activity resumes. This is called from LeanplumActivityHelper.
+   */
+  static void resume() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call resume before calling start");
+      return;
+    }
+    LeanplumInternal.setIsPaused(false);
+
+    if (LeanplumInternal.issuedStart()) {
+      resumeInternal();
+    } else {
+      LeanplumInternal.addStartIssuedHandler(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            resumeInternal();
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+        }
+      });
+    }
+  }
+
+  private static void resumeInternal() {
+    Request request = Request.post(Constants.Methods.RESUME_SESSION, null);
+    if (LeanplumInternal.hasStartedInBackground()) {
+      LeanplumInternal.setStartedInBackground(false);
+      request.sendIfConnected();
+    } else {
+      request.sendIfDelayed();
+      LeanplumInternal.maybePerformActions("resume", null,
+          LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_ALL, null, null);
+    }
+    resumeHeartbeat();
+  }
+
+  /**
+   * Send a heartbeat every 15 minutes while the app is running.
+   */
+  private static void startHeartbeat() {
+    synchronized (heartbeatLock) {
+      heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
+      heartbeatExecutor.scheduleAtFixedRate(new Runnable() {
+        public void run() {
+          try {
+            Request.post(Constants.Methods.HEARTBEAT, null).sendIfDelayed();
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+        }
+      }, 15, 15, TimeUnit.MINUTES);
+    }
+  }
+
+  private static void pauseHeartbeat() {
+    synchronized (heartbeatLock) {
+      if (heartbeatExecutor != null) {
+        heartbeatExecutor.shutdown();
+      }
+    }
+  }
+
+  private static void resumeHeartbeat() {
+    startHeartbeat();
+  }
+
+  /**
+   * Call this to explicitly end the session. This should not be used in most cases, so we won't
+   * make it public for now.
+   */
+  static void stop() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call stop before calling start");
+      return;
+    }
+
+    if (LeanplumInternal.issuedStart()) {
+      stopInternal();
+    } else {
+      LeanplumInternal.addStartIssuedHandler(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            stopInternal();
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+        }
+      });
+    }
+  }
+
+  private static void stopInternal() {
+    Request.post(Constants.Methods.STOP, null).sendIfConnected();
+  }
+
+  /**
+   * Whether or not Leanplum has finished starting.
+   */
+  public static boolean hasStarted() {
+    return LeanplumInternal.hasStarted();
+  }
+
+  /**
+   * Returns an instance to the singleton Newsfeed object.
+   *
+   * @deprecated use {@link #getInbox} instead
+   */
+  public static Newsfeed newsfeed() {
+    return Newsfeed.getInstance();
+  }
+
+  /**
+   * Returns an instance to the singleton LeanplumInbox object.
+   */
+  public static LeanplumInbox getInbox() {
+    return LeanplumInbox.getInstance();
+  }
+
+  /**
+   * Whether or not Leanplum has finished starting and the device is registered as a developer.
+   */
+  public static boolean hasStartedAndRegisteredAsDeveloper() {
+    return LeanplumInternal.hasStartedAndRegisteredAsDeveloper();
+  }
+
+  /**
+   * Add a callback for when the start call finishes, and variables are returned back from the
+   * server.
+   */
+  public static void addStartResponseHandler(StartCallback handler) {
+    if (handler == null) {
+      Log.e("addStartResponseHandler - Invalid handler parameter provided.");
+      return;
+    }
+
+    if (LeanplumInternal.hasStarted()) {
+      if (LeanplumInternal.isStartSuccessful()) {
+        handler.setSuccess(true);
+      }
+      handler.run();
+    } else {
+      synchronized (startHandlers) {
+        if (startHandlers.indexOf(handler) == -1) {
+          startHandlers.add(handler);
+        }
+      }
+    }
+  }
+
+  /**
+   * Removes a start response callback.
+   */
+  public static void removeStartResponseHandler(StartCallback handler) {
+    if (handler == null) {
+      Log.e("removeStartResponseHandler - Invalid handler parameter provided.");
+      return;
+    }
+
+    synchronized (startHandlers) {
+      startHandlers.remove(handler);
+    }
+  }
+
+  private static void triggerStartResponse(boolean success) {
+    synchronized (startHandlers) {
+      for (StartCallback callback : startHandlers) {
+        callback.setSuccess(success);
+        OsHandler.getInstance().post(callback);
+      }
+      startHandlers.clear();
+    }
+  }
+
+  /**
+   * Add a callback for when the variables receive new values from the server. This will be called
+   * on start, and also later on if the user is in an experiment that can updated in realtime.
+   */
+  public static void addVariablesChangedHandler(VariablesChangedCallback handler) {
+    if (handler == null) {
+      Log.e("addVariablesChangedHandler - Invalid handler parameter provided.");
+      return;
+    }
+
+    synchronized (variablesChangedHandlers) {
+      variablesChangedHandlers.add(handler);
+    }
+    if (VarCache.hasReceivedDiffs()) {
+      handler.variablesChanged();
+    }
+  }
+
+  /**
+   * Removes a variables changed callback.
+   */
+  public static void removeVariablesChangedHandler(VariablesChangedCallback handler) {
+    if (handler == null) {
+      Log.e("removeVariablesChangedHandler - Invalid handler parameter provided.");
+      return;
+    }
+
+    synchronized (variablesChangedHandlers) {
+      variablesChangedHandlers.remove(handler);
+    }
+  }
+
+  private static void triggerVariablesChanged() {
+    synchronized (variablesChangedHandlers) {
+      for (VariablesChangedCallback callback : variablesChangedHandlers) {
+        OsHandler.getInstance().post(callback);
+      }
+    }
+  }
+
+  /**
+   * Add a callback for when no more file downloads are pending (either when no files needed to be
+   * downloaded or all downloads have been completed).
+   */
+  public static void addVariablesChangedAndNoDownloadsPendingHandler(
+      VariablesChangedCallback handler) {
+    if (handler == null) {
+      Log.e("addVariablesChangedAndNoDownloadsPendingHandler - Invalid handler parameter " +
+          "provided.");
+      return;
+    }
+
+    synchronized (noDownloadsHandlers) {
+      noDownloadsHandlers.add(handler);
+    }
+    if (VarCache.hasReceivedDiffs()
+        && Request.numPendingDownloads() == 0) {
+      handler.variablesChanged();
+    }
+  }
+
+  /**
+   * Removes a variables changed and no downloads pending callback.
+   */
+  public static void removeVariablesChangedAndNoDownloadsPendingHandler(
+      VariablesChangedCallback handler) {
+    if (handler == null) {
+      Log.e("removeVariablesChangedAndNoDownloadsPendingHandler - Invalid handler parameter " +
+          "provided.");
+      return;
+    }
+
+    synchronized (noDownloadsHandlers) {
+      noDownloadsHandlers.remove(handler);
+    }
+  }
+
+  /**
+   * Add a callback to call ONCE when no more file downloads are pending (either when no files
+   * needed to be downloaded or all downloads have been completed).
+   */
+  public static void addOnceVariablesChangedAndNoDownloadsPendingHandler(
+      VariablesChangedCallback handler) {
+    if (handler == null) {
+      Log.e("addOnceVariablesChangedAndNoDownloadsPendingHandler - Invalid handler parameter" +
+          " provided.");
+      return;
+    }
+
+    if (VarCache.hasReceivedDiffs()
+        && Request.numPendingDownloads() == 0) {
+      handler.variablesChanged();
+    } else {
+      synchronized (onceNoDownloadsHandlers) {
+        onceNoDownloadsHandlers.add(handler);
+      }
+    }
+  }
+
+  /**
+   * Removes a once variables changed and no downloads pending callback.
+   */
+  public static void removeOnceVariablesChangedAndNoDownloadsPendingHandler(
+      VariablesChangedCallback handler) {
+    if (handler == null) {
+      Log.e("removeOnceVariablesChangedAndNoDownloadsPendingHandler - Invalid handler" +
+          " parameter provided.");
+      return;
+    }
+
+    synchronized (onceNoDownloadsHandlers) {
+      onceNoDownloadsHandlers.remove(handler);
+    }
+  }
+
+  static void triggerVariablesChangedAndNoDownloadsPending() {
+    synchronized (noDownloadsHandlers) {
+      for (VariablesChangedCallback callback : noDownloadsHandlers) {
+        OsHandler.getInstance().post(callback);
+      }
+    }
+    synchronized (onceNoDownloadsHandlers) {
+      for (VariablesChangedCallback callback : onceNoDownloadsHandlers) {
+        OsHandler.getInstance().post(callback);
+      }
+      onceNoDownloadsHandlers.clear();
+    }
+  }
+
+  /**
+   * Defines an action that is used within Leanplum Marketing Automation. Actions can be set up to
+   * get triggered based on app opens, events, and states. Call {@link Leanplum#onAction} to handle
+   * the action.
+   *
+   * @param name The name of the action to register.
+   * @param kind Whether to display the action as a message and/or a regular action.
+   * @param args User-customizable options for the action.
+   */
+  public static void defineAction(String name, int kind, ActionArgs args) {
+    defineAction(name, kind, args, null, null);
+  }
+
+  @Deprecated
+  static void defineAction(String name, int kind, ActionArgs args,
+      Map<String, Object> options) {
+    defineAction(name, kind, args, options, null);
+  }
+
+  /**
+   * Defines an action that is used within Leanplum Marketing Automation. Actions can be set up to
+   * get triggered based on app opens, events, and states.
+   *
+   * @param name The name of the action to register.
+   * @param kind Whether to display the action as a message and/or a regular action.
+   * @param args User-customizable options for the action.
+   * @param responder Called when the action is triggered with a context object containing the
+   * user-specified options.
+   */
+  public static void defineAction(String name, int kind, ActionArgs args,
+      ActionCallback responder) {
+    defineAction(name, kind, args, null, responder);
+  }
+
+  private static void defineAction(String name, int kind, ActionArgs args,
+      Map<String, Object> options, ActionCallback responder) {
+    if (TextUtils.isEmpty(name)) {
+      Log.e("defineAction - Empty name parameter provided.");
+      return;
+    }
+    if (args == null) {
+      Log.e("defineAction - Invalid args parameter provided.");
+      return;
+    }
+
+    try {
+      Context context = Leanplum.getContext();
+      if (!initializedMessageTemplates) {
+        initializedMessageTemplates = true;
+        MessageTemplates.register(context);
+      }
+
+      if (options == null) {
+        options = new HashMap<>();
+      }
+      LeanplumInternal.getActionHandlers().remove(name);
+      VarCache.registerActionDefinition(name, kind, args.getValue(), options);
+      if (responder != null) {
+        onAction(name, responder);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Adds a callback that handles an action with the given name.
+   *
+   * @param actionName The name of the type of action to handle.
+   * @param handler The callback that runs when the action is triggered.
+   */
+  public static void onAction(String actionName, ActionCallback handler) {
+    if (actionName == null) {
+      Log.e("onAction - Invalid actionName parameter provided.");
+      return;
+    }
+    if (handler == null) {
+      Log.e("onAction - Invalid handler parameter provided.");
+      return;
+    }
+
+    List<ActionCallback> handlers = LeanplumInternal.getActionHandlers().get(actionName);
+    if (handlers == null) {
+      handlers = new ArrayList<>();
+      LeanplumInternal.getActionHandlers().put(actionName, handlers);
+    }
+    handlers.add(handler);
+  }
+
+  /**
+   * Updates the user ID and adds or modifies user attributes.
+   */
+  public static void setUserAttributes(final String userId, Map<String, ?> userAttributes) {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call setUserAttributes before calling start");
+      return;
+    }
+    try {
+      final HashMap<String, Object> params = new HashMap<>();
+      if (userId != null) {
+        params.put(Constants.Params.NEW_USER_ID, userId);
+      }
+      if (userAttributes != null) {
+        userAttributes = LeanplumInternal.validateAttributes(userAttributes, "userAttributes",
+            true);
+        params.put(Constants.Params.USER_ATTRIBUTES, JsonConverter.toJson(userAttributes));
+        LeanplumInternal.getUserAttributeChanges().add(userAttributes);
+      }
+
+      if (LeanplumInternal.issuedStart()) {
+        setUserAttributesInternal(userId, params);
+      } else {
+        LeanplumInternal.addStartIssuedHandler(new Runnable() {
+          @Override
+          public void run() {
+            try {
+              setUserAttributesInternal(userId, params);
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+          }
+        });
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  private static void setUserAttributesInternal(String userId,
+      HashMap<String, Object> requestArgs) {
+    Request.post(Constants.Methods.SET_USER_ATTRIBUTES, requestArgs).send();
+    if (userId != null && userId.length() > 0) {
+      Request.setUserId(userId);
+      if (LeanplumInternal.hasStarted()) {
+        VarCache.saveDiffs();
+      }
+    }
+    LeanplumInternal.recordAttributeChanges();
+  }
+
+  /**
+   * Updates the user ID.
+   */
+  public static void setUserId(String userId) {
+    if (userId == null) {
+      Log.e("setUserId - Invalid userId parameter provided.");
+      return;
+    }
+
+    setUserAttributes(userId, null);
+  }
+
+  /**
+   * Adds or modifies user attributes.
+   */
+  public static void setUserAttributes(Map<String, Object> userAttributes) {
+    if (userAttributes == null || userAttributes.isEmpty()) {
+      Log.e("setUserAttributes - Invalid userAttributes parameter provided (null or empty).");
+      return;
+    }
+
+    setUserAttributes(null, userAttributes);
+  }
+
+  /**
+   * Sets the registration ID used for Cloud Messaging.
+   */
+  static void setRegistrationId(final String registrationId) {
+    if (Constants.isNoop()) {
+      return;
+    }
+    pushStartCallback = new Runnable() {
+      @Override
+      public void run() {
+        if (Constants.isNoop()) {
+          return;
+        }
+        try {
+          HashMap<String, Object> params = new HashMap<>();
+          params.put(Constants.Params.DEVICE_PUSH_TOKEN, registrationId);
+          Request.post(Constants.Methods.SET_DEVICE_ATTRIBUTES, params).send();
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+    };
+    LeanplumInternal.addStartIssuedHandler(pushStartCallback);
+  }
+
+  /**
+   * Sets the traffic source info for the current user. Keys in info must be one of: publisherId,
+   * publisherName, publisherSubPublisher, publisherSubSite, publisherSubCampaign,
+   * publisherSubAdGroup, publisherSubAd.
+   */
+  public static void setTrafficSourceInfo(Map<String, String> info) {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call setTrafficSourceInfo before calling start");
+      return;
+    }
+    if (info == null || info.isEmpty()) {
+      Log.e("setTrafficSourceInfo - Invalid info parameter provided (null or empty).");
+      return;
+    }
+
+    try {
+      final HashMap<String, Object> params = new HashMap<>();
+      info = LeanplumInternal.validateAttributes(info, "info", false);
+      params.put(Constants.Params.TRAFFIC_SOURCE, JsonConverter.toJson(info));
+      if (LeanplumInternal.issuedStart()) {
+        setTrafficSourceInfoInternal(params);
+      } else {
+        LeanplumInternal.addStartIssuedHandler(new Runnable() {
+          @Override
+          public void run() {
+            try {
+              setTrafficSourceInfoInternal(params);
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+          }
+        });
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  private static void setTrafficSourceInfoInternal(HashMap<String, Object> params) {
+    Request.post(Constants.Methods.SET_TRAFFIC_SOURCE_INFO, params).send();
+  }
+
+  /**
+   * Logs a particular event in your application. The string can be any value of your choosing, and
+   * will show up in the dashboard.
+   * <p>
+   * <p>To track Purchase events, call {@link Leanplum#trackGooglePlayPurchase} instead for in-app
+   * purchases, or use {@link Leanplum#PURCHASE_EVENT_NAME} as the event name for other types of
+   * purchases.
+   *
+   * @param event Name of the event. Event may be empty for message impression events.
+   * @param value The value of the event. The value is special in that you can use it for targeting
+   * content and messages to users who have a particular lifetime value. For purchase events, the
+   * value is the revenue associated with the purchase.
+   * @param info Basic context associated with the event, such as the item purchased. info is
+   * treated like a default parameter.
+   * @param params Key-value pairs with metrics or data associated with the event. Parameters can be
+   * strings or numbers. You can use up to 200 different parameter names in your app.
+   */
+  public static void track(final String event, double value, String info,
+      Map<String, ?> params) {
+    LeanplumInternal.track(event, value, info, params, null);
+  }
+
+  /**
+   * Tracks an in-app purchase as a Purchase event.
+   *
+   * @param item The name of the item that was purchased.
+   * @param priceMicros The price in micros in the user's local currency.
+   * @param currencyCode The currency code corresponding to the price.
+   * @param purchaseData Purchase data from purchase.getOriginalJson().
+   * @param dataSignature Signature from purchase.getSignature().
+   */
+  public static void trackGooglePlayPurchase(String item, long priceMicros, String currencyCode,
+      String purchaseData, String dataSignature) {
+    trackGooglePlayPurchase(PURCHASE_EVENT_NAME, item, priceMicros, currencyCode, purchaseData,
+        dataSignature, null);
+  }
+
+  /**
+   * Tracks an in-app purchase as a Purchase event.
+   *
+   * @param item The name of the item that was purchased.
+   * @param priceMicros The price in micros in the user's local currency.
+   * @param currencyCode The currency code corresponding to the price.
+   * @param purchaseData Purchase data from purchase.getOriginalJson().
+   * @param dataSignature Signature from purchase.getSignature().
+   * @param params Any additional parameters to track with the event.
+   */
+  public static void trackGooglePlayPurchase(String item, long priceMicros, String currencyCode,
+      String purchaseData, String dataSignature, Map<String, ?> params) {
+    trackGooglePlayPurchase(PURCHASE_EVENT_NAME, item, priceMicros, currencyCode,
+        purchaseData, dataSignature, params);
+  }
+
+  /**
+   * Tracks an in-app purchase.
+   *
+   * @param eventName The name of the event to record the purchase under. Normally, this would be
+   * {@link Leanplum#PURCHASE_EVENT_NAME}.
+   * @param item The name of the item that was purchased.
+   * @param priceMicros The price in micros in the user's local currency.
+   * @param currencyCode The currency code corresponding to the price.
+   * @param purchaseData Purchase data from purchase.getOriginalJson().
+   * @param dataSignature Signature from purchase.getSignature().
+   * @param params Any additional parameters to track with the event.
+   */
+  @SuppressWarnings("SameParameterValue")
+  public static void trackGooglePlayPurchase(String eventName, String item, long priceMicros,
+      String currencyCode, String purchaseData, String dataSignature, Map<String, ?> params) {
+    if (TextUtils.isEmpty(eventName)) {
+      Log.w("trackGooglePlayPurchase - Empty eventName parameter provided.");
+    }
+
+    final Map<String, String> requestArgs = new HashMap<>();
+    requestArgs.put(Constants.Params.GOOGLE_PLAY_PURCHASE_DATA, purchaseData);
+    requestArgs.put(Constants.Params.GOOGLE_PLAY_PURCHASE_DATA_SIGNATURE, dataSignature);
+    requestArgs.put(Constants.Params.IAP_CURRENCY_CODE, currencyCode);
+
+    Map<String, Object> modifiedParams;
+    if (params == null) {
+      modifiedParams = new HashMap<>();
+    } else {
+      modifiedParams = new HashMap<>(params);
+    }
+    modifiedParams.put(Constants.Params.IAP_ITEM, item);
+
+    LeanplumInternal.track(eventName, priceMicros / 1000000.0, null, modifiedParams, requestArgs);
+  }
+
+  /**
+   * Logs a particular event in your application. The string can be any value of your choosing, and
+   * will show up in the dashboard.
+   * <p>
+   * <p>To track Purchase events, use {@link Leanplum#PURCHASE_EVENT_NAME}.
+   *
+   * @param event Name of the event.
+   */
+  public static void track(String event) {
+    track(event, 0.0, "", null);
+  }
+
+  /**
+   * Logs a particular event in your application. The string can be any value of your choosing, and
+   * will show up in the dashboard.
+   * <p>
+   * <p>To track Purchase events, use {@link Leanplum#PURCHASE_EVENT_NAME}.
+   *
+   * @param event Name of the event.
+   * @param value The value of the event. The value is special in that you can use it for targeting
+   * content and messages to users who have a particular lifetime value. For purchase events, the
+   * value is the revenue associated with the purchase.
+   */
+  public static void track(String event, double value) {
+    track(event, value, "", null);
+  }
+
+  /**
+   * Logs a particular event in your application. The string can be any value of your choosing, and
+   * will show up in the dashboard.
+   * <p>
+   * <p>To track Purchase events, use {@link Leanplum#PURCHASE_EVENT_NAME}.
+   *
+   * @param event Name of the event.
+   * @param info Basic context associated with the event, such as the item purchased. info is
+   * treated like a default parameter.
+   */
+  public static void track(String event, String info) {
+    track(event, 0.0, info, null);
+  }
+
+  /**
+   * Logs a particular event in your application. The string can be any value of your choosing, and
+   * will show up in the dashboard.
+   * <p>
+   * <p>To track Purchase events, use {@link Leanplum#PURCHASE_EVENT_NAME}.
+   *
+   * @param event Name of the event.
+   * @param params Key-value pairs with metrics or data associated with the event. Parameters can be
+   * strings or numbers. You can use up to 200 different parameter names in your app.
+   */
+  public static void track(String event, Map<String, ?> params) {
+    track(event, 0.0, "", params);
+  }
+
+  /**
+   * Logs a particular event in your application. The string can be any value of your choosing, and
+   * will show up in the dashboard.
+   * <p>
+   * <p>To track Purchase events, use {@link Leanplum#PURCHASE_EVENT_NAME}.
+   *
+   * @param event Name of the event.
+   * @param value The value of the event. The value is special in that you can use it for targeting
+   * content and messages to users who have a particular lifetime value. For purchase events, the
+   * value is the revenue associated with the purchase.
+   * @param params Key-value pairs with metrics or data associated with the event. Parameters can be
+   * strings or numbers. You can use up to 200 different parameter names in your app.
+   */
+  public static void track(String event, double value, Map<String, ?> params) {
+    track(event, value, "", params);
+  }
+
+  /**
+   * Logs a particular event in your application. The string can be any value of your choosing, and
+   * will show up in the dashboard.
+   * <p>
+   * <p>To track Purchase events, use {@link Leanplum#PURCHASE_EVENT_NAME}.
+   *
+   * @param event Name of the event.
+   * @param value The value of the event. The value is special in that you can use it for targeting
+   * content and messages to users who have a particular lifetime value. For purchase events, the
+   * value is the revenue associated with the purchase.
+   * @param info Basic context associated with the event, such as the item purchased. info is
+   * treated like a default parameter.
+   */
+  public static void track(String event, double value, String info) {
+    track(event, value, info, null);
+  }
+
+  /**
+   * Advances to a particular state in your application. The string can be any value of your
+   * choosing, and will show up in the dashboard. A state is a section of your app that the user is
+   * currently in.
+   *
+   * @param state Name of the state. State may be empty for message impression events.
+   * @param info Basic context associated with the state, such as the item purchased. info is
+   * treated like a default parameter.
+   * @param params Key-value pairs with metrics or data associated with the state. Parameters can be
+   * strings or numbers. You can use up to 200 different parameter names in your app.
+   */
+  public static void advanceTo(final String state, String info, final Map<String, ?> params) {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call advanceTo before calling start");
+      return;
+    }
+
+    try {
+      final Map<String, Object> requestParams = new HashMap<>();
+      requestParams.put(Constants.Params.INFO, info);
+      requestParams.put(Constants.Params.STATE, state);
+      final Map<String, ?> validatedParams;
+      if (params != null) {
+        validatedParams = LeanplumInternal.validateAttributes(params, "params", false);
+        requestParams.put(Constants.Params.PARAMS, JsonConverter.toJson(validatedParams));
+      } else {
+        validatedParams = null;
+      }
+
+      if (LeanplumInternal.issuedStart()) {
+        advanceToInternal(state, validatedParams, requestParams);
+      } else {
+        LeanplumInternal.addStartIssuedHandler(new Runnable() {
+          @Override
+          public void run() {
+            try {
+              advanceToInternal(state, validatedParams, requestParams);
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+          }
+        });
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Performs the advance API and any actions that are associated with the state.
+   *
+   * @param state The state name. State may be empty for message impression events.
+   * @param params The state parameters.
+   * @param requestParams The arguments to send with the API request.
+   */
+  private static void advanceToInternal(String state, Map<String, ?> params,
+      Map<String, Object> requestParams) {
+    Request.post(Constants.Methods.ADVANCE, requestParams).send();
+
+    ContextualValues contextualValues = new ContextualValues();
+    contextualValues.parameters = params;
+
+    LeanplumInternal.maybePerformActions("state", state,
+        LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_ALL, null, contextualValues);
+  }
+
+  /**
+   * Advances to a particular state in your application. The string can be any value of your
+   * choosing, and will show up in the dashboard. A state is a section of your app that the user is
+   * currently in.
+   *
+   * @param state Name of the state. State may be empty for message impression events.
+   */
+  public static void advanceTo(String state) {
+    advanceTo(state, "", null);
+  }
+
+  /**
+   * Advances to a particular state in your application. The string can be any value of your
+   * choosing, and will show up in the dashboard. A state is a section of your app that the user is
+   * currently in.
+   *
+   * @param state Name of the state. State may be empty for message impression events.
+   * @param info Basic context associated with the state, such as the item purchased. info is
+   * treated like a default parameter.
+   */
+  public static void advanceTo(String state, String info) {
+    advanceTo(state, info, null);
+  }
+
+  /**
+   * Advances to a particular state in your application. The string can be any value of your
+   * choosing, and will show up in the dashboard. A state is a section of your app that the user is
+   * currently in.
+   *
+   * @param state Name of the state. State may be empty for message impression events.
+   * @param params Key-value pairs with metrics or data associated with the state. Parameters can be
+   * strings or numbers. You can use up to 200 different parameter names in your app.
+   */
+  public static void advanceTo(String state, Map<String, ?> params) {
+    advanceTo(state, "", params);
+  }
+
+  /**
+   * Pauses the current state. You can use this if your game has a "pause" mode. You shouldn't call
+   * it when someone switches out of your app because that's done automatically.
+   */
+  public static void pauseState() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call pauseState before calling start");
+      return;
+    }
+
+    try {
+      if (LeanplumInternal.issuedStart()) {
+        pauseStateInternal();
+      } else {
+        LeanplumInternal.addStartIssuedHandler(new Runnable() {
+          @Override
+          public void run() {
+            try {
+              pauseStateInternal();
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+          }
+        });
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  private static void pauseStateInternal() {
+    Request.post(Constants.Methods.PAUSE_STATE, new HashMap<String, Object>()).send();
+  }
+
+  /**
+   * Resumes the current state.
+   */
+  public static void resumeState() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (!LeanplumInternal.hasCalledStart()) {
+      Log.e("You cannot call resumeState before calling start");
+      return;
+    }
+
+    try {
+      if (LeanplumInternal.issuedStart()) {
+        resumeStateInternal();
+      } else {
+        LeanplumInternal.addStartIssuedHandler(new Runnable() {
+          @Override
+          public void run() {
+            try {
+              resumeStateInternal();
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+          }
+        });
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  private static void resumeStateInternal() {
+    Request.post(Constants.Methods.RESUME_STATE, new HashMap<String, Object>()).send();
+  }
+
+  /**
+   * Forces content to update from the server. If variables have changed, the appropriate callbacks
+   * will fire. Use sparingly as if the app is updated, you'll have to deal with potentially
+   * inconsistent state or user experience.
+   */
+  public static void forceContentUpdate() {
+    forceContentUpdate(null);
+  }
+
+  /**
+   * Forces content to update from the server. If variables have changed, the appropriate callbacks
+   * will fire. Use sparingly as if the app is updated, you'll have to deal with potentially
+   * inconsistent state or user experience.
+   *
+   * @param callback The callback to invoke when the call completes from the server. The callback
+   * will fire regardless of whether the variables have changed.
+   */
+  @SuppressWarnings("SameParameterValue")
+  public static void forceContentUpdate(final VariablesChangedCallback callback) {
+    if (Constants.isNoop()) {
+      if (callback != null) {
+        OsHandler.getInstance().post(callback);
+      }
+      return;
+    }
+    try {
+      Map<String, Object> params = new HashMap<>();
+      params.put(Constants.Params.INCLUDE_DEFAULTS, Boolean.toString(false));
+      params.put(Constants.Params.INBOX_MESSAGES, LeanplumInbox.getInstance().messagesIds());
+      Request req = Request.post(Constants.Methods.GET_VARS, params);
+      req.onResponse(new Request.ResponseCallback() {
+        @Override
+        public void response(JSONObject response) {
+          try {
+            JSONObject lastResponse = Request.getLastResponse(response);
+            if (lastResponse == null) {
+              Log.e("No response received from the server. Please contact us to investigate.");
+            } else {
+              applyContentInResponse(lastResponse, false);
+              if (lastResponse.optBoolean(Constants.Keys.SYNC_INBOX, false)) {
+                LeanplumInbox.getInstance().downloadMessages();
+              }
+              if (lastResponse.optBoolean(Constants.Keys.LOGGING_ENABLED, false)) {
+                Constants.loggingEnabled = true;
+              }
+            }
+            if (callback != null) {
+              OsHandler.getInstance().post(callback);
+            }
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+        }
+      });
+      req.onError(
+          new Request.ErrorCallback() {
+            @Override
+            public void error(Exception e) {
+              if (callback != null) {
+                OsHandler.getInstance().post(callback);
+              }
+            }
+          });
+      req.sendIfConnected();
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * This should be your first statement in a unit test. This prevents Leanplum from communicating
+   * with the server.
+   */
+  public static void enableTestMode() {
+    Constants.isTestMode = true;
+  }
+
+  public static boolean isTestModeEnabled() {
+    return Constants.isTestMode;
+  }
+
+  /**
+   * This should be your first statement in a unit test. This prevents Leanplum from communicating
+   * with the server.
+   */
+  public static void setIsTestModeEnabled(boolean isTestModeEnabled) {
+    Constants.isTestMode = isTestModeEnabled;
+  }
+
+  /**
+   * Gets the path for a particular resource. The resource can be overridden by the server.
+   */
+  public static String pathForResource(String filename) {
+    if (TextUtils.isEmpty(filename)) {
+      Log.e("pathForResource - Empty filename parameter provided.");
+      return null;
+    }
+
+    Var fileVar = Var.defineFile(filename, filename);
+    return (fileVar != null) ? fileVar.fileValue() : null;
+  }
+
+  /**
+   * Traverses the variable structure with the specified path. Path components can be either strings
+   * representing keys in a dictionary, or integers representing indices in a list.
+   */
+  public static Object objectForKeyPath(Object... components) {
+    return objectForKeyPathComponents(components);
+  }
+
+  /**
+   * Traverses the variable structure with the specified path. Path components can be either strings
+   * representing keys in a dictionary, or integers representing indices in a list.
+   */
+  public static Object objectForKeyPathComponents(Object[] pathComponents) {
+    try {
+      return VarCache.getMergedValueFromComponentArray(pathComponents);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+    return null;
+  }
+
+  /**
+   * Returns information about the active variants for the current user. Each variant will contain
+   * an "id" key mapping to the numeric ID of the variant.
+   */
+  public static List<Map<String, Object>> variants() {
+    List<Map<String, Object>> variants = VarCache.variants();
+    if (variants == null) {
+      return new ArrayList<>();
+    }
+    return variants;
+  }
+
+  /**
+   * Returns metadata for all active in-app messages. Recommended only for debugging purposes and
+   * advanced use cases.
+   */
+  public static Map<String, Object> messageMetadata() {
+    Map<String, Object> messages = VarCache.messages();
+    if (messages == null) {
+      return new HashMap<>();
+    }
+    return messages;
+  }
+
+  /**
+   * Set location manually. Calls setDeviceLocation with cell type. Best if used in after calling
+   * disableLocationCollection.
+   *
+   * @param location Device location.
+   */
+  public static void setDeviceLocation(Location location) {
+    setDeviceLocation(location, LeanplumLocationAccuracyType.CELL);
+  }
+
+  /**
+   * Set location manually. Best if used in after calling disableLocationCollection. Useful if you
+   * want to apply additional logic before sending in the location.
+   *
+   * @param location Device location.
+   * @param type LeanplumLocationAccuracyType of the location.
+   */
+  public static void setDeviceLocation(Location location, LeanplumLocationAccuracyType type) {
+    if (locationCollectionEnabled) {
+      Log.w("Leanplum is automatically collecting device location, so there is no need to " +
+          "call setDeviceLocation. If you prefer to always set location manually, " +
+          "then call disableLocationCollection.");
+    }
+    LeanplumInternal.setUserLocationAttribute(location, type,
+        new LeanplumInternal.locationAttributeRequestsCallback() {
+          @Override
+          public void response(boolean success) {
+            if (success) {
+              Log.d("setUserAttributes with location is successfully called");
+            }
+          }
+        });
+  }
+
+  /**
+   * Disable location collection by setting |locationCollectionEnabled| to false.
+   */
+  public static void disableLocationCollection() {
+    locationCollectionEnabled = false;
+  }
+
+  /**
+   * Returns whether a customer enabled location collection.
+   *
+   * @return The value of |locationCollectionEnabled|.
+   */
+  public static boolean isLocationCollectionEnabled() {
+    return locationCollectionEnabled;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumActivityHelper.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.Bundle;
+
+import com.leanplum.annotations.Parser;
+import com.leanplum.callbacks.PostponableAction;
+import com.leanplum.internal.ActionManager;
+import com.leanplum.internal.LeanplumInternal;
+import com.leanplum.internal.LeanplumUIEditorWrapper;
+import com.leanplum.internal.OsHandler;
+import com.leanplum.internal.Util;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * Utility class for handling activity lifecycle events. Call these methods from your activity if
+ * you don't extend one of the Leanplum*Activity classes.
+ *
+ * @author Andrew First
+ */
+public class LeanplumActivityHelper {
+  /**
+   * Whether any of the activities are paused.
+   */
+  static boolean isActivityPaused;
+  private static Set<Class> ignoredActivityClasses;
+
+  /**
+   * Whether lifecycle callbacks were registered. This is only supported on Android OS &gt;= 4.0.
+   */
+  private static boolean registeredCallbacks;
+
+  static Activity currentActivity;
+
+  private final Activity activity;
+  private LeanplumResources res;
+  private LeanplumInflater inflater;
+
+  private static final Queue<Runnable> pendingActions = new LinkedList<>();
+  private static final Runnable runPendingActionsRunnable = new Runnable() {
+    @Override
+    public void run() {
+      runPendingActions();
+    }
+  };
+
+  public LeanplumActivityHelper(Activity activity) {
+    this.activity = activity;
+    Leanplum.setApplicationContext(activity.getApplicationContext());
+    Parser.parseVariables(activity);
+  }
+
+  /**
+   * Retrieves the currently active activity.
+   */
+  public static Activity getCurrentActivity() {
+    return currentActivity;
+  }
+
+  /**
+   * Retrieves if the activity is paused.
+   */
+  public static boolean isActivityPaused() {
+    return isActivityPaused;
+  }
+
+  /**
+   * Enables lifecycle callbacks for Android devices with Android OS &gt;= 4.0
+   */
+  public static void enableLifecycleCallbacks(final Application app) {
+    Leanplum.setApplicationContext(app.getApplicationContext());
+    if (Build.VERSION.SDK_INT < 14) {
+      return;
+    }
+    app.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+      @Override
+      public void onActivityStopped(Activity activity) {
+        try {
+          onStop(activity);
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+
+      @Override
+      public void onActivityResumed(final Activity activity) {
+        try {
+          if (Leanplum.isInterfaceEditingEnabled()) {
+            // Execute runnable in next frame to ensure that all system stuff is setup, before
+            // applying UI edits.
+            OsHandler.getInstance().post(new Runnable() {
+              @Override
+              public void run() {
+                LeanplumUIEditorWrapper.getInstance().applyInterfaceEdits(activity);
+              }
+            });
+          }
+          onResume(activity);
+          if (Leanplum.isScreenTrackingEnabled()) {
+            Leanplum.advanceTo(activity.getLocalClassName());
+          }
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+
+      @Override
+      public void onActivityPaused(Activity activity) {
+        try {
+          onPause(activity);
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+
+      @Override
+      public void onActivityStarted(Activity activity) {
+      }
+
+      @Override
+      public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+      }
+
+      @Override
+      public void onActivityDestroyed(Activity activity) {
+      }
+
+      @Override
+      public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+      }
+
+    });
+    registeredCallbacks = true;
+  }
+
+  public LeanplumResources getLeanplumResources() {
+    return getLeanplumResources(null);
+  }
+
+  public LeanplumResources getLeanplumResources(Resources baseResources) {
+    if (res != null) {
+      return res;
+    }
+    if (baseResources == null) {
+      baseResources = activity.getResources();
+    }
+    if (baseResources instanceof LeanplumResources) {
+      return (LeanplumResources) baseResources;
+    }
+    res = new LeanplumResources(baseResources);
+    return res;
+  }
+
+  /**
+   * Sets the view from a layout file.
+   */
+  public void setContentView(final int layoutResID) {
+    if (inflater == null) {
+      inflater = LeanplumInflater.from(activity);
+    }
+    activity.setContentView(inflater.inflate(layoutResID));
+  }
+
+  @SuppressWarnings("unused")
+  private static void onPause(Activity activity) {
+    isActivityPaused = true;
+  }
+
+  /**
+   * Call this when your activity gets paused.
+   */
+  public void onPause() {
+    try {
+      if (!registeredCallbacks) {
+        onPause(activity);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  private static void onResume(Activity activity) {
+    isActivityPaused = false;
+    currentActivity = activity;
+    if (LeanplumInternal.isPaused() || LeanplumInternal.hasStartedInBackground()) {
+      Leanplum.resume();
+      LocationManager locationManager = ActionManager.getLocationManager();
+      if (locationManager != null) {
+        locationManager.updateGeofencing();
+        locationManager.updateUserLocation();
+      }
+    }
+
+    // Pending actions execution triggered, but Leanplum.start() may not be done yet.
+    LeanplumInternal.addStartIssuedHandler(runPendingActionsRunnable);
+  }
+
+  /**
+   * Call this when your activity gets resumed.
+   */
+  public void onResume() {
+    try {
+      if (!registeredCallbacks) {
+        onResume(activity);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  private static void onStop(Activity activity) {
+    // onStop is called when the activity gets hidden, and is
+    // called after onPause.
+    //
+    // However, if we're switching to another activity, that activity
+    // will call onResume, so we shouldn't pause if that's the case.
+    //
+    // Thus, we can call pause from here, only if all activities are paused.
+    if (isActivityPaused) {
+      Leanplum.pause();
+      LocationManager locationManager = ActionManager.getLocationManager();
+      if (locationManager != null) {
+        locationManager.updateGeofencing();
+      }
+    }
+    if (currentActivity != null && currentActivity.equals(activity)) {
+      // Don't leak activities.
+      currentActivity = null;
+    }
+  }
+
+  /**
+   * Call this when your activity gets stopped.
+   */
+  public void onStop() {
+    try {
+      if (!registeredCallbacks) {
+        onStop(activity);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Enqueues a callback to invoke when an activity reaches in the foreground.
+   */
+  public static void queueActionUponActive(Runnable action) {
+    try {
+      if (currentActivity != null && !currentActivity.isFinishing() && !isActivityPaused &&
+          (!(action instanceof PostponableAction) || !isActivityClassIgnored(currentActivity))) {
+        action.run();
+      } else {
+        synchronized (pendingActions) {
+          pendingActions.add(action);
+        }
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Runs any pending actions that have been queued.
+   */
+  private static void runPendingActions() {
+    if (isActivityPaused || currentActivity == null) {
+      // Trying to run pending actions, but no activity is resumed. Skip.
+      return;
+    }
+
+    Queue<Runnable> runningActions;
+    synchronized (pendingActions) {
+      runningActions = new LinkedList<>(pendingActions);
+      pendingActions.clear();
+    }
+    for (Runnable action : runningActions) {
+      // If postponable callback and current activity should be skipped, then postpone.
+      if (action instanceof PostponableAction && isActivityClassIgnored(currentActivity)) {
+        pendingActions.add(action);
+      } else {
+        action.run();
+      }
+    }
+  }
+
+  /**
+   * Whether or not an activity is configured to not show messages.
+   *
+   * @param activity The activity to check.
+   * @return Whether or not the activity is ignored.
+   */
+  private static boolean isActivityClassIgnored(Activity activity) {
+    return ignoredActivityClasses != null && ignoredActivityClasses.contains(activity.getClass());
+  }
+
+  /**
+   * Does not show messages for the provided activity classes.
+   *
+   * @param activityClasses The activity classes to not show messages on.
+   */
+  public static void deferMessagesForActivities(Class... activityClasses) {
+    // Check if valid arguments are provided.
+    if (activityClasses == null || activityClasses.length == 0) {
+      return;
+    }
+    // Lazy instantiate activityClasses set.
+    if (ignoredActivityClasses == null) {
+      ignoredActivityClasses = new HashSet<>(activityClasses.length);
+    }
+    // Add all class names to set.
+    Collections.addAll(ignoredActivityClasses, activityClasses);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumApplication.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.annotation.SuppressLint;
+import android.app.Application;
+import android.content.Context;
+import android.content.res.Resources;
+
+import com.leanplum.annotations.Parser;
+import com.leanplum.internal.Constants;
+
+/**
+ * Base class for your Application that handles lifecycle events.
+ *
+ * @author Andrew First
+ */
+@SuppressLint("Registered")
+public class LeanplumApplication extends Application {
+  private static LeanplumApplication instance;
+
+  public static LeanplumApplication getInstance() {
+    return instance;
+  }
+
+  public static Context getContext() {
+    return instance;
+  }
+
+  @Override
+  public void onCreate() {
+    super.onCreate();
+    instance = this;
+    LeanplumActivityHelper.enableLifecycleCallbacks(this);
+    Parser.parseVariables(this);
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Constants.isNoop() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return new LeanplumResources(super.getResources());
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumCloudMessagingProvider.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.Context;
+
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.Log;
+import com.leanplum.utils.SharedPreferencesUtil;
+
+/**
+ * Leanplum Cloud Messaging provider.
+ *
+ * @author Anna Orlova
+ */
+abstract class LeanplumCloudMessagingProvider {
+  static final String PUSH_REGISTRATION_SERVICE = "com.leanplum.LeanplumPushRegistrationService";
+  static final String PUSH_RECEIVER = "com.leanplum.LeanplumPushReceiver";
+
+  private static String registrationId;
+
+  /**
+   * Registration app for Cloud Messaging.
+   *
+   * @return String - registration id for app.
+   */
+  public abstract String getRegistrationId();
+
+  /**
+   * Verifies that Android Manifest is set up correctly.
+   *
+   * @return true If Android Manifest is set up correctly.
+   */
+  public abstract boolean isManifestSetUp();
+
+  public abstract boolean isInitialized();
+
+  /**
+   * Unregister from cloud messaging.
+   */
+  public abstract void unregister();
+
+  static String getCurrentRegistrationId() {
+    return registrationId;
+  }
+
+  void onRegistrationIdReceived(Context context, String registrationId) {
+    if (registrationId == null) {
+      Log.w("Registration ID is undefined.");
+      return;
+    }
+    LeanplumCloudMessagingProvider.registrationId = registrationId;
+    // Check if received push notification token is different from stored one and send new one to
+    // server.
+    if (!LeanplumCloudMessagingProvider.registrationId.equals(SharedPreferencesUtil.getString(
+        context, Constants.Defaults.LEANPLUM_PUSH, Constants.Defaults.PROPERTY_REGISTRATION_ID))) {
+      Log.i("Device registered for push notifications with registration token", registrationId);
+      storePreferences(context.getApplicationContext());
+    }
+    // Send push token on every launch for not missed token when user force quit the app.
+    sendRegistrationIdToBackend(LeanplumCloudMessagingProvider.registrationId);
+  }
+
+  /**
+   * Sends the registration ID to the server over HTTP.
+   */
+  private static void sendRegistrationIdToBackend(String registrationId) {
+    Leanplum.setRegistrationId(registrationId);
+  }
+
+  /**
+   * Stores the registration ID in the application's {@code SharedPreferences}.
+   *
+   * @param context application's context.
+   */
+  public void storePreferences(Context context) {
+    Log.v("Saving the registration ID in the shared preferences.");
+    SharedPreferencesUtil.setString(context, Constants.Defaults.LEANPLUM_PUSH,
+        Constants.Defaults.PROPERTY_REGISTRATION_ID, registrationId);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumDeviceIdMode.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+/**
+ * LeanplumDeviceIdMode enum used for Leanplum.setDeviceMode.
+ *
+ * @author Paul Beusterien
+ */
+public enum LeanplumDeviceIdMode {
+  /**
+   * Takes the md5 hash of the MAC address, or the ANDROID_ID on Marshmallow or later, or if the
+   * permission to access the MAC address is not set (Default).
+   */
+  MD5_MAC_ADDRESS,
+
+  /**
+   * Uses the ANDROID_ID.
+   */
+  ANDROID_ID,
+
+  /**
+   * Uses the Android Advertising ID. Requires Google Play Services v4.0 or higher. If there is an
+   * error retrieving the Advertising ID, MD5_MAC_ADDRESS will be used instead.
+   * <p>
+   * <p>You also need the following line of code in your Android manifest within your
+   * &lt;application&gt; tag:
+   * <p>
+   * <pre>&lt;meta-data android:name="com.google.android.gms.version"
+   * android:value="@integer/google_play_services_version" /&gt;</pre>
+   */
+  ADVERTISING_ID,
+}
+
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumEditorMode.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+/**
+ * Enum for describing the Editor Mode.
+ *
+ * @author Ben Marten
+ */
+public enum LeanplumEditorMode {
+  LP_EDITOR_MODE_INTERFACE(0),
+  LP_EDITOR_MODE_EVENT(1);
+
+  private final int value;
+
+  /**
+   * Creates a new EditorMode enum with given value.
+   */
+  LeanplumEditorMode(final int newValue) {
+    value = newValue;
+  }
+
+  /**
+   * Returns the value of the enum entry.
+   *
+   * @return The value of the entry.
+   */
+  public int getValue() {
+    return value;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+/**
+ * Leanplum exception.
+ *
+ * @author Andrew First
+ */
+public class LeanplumException extends RuntimeException {
+  private static final long serialVersionUID = 1L;
+
+  public LeanplumException(String message) {
+    super(message);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumGcmProvider.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.Context;
+
+import com.google.android.gms.gcm.GoogleCloudMessaging;
+import com.google.android.gms.iid.InstanceID;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.LeanplumManifestHelper;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+import com.leanplum.utils.SharedPreferencesUtil;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Leanplum provider for work with GCM.
+ *
+ * @author Anna Orlova
+ */
+class LeanplumGcmProvider extends LeanplumCloudMessagingProvider {
+  private static final String ERROR_TIMEOUT = "TIMEOUT";
+  private static final String ERROR_INVALID_SENDER = "INVALID_SENDER";
+  private static final String ERROR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
+  private static final String ERROR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
+  private static final String ERROR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
+
+  private static final String SEND_PERMISSION = "com.google.android.c2dm.permission.SEND";
+  private static final String RECEIVE_PERMISSION = "com.google.android.c2dm.permission.RECEIVE";
+  private static final String RECEIVE_ACTION = "com.google.android.c2dm.intent.RECEIVE";
+  private static final String REGISTRATION_ACTION = "com.google.android.c2dm.intent.REGISTRATION";
+  private static final String INSTANCE_ID_ACTION = "com.google.android.gms.iid.InstanceID";
+  private static final String PUSH_LISTENER_SERVICE = "com.leanplum.LeanplumPushListenerService";
+  private static final String GCM_RECEIVER = "com.google.android.gms.gcm.GcmReceiver";
+  private static final String PUSH_INSTANCE_ID_SERVICE =
+      "com.leanplum.LeanplumPushInstanceIDService";
+
+  private static String senderIds;
+
+  static void setSenderId(String senderId) {
+    senderIds = senderId;
+  }
+
+  /**
+   * Stores the GCM sender ID in the application's {@code SharedPreferences}.
+   *
+   * @param context application's context.
+   */
+  @Override
+  public void storePreferences(Context context) {
+    super.storePreferences(context);
+    Log.v("Saving GCM sender ID");
+    SharedPreferencesUtil.setString(context, Constants.Defaults.LEANPLUM_PUSH,
+        Constants.Defaults.PROPERTY_SENDER_IDS, senderIds);
+  }
+
+  public String getRegistrationId() {
+    String registrationId = null;
+    try {
+      InstanceID instanceID = InstanceID.getInstance(Leanplum.getContext());
+      if (senderIds == null || instanceID == null) {
+        Log.w("There was a problem setting up GCM, please make sure you follow instructions " +
+            "on how to set it up.");
+        return null;
+      }
+      registrationId = instanceID.getToken(senderIds,
+          GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
+    } catch (IOException e) {
+      if (GoogleCloudMessaging.ERROR_SERVICE_NOT_AVAILABLE.equals(e.getMessage())) {
+        Log.w("GCM service is not available. Will try to " +
+            "register again next time the app starts.");
+      } else if (ERROR_TIMEOUT.equals(e.getMessage())) {
+        Log.w("Retrieval of GCM registration token timed out. " +
+            "Will try to register again next time the app starts.");
+      } else if (ERROR_INVALID_SENDER.equals(e.getMessage())) {
+        Log.e("The GCM sender account is not recognized. Please be " +
+            "sure to call LeanplumPushService.setGsmSenderId() with a valid GCM sender id.");
+      } else if (ERROR_AUTHENTICATION_FAILED.equals(e.getMessage())) {
+        Log.w("Bad Google Account password.");
+      } else if (ERROR_PHONE_REGISTRATION_ERROR.equals(e.getMessage())) {
+        Log.w("This phone doesn't currently support GCM.");
+      } else if (ERROR_TOO_MANY_REGISTRATIONS.equals(e.getMessage())) {
+        Log.w("This phone has more than the allowed number of " +
+            "apps that are registered with GCM.");
+      } else {
+        Log.e("Failed to complete registration token refresh.");
+        Util.handleException(e);
+      }
+    } catch (Throwable t) {
+      Log.w("There was a problem setting up GCM, please make sure you follow instructions " +
+          "on how to set it up. Please verify that you are using correct version of " +
+          "Google Play Services and Android Support Library v4.");
+      Util.handleException(t);
+    }
+    return registrationId;
+  }
+
+  public boolean isInitialized() {
+    return senderIds != null || getCurrentRegistrationId() != null;
+  }
+
+  public boolean isManifestSetUp() {
+    Context context = Leanplum.getContext();
+    if (context == null) {
+      return false;
+    }
+
+    boolean hasPermissions = LeanplumManifestHelper.checkPermission(RECEIVE_PERMISSION, false, true)
+        && (LeanplumManifestHelper.checkPermission(context.getPackageName() +
+        ".gcm.permission.C2D_MESSAGE", true, false) || LeanplumManifestHelper.checkPermission(
+        context.getPackageName() + ".permission.C2D_MESSAGE", true, true));
+
+    boolean hasGcmReceiver = LeanplumManifestHelper.checkComponent(
+        LeanplumManifestHelper.getReceivers(), GCM_RECEIVER, true, SEND_PERMISSION,
+        Arrays.asList(RECEIVE_ACTION, REGISTRATION_ACTION), context.getPackageName());
+    boolean hasPushReceiver = LeanplumManifestHelper.checkComponent(
+        LeanplumManifestHelper.getReceivers(), PUSH_RECEIVER, false, null,
+        Collections.singletonList(PUSH_LISTENER_SERVICE), null);
+
+    boolean hasReceivers = hasGcmReceiver && hasPushReceiver;
+
+    boolean hasPushListenerService = LeanplumManifestHelper.checkComponent(
+        LeanplumManifestHelper.getServices(), PUSH_LISTENER_SERVICE, false, null,
+        Collections.singletonList(RECEIVE_ACTION), null);
+    boolean hasPushInstanceIDService = LeanplumManifestHelper.checkComponent(
+        LeanplumManifestHelper.getServices(), PUSH_INSTANCE_ID_SERVICE, false, null,
+        Collections.singletonList(INSTANCE_ID_ACTION), null);
+    boolean hasPushRegistrationService = LeanplumManifestHelper.checkComponent(
+        LeanplumManifestHelper.getServices(), PUSH_REGISTRATION_SERVICE, false, null, null, null);
+
+    boolean hasServices = hasPushListenerService && hasPushInstanceIDService
+        && hasPushRegistrationService;
+
+    return hasPermissions && hasReceivers && hasServices;
+  }
+
+  /**
+   * Unregister from GCM.
+   */
+  public void unregister() {
+    try {
+      InstanceID.getInstance(Leanplum.getContext()).deleteInstanceID();
+      Log.i("Application was unregistred from GCM.");
+    } catch (Exception e) {
+      Log.e("Failed to unregister from GCM.");
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumInbox.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.leanplum.callbacks.InboxChangedCallback;
+import com.leanplum.callbacks.VariablesChangedCallback;
+import com.leanplum.internal.AESCrypt;
+import com.leanplum.internal.CollectionUtil;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.JsonConverter;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.OsHandler;
+import com.leanplum.internal.Request;
+import com.leanplum.internal.Util;
+
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Inbox class.
+ *
+ * @author Aleksandar Gyorev, Anna Orlova
+ */
+public class LeanplumInbox {
+  static boolean isInboxImagePrefetchingEnabled = true;
+  /**
+   * Should be like this until Newsfeed is removed for backward compatibility.
+   */
+  static Newsfeed instance = new Newsfeed();
+  static Set<String> downloadedImageUrls;
+
+  // Inbox properties.
+  private int unreadCount;
+  private Map<String, LeanplumInboxMessage> messages;
+  private boolean didLoad = false;
+  private List<InboxChangedCallback> changedCallbacks;
+  private Object updatingLock = new Object();
+
+  LeanplumInbox() {
+    this.unreadCount = 0;
+    this.messages = new HashMap<>();
+    this.didLoad = false;
+    this.changedCallbacks = new ArrayList<>();
+    downloadedImageUrls = new HashSet<>();
+  }
+
+  /**
+   * Static 'getInstance' method.
+   */
+  static LeanplumInbox getInstance() {
+    return instance;
+  }
+
+  /**
+   * Disable prefetching images.
+   */
+  public static void disableImagePrefetching() {
+    isInboxImagePrefetchingEnabled = false;
+  }
+
+  boolean isInboxImagePrefetchingEnabled() {
+    return isInboxImagePrefetchingEnabled;
+  }
+
+  void updateUnreadCount(int unreadCount) {
+    this.unreadCount = unreadCount;
+    save();
+    triggerChanged();
+  }
+
+  void update(Map<String, LeanplumInboxMessage> messages, int unreadCount, boolean shouldSave) {
+    try {
+      synchronized (updatingLock) {
+        this.unreadCount = unreadCount;
+        if (messages != null) {
+          this.messages = messages;
+        }
+      }
+      this.didLoad = true;
+      if (shouldSave) {
+        save();
+      }
+      triggerChanged();
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  void removeMessage(String messageId) {
+    int unreadCount = this.unreadCount;
+    LeanplumInboxMessage message = messageForId(messageId);
+    if (message != null && !message.isRead()) {
+      unreadCount--;
+    }
+
+    messages.remove(messageId);
+    update(messages, unreadCount, true);
+
+    if (Constants.isNoop()) {
+      return;
+    }
+
+    Map<String, Object> params = new HashMap<>();
+    params.put(Constants.Params.INBOX_MESSAGE_ID, messageId);
+    Request req = Request.post(Constants.Methods.DELETE_INBOX_MESSAGE, params);
+    req.send();
+  }
+
+  void triggerChanged() {
+    synchronized (changedCallbacks) {
+      for (InboxChangedCallback callback : changedCallbacks) {
+        OsHandler.getInstance().post(callback);
+      }
+    }
+  }
+
+  void load() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(
+        "__leanplum__", Context.MODE_PRIVATE);
+    if (Request.token() == null) {
+      update(new HashMap<String, LeanplumInboxMessage>(), 0, false);
+      return;
+    }
+    int unreadCount = 0;
+    AESCrypt aesContext = new AESCrypt(Request.appId(), Request.token());
+    String newsfeedString = aesContext.decodePreference(
+        defaults, Constants.Defaults.INBOX_KEY, "{}");
+    Map<String, Object> newsfeed = JsonConverter.fromJson(newsfeedString);
+
+    Map<String, LeanplumInboxMessage> messages = new HashMap<>();
+    if (newsfeed == null) {
+      Log.e("Could not parse newsfeed string: " + newsfeedString);
+    } else {
+      for (Map.Entry<String, Object> entry : newsfeed.entrySet()) {
+        String messageId = entry.getKey();
+        Map<String, Object> data = CollectionUtil.uncheckedCast(entry.getValue());
+        LeanplumInboxMessage message = LeanplumInboxMessage.createFromJsonMap(messageId, data);
+
+        if (message != null && message.isActive()) {
+          messages.put(messageId, message);
+          if (!message.isRead()) {
+            unreadCount++;
+          }
+        }
+      }
+    }
+
+    update(messages, unreadCount, false);
+  }
+
+  void save() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (Request.token() == null) {
+      return;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(
+        "__leanplum__", Context.MODE_PRIVATE);
+    SharedPreferences.Editor editor = defaults.edit();
+    Map<String, Object> messages = new HashMap<>();
+    for (Map.Entry<String, LeanplumInboxMessage> entry : this.messages.entrySet()) {
+      String messageId = entry.getKey();
+      NewsfeedMessage newsfeedMessage = entry.getValue();
+      Map<String, Object> data = newsfeedMessage.toJsonMap();
+      messages.put(messageId, data);
+    }
+    String messagesJson = JsonConverter.toJson(messages);
+    AESCrypt aesContext = new AESCrypt(Request.appId(), Request.token());
+    editor.putString(Constants.Defaults.INBOX_KEY, aesContext.encrypt(messagesJson));
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  void downloadMessages() {
+    if (Constants.isNoop()) {
+      return;
+    }
+
+    Request req = Request.post(Constants.Methods.GET_INBOX_MESSAGES, null);
+    req.onResponse(new Request.ResponseCallback() {
+      @Override
+      public void response(JSONObject responses) {
+        try {
+          JSONObject response = Request.getLastResponse(responses);
+          if (response == null) {
+            Log.e("No inbox response received from the server.");
+            return;
+          }
+
+          JSONObject messagesDict = response.optJSONObject(Constants.Keys.INBOX_MESSAGES);
+          if (messagesDict == null) {
+            Log.e("No inbox messages found in the response from the server.", response);
+            return;
+          }
+          int unreadCount = 0;
+          final Map<String, LeanplumInboxMessage> messages = new HashMap<>();
+          Boolean willDownladImages = false;
+
+          for (Iterator iterator = messagesDict.keys(); iterator.hasNext(); ) {
+            String messageId = (String) iterator.next();
+            JSONObject messageDict = messagesDict.getJSONObject(messageId);
+
+            Map<String, Object> actionArgs = JsonConverter.mapFromJson(
+                messageDict.getJSONObject(Constants.Keys.MESSAGE_DATA).getJSONObject(Constants.Keys.VARS)
+            );
+            Long deliveryTimestamp = messageDict.getLong(Constants.Keys.DELIVERY_TIMESTAMP);
+            Long expirationTimestamp = null;
+            if (messageDict.opt(Constants.Keys.EXPIRATION_TIMESTAMP) != null) {
+              expirationTimestamp = messageDict.getLong(Constants.Keys.EXPIRATION_TIMESTAMP);
+            }
+            boolean isRead = messageDict.getBoolean(Constants.Keys.IS_READ);
+            LeanplumInboxMessage message = LeanplumInboxMessage.constructMessage(messageId,
+                deliveryTimestamp, expirationTimestamp, isRead, actionArgs);
+            if (message != null) {
+              willDownladImages |= message.downloadImageIfPrefetchingEnabled();
+              if (!isRead) {
+                unreadCount++;
+              }
+              messages.put(messageId, message);
+            }
+          }
+
+          if (!willDownladImages) {
+            update(messages, unreadCount, true);
+            return;
+          }
+
+          final int totalUnreadCount = unreadCount;
+          Leanplum.addOnceVariablesChangedAndNoDownloadsPendingHandler(
+              new VariablesChangedCallback() {
+                @Override
+                public void variablesChanged() {
+                  update(messages, totalUnreadCount, true);
+                }
+              });
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+    });
+    req.sendIfConnected();
+  }
+
+  /**
+   * Returns the number of all inbox messages on the device.
+   */
+  public int count() {
+    return messages.size();
+  }
+
+  /**
+   * Returns the number of the unread inbox messages on the device.
+   */
+  public int unreadCount() {
+    return unreadCount;
+  }
+
+  /**
+   * Returns the identifiers of all inbox messages on the device sorted in ascending
+   * chronological order, i.e. the id of the oldest message is the first one, and the most recent
+   * one is the last one in the array.
+   */
+  public List<String> messagesIds() {
+    List<String> messageIds = new ArrayList<>(messages.keySet());
+    try {
+      Collections.sort(messageIds, new Comparator<String>() {
+        @Override
+        public int compare(String firstMessage, String secondMessage) {
+          Date firstDate = messageForId(firstMessage).getDeliveryTimestamp();
+          Date secondDate = messageForId(secondMessage).getDeliveryTimestamp();
+          return firstDate.compareTo(secondDate);
+        }
+      });
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+    return messageIds;
+  }
+
+  /**
+   * Have to stay as is because of backward compatibility + generics super-sub incompatibility
+   * (http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#Topic2).
+   * <p>
+   * Returns a List containing all of the newsfeed messages sorted chronologically ascending (i.e.
+   * the oldest first and the newest last).
+   */
+  public List<NewsfeedMessage> allMessages() {
+    return allMessages(new ArrayList<NewsfeedMessage>());
+  }
+
+  /**
+   * Have to stay as is because of backward compatibility + generics super-sub incompatibility
+   * (http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#Topic2).
+   * <p>
+   * Returns a List containing all of the unread newsfeed messages sorted chronologically ascending
+   * (i.e. the oldest first and the newest last).
+   */
+  public List<NewsfeedMessage> unreadMessages() {
+    return unreadMessages(new ArrayList<NewsfeedMessage>());
+  }
+
+  /**
+   * Suggested workaround for generics to be used with {@link LeanplumInbox#getInstance()} although
+   * only LeanplumInboxMessage could be an instance of NewsfeedMessage.
+   */
+  private <T extends NewsfeedMessage> List<T> allMessages(List<T> messages) {
+    if (messages == null) {
+      messages = new ArrayList<>();
+    }
+    try {
+      for (String messageId : messagesIds()) {
+        messages.add((T) messageForId(messageId));
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+    return messages;
+  }
+
+  /**
+   * Suggested workaround for generics to be used with {@link LeanplumInbox#getInstance()} although
+   * only LeanplumInboxMessage could be an instance of NewsfeedMessage.
+   */
+  private <T extends NewsfeedMessage> List<T> unreadMessages(List<T> unreadMessages) {
+    if (unreadMessages == null) {
+      unreadMessages = new ArrayList<>();
+    }
+    List<LeanplumInboxMessage> messages = allMessages(null);
+    for (LeanplumInboxMessage message : messages) {
+      if (!message.isRead()) {
+        unreadMessages.add((T) message);
+      }
+    }
+    return unreadMessages;
+  }
+
+  /**
+   * Returns the inbox messages associated with the given getMessageId identifier.
+   */
+  public LeanplumInboxMessage messageForId(String messageId) {
+    return messages.get(messageId);
+  }
+
+  /**
+   * Add a callback for when the inbox receives new values from the server.
+   */
+  public void addChangedHandler(InboxChangedCallback handler) {
+    synchronized (changedCallbacks) {
+      changedCallbacks.add(handler);
+    }
+    if (this.didLoad) {
+      handler.inboxChanged();
+    }
+  }
+
+  /**
+   * Removes a inbox changed callback.
+   */
+  public void removeChangedHandler(InboxChangedCallback handler) {
+    synchronized (changedCallbacks) {
+      changedCallbacks.remove(handler);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumInboxMessage.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.leanplum.internal.CollectionUtil;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+
+import org.json.JSONObject;
+
+import java.io.File;
+import java.util.Map;
+
+import static com.leanplum.internal.FileManager.DownloadFileResult;
+import static com.leanplum.internal.FileManager.fileExistsAtPath;
+import static com.leanplum.internal.FileManager.fileValue;
+import static com.leanplum.internal.FileManager.maybeDownloadFile;
+
+/**
+ * LeanplumInboxMessage class.
+ *
+ * @author Anna Orlova
+ */
+public class LeanplumInboxMessage extends NewsfeedMessage {
+  private String imageUrl;
+  private String imageFileName;
+
+  private LeanplumInboxMessage(String messageId, Long deliveryTimestamp, Long expirationTimestamp,
+      boolean isRead, ActionContext context) {
+    super(messageId, deliveryTimestamp, expirationTimestamp, isRead, context);
+    imageUrl = context.stringNamed(Constants.Keys.INBOX_IMAGE);
+    if (imageUrl != null) {
+      try {
+        imageFileName = Util.sha256(imageUrl);
+      } catch (Exception ignored) {
+      }
+    }
+  }
+
+  static LeanplumInboxMessage createFromJsonMap(String messageId, Map<String, Object> map) {
+    Map<String, Object> messageData = CollectionUtil.uncheckedCast(map.get(Constants.Keys
+        .MESSAGE_DATA));
+    Long deliveryTimestamp = CollectionUtil.uncheckedCast(map.get(Constants.Keys
+        .DELIVERY_TIMESTAMP));
+    Long expirationTimestamp = CollectionUtil.uncheckedCast(map.get(Constants.Keys
+        .EXPIRATION_TIMESTAMP));
+    Boolean isRead = CollectionUtil.uncheckedCast(map.get(Constants.Keys.IS_READ));
+    return constructMessage(messageId, deliveryTimestamp, expirationTimestamp,
+        isRead != null ? isRead : false, messageData);
+  }
+
+  static LeanplumInboxMessage constructMessage(String messageId, Long deliveryTimestamp,
+      Long expirationTimestamp, boolean isRead, Map<String, Object> actionArgs) {
+    if (!isValidMessageId(messageId)) {
+      Log.e("Malformed inbox messageId: " + messageId);
+      return null;
+    }
+
+    String[] messageIdParts = messageId.split("##");
+    ActionContext context = new ActionContext((String) actionArgs.get(Constants.Values.ACTION_ARG),
+        actionArgs, messageIdParts[0]);
+    context.preventRealtimeUpdating();
+    context.update();
+    return new LeanplumInboxMessage(messageId, deliveryTimestamp, expirationTimestamp, isRead,
+        context);
+  }
+
+  /**
+   * Returns the image file path of the inbox message. Can be null.
+   */
+  public String getImageFilePath() {
+    String path = fileValue(imageFileName);
+    if (fileExistsAtPath(path)) {
+      return new File(path).getAbsolutePath();
+    }
+    if (!LeanplumInbox.getInstance().isInboxImagePrefetchingEnabled()) {
+      Log.w("Inbox Message image path is null because you're calling disableImagePrefetching. " +
+          "Consider using imageURL method or remove disableImagePrefetching.");
+    }
+    return null;
+  }
+
+  /**
+   * Returns the image Uri of the inbox message.
+   * You can safely use this with prefetching enabled.
+   * It will return the file Uri path instead if the image is in cache.
+   */
+  public Uri getImageUrl() {
+    String path = fileValue(imageFileName);
+    if (fileExistsAtPath(path)) {
+      return Uri.fromFile(new File(path));
+    }
+    if (TextUtils.isEmpty(imageUrl)) {
+      return null;
+    }
+
+    return Uri.parse(imageUrl);
+  }
+
+  /**
+   * Returns the data of the inbox message. Advanced use only.
+   */
+  public JSONObject getData() {
+    JSONObject object = null;
+    try {
+      String dataString = getContext().stringNamed(Constants.Keys.DATA);
+      if (!TextUtils.isEmpty(dataString)) {
+        object = new JSONObject(dataString);
+      }
+    } catch (Exception e) {
+      Log.w("Unable to parse JSONObject for Data field of inbox message.");
+    }
+    return object;
+  }
+
+  /**
+   * Download image if prefetching is enabled.
+   * Uses {@link LeanplumInbox#downloadedImageUrls} to make sure we don't call fileExist method
+   * multiple times for same URLs.
+   *
+   * @return Boolean True if the image will be downloaded, otherwise false.
+   */
+  Boolean downloadImageIfPrefetchingEnabled() {
+    if (!LeanplumInbox.isInboxImagePrefetchingEnabled) {
+      return false;
+    }
+
+    if (TextUtils.isEmpty(imageUrl) || LeanplumInbox.downloadedImageUrls.contains(imageUrl)) {
+      return false;
+    }
+
+    DownloadFileResult result = maybeDownloadFile(true, imageFileName,
+        imageUrl, imageUrl, null);
+    LeanplumInbox.downloadedImageUrls.add(imageUrl);
+    return DownloadFileResult.DOWNLOADING == result;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumInflater.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.view.InflateException;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Inflates layout files that may be overridden by other files.
+ *
+ * @author Andrew First
+ */
+public class LeanplumInflater {
+  private Context context;
+  private LeanplumResources res;
+
+  public static LeanplumInflater from(Context context) {
+    return new LeanplumInflater(context);
+  }
+
+  private LeanplumInflater(Context context) {
+    this.context = context;
+  }
+
+  public LeanplumResources getLeanplumResources() {
+    return getLeanplumResources(null);
+  }
+
+  public LeanplumResources getLeanplumResources(Resources baseResources) {
+    if (res != null) {
+      return res;
+    }
+    if (baseResources == null) {
+      baseResources = context.getResources();
+    }
+    if (baseResources instanceof LeanplumResources) {
+      return (LeanplumResources) baseResources;
+    }
+    res = new LeanplumResources(baseResources);
+    return res;
+  }
+
+  /**
+   * Creates a view from the corresponding resource ID.
+   */
+  public View inflate(int layoutResID) {
+    return inflate(layoutResID, null, false);
+  }
+
+  /**
+   * Creates a view from the corresponding resource ID.
+   */
+  public View inflate(int layoutResID, ViewGroup root) {
+    return inflate(layoutResID, root, root != null);
+  }
+
+  /**
+   * Creates a view from the corresponding resource ID.
+   */
+  public View inflate(int layoutResID, ViewGroup root, boolean attachToRoot) {
+    Var<String> var;
+    try {
+      LeanplumResources res = getLeanplumResources(context.getResources());
+      var = res.getOverrideResource(layoutResID);
+      if (var == null || var.stringValue.equals(var.defaultValue())) {
+        return LayoutInflater.from(context).inflate(layoutResID, root, attachToRoot);
+      }
+      int overrideResId = var.overrideResId();
+      if (overrideResId != 0) {
+        return LayoutInflater.from(context).inflate(overrideResId, root, attachToRoot);
+      }
+    } catch (Throwable t) {
+      if (!(t instanceof InflateException)) {
+        Util.handleException(t);
+      }
+      return LayoutInflater.from(context).inflate(layoutResID, root, attachToRoot);
+    }
+
+    InputStream stream = null;
+
+    try {
+      ByteArrayOutputStream fileData = new ByteArrayOutputStream();
+      stream = var.stream();
+      byte[] buffer = new byte[8192];
+      int bytesRead;
+      while ((bytesRead = stream.read(buffer)) > -1) {
+        fileData.write(buffer, 0, bytesRead);
+      }
+      Object xmlBlock = Class.forName("android.content.res.XmlBlock").getConstructor(
+          byte[].class).newInstance((Object) fileData.toByteArray());
+      XmlResourceParser parser = null;
+      try {
+        parser = (XmlResourceParser) xmlBlock.getClass().getMethod(
+            "newParser").invoke(xmlBlock);
+        return LayoutInflater.from(context).inflate(parser, root, attachToRoot);
+      } catch (Throwable t) {
+        throw new RuntimeException(t);
+      } finally {
+        if (parser != null) {
+          parser.close();
+        }
+      }
+    } catch (Throwable t) {
+      Log.e("Could not inflate resource " + layoutResID + ":" + var.stringValue(), t);
+    } finally {
+      if (stream != null) {
+        try {
+          stream.close();
+        } catch (IOException e) {
+          Log.e("Failed to close input stream.");
+        }
+      }
+    }
+    return LayoutInflater.from(context).inflate(layoutResID, root, attachToRoot);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumLocalPushListenerService.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+
+/**
+ * Listener Service for local push notifications.
+ *
+ * @author Aleksandar Gyorev
+ */
+public class LeanplumLocalPushListenerService extends IntentService {
+  public LeanplumLocalPushListenerService() {
+    super("LeanplumLocalPushListenerService");
+  }
+
+  @Override
+  protected void onHandleIntent(Intent intent) {
+    try {
+      if (intent == null) {
+        Log.e("The intent cannot be null");
+        return;
+      }
+      Bundle extras = intent.getExtras();
+      if (!extras.isEmpty() && extras.containsKey(Constants.Keys.PUSH_MESSAGE_TEXT)) {
+        LeanplumPushService.handleNotification(this, extras);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumLocationAccuracyType.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+/**
+ * LeanplumLocationAccuracyType enum used for Leanplum.setUserLocationAttribute.
+ *
+ * @author Alexis Oyama
+ */
+public enum LeanplumLocationAccuracyType {
+  /**
+   * Lowest accuracy. Reserved for internal use.
+   */
+  IP(0),
+
+  /**
+   * Default accuracy.
+   */
+  CELL(1),
+
+  /**
+   * Highest accuracy.
+   */
+  GPS(2);
+
+  private int value;
+
+  LeanplumLocationAccuracyType(int value) {
+    this.value = value;
+  }
+
+  public int value() {
+    return value;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumManualProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.Context;
+
+/**
+ * Leanplum provider for manually registering for Cloud Messaging services.
+ *
+ * @author Anna Orlova
+ */
+public class LeanplumManualProvider extends LeanplumCloudMessagingProvider {
+  LeanplumManualProvider(Context context, String registrationId) {
+    onRegistrationIdReceived(context, registrationId);
+  }
+
+  public String getRegistrationId() {
+    return getCurrentRegistrationId();
+  }
+
+  public boolean isInitialized() {
+    return true;
+  }
+
+  public boolean isManifestSetUp() {
+    return true;
+  }
+
+  public void unregister() {
+
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushInstanceIDService.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.Intent;
+
+import com.google.android.gms.iid.InstanceIDListenerService;
+import com.leanplum.internal.Log;
+
+/**
+ * GCM InstanceID listener service to handle creation, rotation, and updating of registration
+ * tokens.
+ *
+ * @author Aleksandar Gyorev
+ */
+public class LeanplumPushInstanceIDService extends InstanceIDListenerService {
+  /**
+   * Called if InstanceID token is updated. This may occur if the security of the previous token had
+   * been compromised. This call is initiated by the InstanceID provider.
+   */
+  @Override
+  public void onTokenRefresh() {
+    Log.i("GCM InstanceID token needs an update");
+    // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
+    Intent intent = new Intent(this, LeanplumPushRegistrationService.class);
+    startService(intent);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushListenerService.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.os.Bundle;
+
+import com.google.android.gms.gcm.GcmListenerService;
+import com.leanplum.internal.Constants.Keys;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+
+/**
+ * GCM listener service, which enables handling messages on the app's behalf.
+ *
+ * @author Aleksandar Gyorev
+ */
+public class LeanplumPushListenerService extends GcmListenerService {
+  /**
+   * Called when a message is received.
+   *
+   * @param senderId Sender ID of the sender.
+   * @param data Data bundle containing the message data as key-value pairs.
+   */
+  @Override
+  public void onMessageReceived(String senderId, Bundle data) {
+    try {
+      if (data.containsKey(Keys.PUSH_MESSAGE_TEXT)) {
+        LeanplumPushService.handleNotification(this, data);
+      }
+      Log.i("Received: " + data.toString());
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushNotificationCustomizer.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
+
+/**
+ * Implement LeanplumPushNotificationCustomizer to customize the appearance of notifications.
+ */
+public interface LeanplumPushNotificationCustomizer {
+  void customize(NotificationCompat.Builder builder, Bundle notificationPayload);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushReceiver.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+
+/**
+ * Handles push notification intents, for example, by tracking opens and performing the open
+ * action.
+ *
+ * @author Aleksandar Gyorev
+ */
+public class LeanplumPushReceiver extends BroadcastReceiver {
+
+  @Override
+  public void onReceive(Context context, Intent intent) {
+    try {
+      if (intent == null) {
+        Log.e("Received a null intent.");
+        return;
+      }
+      LeanplumPushService.openNotification(context, intent.getExtras());
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushRegistrationService.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+import com.leanplum.internal.Log;
+
+/**
+ * Registration service that handles registration with the GCM and FCM, using
+ * InstanceID.
+ *
+ * @author Aleksandar Gyorev
+ */
+public class LeanplumPushRegistrationService extends IntentService {
+  private static String existingRegistrationId;
+
+  public LeanplumPushRegistrationService() {
+    super("LeanplumPushRegistrationService");
+  }
+
+  @Override
+  protected void onHandleIntent(Intent intent) {
+    LeanplumCloudMessagingProvider provider = LeanplumPushService.getCloudMessagingProvider();
+    if (provider == null) {
+      Log.e("Failed to complete registration token refresh.");
+      return;
+    }
+    String registrationId = provider.getRegistrationId();
+    if (registrationId != null) {
+      if (existingRegistrationId != null && !registrationId.equals(existingRegistrationId)) {
+        Log.e("WARNING: It appears your app is registering " +
+            "with GCM/FCM using multiple GCM/FCM sender ids. Please be sure to call " +
+            "LeanplumPushService.setGcmSenderIds() with " +
+            "all of the GCM sender ids that you use, not just the one that you use with " +
+            "Leanplum. Otherwise, GCM/FCM push notifications may not work consistently.");
+      }
+      existingRegistrationId = registrationId;
+      provider.onRegistrationIdReceived(getApplicationContext(), registrationId);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumPushService.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
+import android.text.TextUtils;
+
+import com.leanplum.callbacks.VariablesChangedCallback;
+import com.leanplum.internal.ActionManager;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.Constants.Keys;
+import com.leanplum.internal.Constants.Methods;
+import com.leanplum.internal.Constants.Params;
+import com.leanplum.internal.JsonConverter;
+import com.leanplum.internal.LeanplumInternal;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Request;
+import com.leanplum.internal.Util;
+import com.leanplum.internal.VarCache;
+import com.leanplum.utils.BitmapUtil;
+import com.leanplum.utils.SharedPreferencesUtil;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * Leanplum push notification service class, handling initialization, opening, showing, integration
+ * verification and registration for push notifications.
+ *
+ * @author Andrew First, Anna Orlova
+ */
+public class LeanplumPushService {
+  /**
+   * Leanplum's built-in Google Cloud Messaging sender ID.
+   */
+  public static final String LEANPLUM_SENDER_ID = "44059457771";
+  private static final String LEANPLUM_PUSH_FCM_LISTENER_SERVICE_CLASS =
+      "com.leanplum.LeanplumPushFcmListenerService";
+  private static final String PUSH_FIREBASE_MESSAGING_SERVICE_CLASS =
+      "com.leanplum.LeanplumPushFirebaseMessagingService";
+  private static final String LEANPLUM_PUSH_INSTANCE_ID_SERVICE_CLASS =
+      "com.leanplum.LeanplumPushInstanceIDService";
+  private static final String LEANPLUM_PUSH_LISTENER_SERVICE_CLASS =
+      "com.leanplum.LeanplumPushListenerService";
+  private static final String GCM_RECEIVER_CLASS = "com.google.android.gms.gcm.GcmReceiver";
+
+  private static Class<? extends Activity> callbackClass;
+  private static LeanplumCloudMessagingProvider provider;
+  private static boolean isFirebaseEnabled = false;
+  private static final int NOTIFICATION_ID = 1;
+
+  private static final String OPEN_URL = "Open URL";
+  private static final String URL = "URL";
+  private static final String OPEN_ACTION = "Open";
+  private static LeanplumPushNotificationCustomizer customizer;
+
+  /**
+   * Use Firebase Cloud Messaging, instead of the default Google Cloud Messaging.
+   */
+  public static void enableFirebase() {
+    LeanplumPushService.isFirebaseEnabled = true;
+  }
+
+  /**
+   * Whether Firebase Cloud Messaging is enabled or not.
+   *
+   * @return Boolean - true if enabled
+   */
+  static boolean isFirebaseEnabled() {
+    return isFirebaseEnabled;
+  }
+
+  /**
+   * Get Cloud Messaging provider. By default - GCM.
+   *
+   * @return LeanplumCloudMessagingProvider - current provider
+   */
+  static LeanplumCloudMessagingProvider getCloudMessagingProvider() {
+    return provider;
+  }
+
+  /**
+   * Changes the default activity to launch if the user opens a push notification.
+   *
+   * @param callbackClass The activity class.
+   */
+  public static void setDefaultCallbackClass(Class<? extends Activity> callbackClass) {
+    LeanplumPushService.callbackClass = callbackClass;
+  }
+
+  /**
+   * Sets an object used to customize the appearance of notifications. <p>Call this from your
+   * Application class's onCreate method so that the customizer is set when your application starts
+   * in the background.
+   */
+  public static void setCustomizer(LeanplumPushNotificationCustomizer customizer) {
+    LeanplumPushService.customizer = customizer;
+  }
+
+  /**
+   * Sets the Google Cloud Messaging/Firebase Cloud Messaging sender ID. Required for push
+   * notifications to work.
+   *
+   * @param senderId The GCM/FCM sender ID to permit notifications from. Use {@link
+   * LeanplumPushService#LEANPLUM_SENDER_ID} to use the built-in sender ID for GCM. If you have
+   * multiple sender IDs, use {@link LeanplumPushService#setGcmSenderIds}.
+   */
+  public static void setGcmSenderId(String senderId) {
+    LeanplumGcmProvider.setSenderId(senderId);
+  }
+
+  /**
+   * Sets the Google Cloud Messaging/Firebase Cloud Messaging sender ID. Required for push
+   * notifications to work.
+   *
+   * @param senderIds The GCM/FCM sender IDs to permit notifications from. Use {@link
+   * LeanplumPushService#LEANPLUM_SENDER_ID} to use the built-in sender ID.
+   */
+  public static void setGcmSenderIds(String... senderIds) {
+    StringBuilder joinedSenderIds = new StringBuilder();
+    for (String senderId : senderIds) {
+      if (joinedSenderIds.length() > 0) {
+        joinedSenderIds.append(',');
+      }
+      joinedSenderIds.append(senderId);
+    }
+    LeanplumGcmProvider.setSenderId(joinedSenderIds.toString());
+  }
+
+  private static Class<? extends Activity> getCallbackClass() {
+    return callbackClass;
+  }
+
+  private static boolean areActionsEmbedded(final Bundle message) {
+    return message.containsKey(Keys.PUSH_MESSAGE_ACTION);
+  }
+
+  private static void requireMessageContent(
+      final String messageId, final VariablesChangedCallback onComplete) {
+    Leanplum.addOnceVariablesChangedAndNoDownloadsPendingHandler(new VariablesChangedCallback() {
+      @Override
+      public void variablesChanged() {
+        try {
+          Map<String, Object> messages = VarCache.messages();
+          if (messageId == null || (messages != null && messages.containsKey(messageId))) {
+            onComplete.variablesChanged();
+          } else {
+            // Try downloading the messages again if it doesn't exist.
+            // Maybe the message was created while the app was running.
+            Map<String, Object> params = new HashMap<>();
+            params.put(Params.INCLUDE_DEFAULTS, Boolean.toString(false));
+            params.put(Params.INCLUDE_MESSAGE_ID, messageId);
+            Request req = Request.post(Methods.GET_VARS, params);
+            req.onResponse(new Request.ResponseCallback() {
+              @Override
+              public void response(JSONObject response) {
+                try {
+                  JSONObject getVariablesResponse = Request.getLastResponse(response);
+                  if (getVariablesResponse == null) {
+                    Log.e("No response received from the server. Please contact us to " +
+                        "investigate.");
+                  } else {
+                    Map<String, Object> values = JsonConverter.mapFromJson(
+                        getVariablesResponse.optJSONObject(Constants.Keys.VARS));
+                    Map<String, Object> messages = JsonConverter.mapFromJson(
+                        getVariablesResponse.optJSONObject(Constants.Keys.MESSAGES));
+                    Map<String, Object> regions = JsonConverter.mapFromJson(
+                        getVariablesResponse.optJSONObject(Constants.Keys.REGIONS));
+                    List<Map<String, Object>> variants = JsonConverter.listFromJson(
+                        getVariablesResponse.optJSONArray(Constants.Keys.VARIANTS));
+                    if (!Constants.canDownloadContentMidSessionInProduction ||
+                        VarCache.getDiffs().equals(values)) {
+                      values = null;
+                    }
+                    if (VarCache.getMessageDiffs().equals(messages)) {
+                      messages = null;
+                    }
+                    if (values != null || messages != null) {
+                      VarCache.applyVariableDiffs(values, messages, null, null, regions, variants);
+                    }
+                  }
+                  onComplete.variablesChanged();
+                } catch (Throwable t) {
+                  Util.handleException(t);
+                }
+              }
+            });
+            req.onError(new Request.ErrorCallback() {
+              @Override
+              public void error(Exception e) {
+                onComplete.variablesChanged();
+              }
+            });
+            req.sendIfConnected();
+          }
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+    });
+  }
+
+  private static String getMessageId(Bundle message) {
+    String messageId = message.getString(Keys.PUSH_MESSAGE_ID_NO_MUTE_WITH_ACTION);
+    if (messageId == null) {
+      messageId = message.getString(Keys.PUSH_MESSAGE_ID_MUTE_WITH_ACTION);
+      if (messageId == null) {
+        messageId = message.getString(Keys.PUSH_MESSAGE_ID_NO_MUTE);
+        if (messageId == null) {
+          messageId = message.getString(Keys.PUSH_MESSAGE_ID_MUTE);
+        }
+      }
+    }
+    if (messageId != null) {
+      message.putString(Keys.PUSH_MESSAGE_ID, messageId);
+    }
+    return messageId;
+  }
+
+  static void handleNotification(final Context context, final Bundle message) {
+    if (LeanplumActivityHelper.currentActivity != null
+        && !LeanplumActivityHelper.isActivityPaused
+        && (message.containsKey(Keys.PUSH_MESSAGE_ID_MUTE_WITH_ACTION)
+        || message.containsKey(Keys.PUSH_MESSAGE_ID_MUTE))) {
+      // Mute notifications that have "Mute inside app" set if the app is open.
+      return;
+    }
+
+    final String messageId = LeanplumPushService.getMessageId(message);
+    if (messageId == null || !LeanplumInternal.hasCalledStart()) {
+      showNotification(context, message);
+      return;
+    }
+
+    // Can only track displays if we call Leanplum.start explicitly above where it says
+    // if (!Leanplum.calledStart). However, this is probably not worth it.
+    //
+    // Map<String, String> requestArgs = new HashMap<String, String>();
+    // requestArgs.put(Constants.Params.MESSAGE_ID, getMessageId);
+    // Leanplum.track("Displayed", 0.0, null, null, requestArgs);
+
+    showNotification(context, message);
+  }
+
+  /**
+   * Put the message into a notification and post it.
+   */
+  private static void showNotification(Context context, Bundle message) {
+    NotificationManager notificationManager = (NotificationManager)
+        context.getSystemService(Context.NOTIFICATION_SERVICE);
+
+    Intent intent = new Intent(context, LeanplumPushReceiver.class);
+    intent.addCategory("lpAction");
+    intent.putExtras(message);
+    PendingIntent contentIntent = PendingIntent.getBroadcast(
+        context.getApplicationContext(), new Random().nextInt(),
+        intent, 0);
+
+    String title = Util.getApplicationName(context.getApplicationContext());
+    if (message.getString("title") != null) {
+      title = message.getString("title");
+    }
+    NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
+        .setSmallIcon(context.getApplicationInfo().icon)
+        .setContentTitle(title)
+        .setStyle(new NotificationCompat.BigTextStyle()
+            .bigText(message.getString(Keys.PUSH_MESSAGE_TEXT)))
+        .setContentText(message.getString(Keys.PUSH_MESSAGE_TEXT));
+
+    String imageUrl = message.getString(Keys.PUSH_MESSAGE_IMAGE_URL);
+    // BigPictureStyle support requires API 16 and higher.
+    if (!TextUtils.isEmpty(imageUrl) && Build.VERSION.SDK_INT >= 16) {
+      Bitmap bigPicture = BitmapUtil.getScaledBitmap(context, imageUrl);
+      if (bigPicture != null) {
+        builder.setStyle(new NotificationCompat.BigPictureStyle()
+            .bigPicture(bigPicture)
+            .setBigContentTitle(title)
+            .setSummaryText(message.getString(Keys.PUSH_MESSAGE_TEXT)));
+      } else {
+        Log.w(String.format("Image download failed for push notification with big picture. " +
+            "No image will be included with the push notification. Image URL: %s.", imageUrl));
+      }
+    }
+
+    // Try to put notification on top of notification area.
+    if (Build.VERSION.SDK_INT >= 16) {
+      builder.setPriority(Notification.PRIORITY_MAX);
+    }
+    builder.setAutoCancel(true);
+    builder.setContentIntent(contentIntent);
+
+    if (LeanplumPushService.customizer != null) {
+      LeanplumPushService.customizer.customize(builder, message);
+    }
+
+    int notificationId = LeanplumPushService.NOTIFICATION_ID;
+    Object notificationIdObject = message.get("lp_notificationId");
+    if (notificationIdObject instanceof Number) {
+      notificationId = ((Number) notificationIdObject).intValue();
+    } else if (notificationIdObject instanceof String) {
+      try {
+        notificationId = Integer.parseInt((String) notificationIdObject);
+      } catch (NumberFormatException e) {
+        notificationId = LeanplumPushService.NOTIFICATION_ID;
+      }
+    } else if (message.containsKey(Keys.PUSH_MESSAGE_ID)) {
+      String value = message.getString(Keys.PUSH_MESSAGE_ID);
+      if (value != null) {
+        notificationId = value.hashCode();
+      }
+    }
+    notificationManager.notify(notificationId, builder.build());
+  }
+
+  static void openNotification(Context context, final Bundle notification) {
+    Log.d("Opening push notification action.");
+    if (notification == null) {
+      Log.i("Received null Bundle.");
+      return;
+    }
+
+    // Checks if open action is "Open URL" and there is some activity that can handle intent.
+    if (isActivityWithIntentStarted(context, notification)) {
+      return;
+    }
+
+    // Start activity.
+    Class<? extends Activity> callbackClass = LeanplumPushService.getCallbackClass();
+    boolean shouldStartActivity = true;
+    if (LeanplumActivityHelper.currentActivity != null &&
+        !LeanplumActivityHelper.isActivityPaused) {
+      if (callbackClass == null) {
+        shouldStartActivity = false;
+      } else if (callbackClass.isInstance(LeanplumActivityHelper.currentActivity)) {
+        shouldStartActivity = false;
+      }
+    }
+
+    if (shouldStartActivity) {
+      Intent actionIntent = getActionIntent(context);
+      actionIntent.putExtras(notification);
+      actionIntent.addFlags(
+          Intent.FLAG_ACTIVITY_CLEAR_TOP |
+              Intent.FLAG_ACTIVITY_NEW_TASK);
+      context.startActivity(actionIntent);
+    }
+
+    // Perform action.
+    LeanplumActivityHelper.queueActionUponActive(new VariablesChangedCallback() {
+      @Override
+      public void variablesChanged() {
+        try {
+          final String messageId = LeanplumPushService.getMessageId(notification);
+          final String actionName = Constants.Values.DEFAULT_PUSH_ACTION;
+
+          // Make sure content is available.
+          if (messageId != null) {
+            if (LeanplumPushService.areActionsEmbedded(notification)) {
+              Map<String, Object> args = new HashMap<>();
+              args.put(actionName, JsonConverter.fromJson(
+                  notification.getString(Keys.PUSH_MESSAGE_ACTION)));
+              ActionContext context = new ActionContext(
+                  ActionManager.PUSH_NOTIFICATION_ACTION_NAME, args, messageId);
+              context.preventRealtimeUpdating();
+              context.update();
+              context.runTrackedActionNamed(actionName);
+            } else {
+              Leanplum.addOnceVariablesChangedAndNoDownloadsPendingHandler(
+                  new VariablesChangedCallback() {
+                    @Override
+                    public void variablesChanged() {
+                      try {
+                        LeanplumPushService.requireMessageContent(messageId,
+                            new VariablesChangedCallback() {
+                              @Override
+                              public void variablesChanged() {
+                                try {
+                                  LeanplumInternal.performTrackedAction(actionName, messageId);
+                                } catch (Throwable t) {
+                                  Util.handleException(t);
+                                }
+                              }
+                            });
+                      } catch (Throwable t) {
+                        Util.handleException(t);
+                      }
+                    }
+                  });
+            }
+          }
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+    });
+  }
+
+  /**
+   * Return true if we found an activity to handle Intent and started it.
+   */
+  private static boolean isActivityWithIntentStarted(Context context, Bundle notification) {
+    String action = notification.getString(Keys.PUSH_MESSAGE_ACTION);
+    if (action != null && action.contains(OPEN_URL)) {
+      Intent deepLinkIntent = getDeepLinkIntent(notification);
+      if (deepLinkIntent != null && activityHasIntent(context, deepLinkIntent)) {
+        String messageId = LeanplumPushService.getMessageId(notification);
+        if (messageId != null) {
+          ActionContext actionContext = new ActionContext(
+              ActionManager.PUSH_NOTIFICATION_ACTION_NAME, null, messageId);
+          actionContext.track(OPEN_ACTION, 0.0, null);
+          context.startActivity(deepLinkIntent);
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Gets Intent from Push Notification Bundle.
+   */
+  private static Intent getDeepLinkIntent(Bundle notification) {
+    try {
+      String actionString = notification.getString(Keys.PUSH_MESSAGE_ACTION);
+      if (actionString != null) {
+        JSONObject openAction = new JSONObject(actionString);
+        Intent deepLinkIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(
+            openAction.getString(URL)));
+        deepLinkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return deepLinkIntent;
+      }
+    } catch (JSONException ignored) {
+    }
+    return null;
+  }
+
+  /**
+   * Checks if there is some activity that can handle intent.
+   */
+  private static Boolean activityHasIntent(Context context, Intent deepLinkIntent) {
+    List<ResolveInfo> resolveInfoList =
+        context.getPackageManager().queryIntentActivities(deepLinkIntent, 0);
+    if (resolveInfoList != null && !resolveInfoList.isEmpty()) {
+      for (ResolveInfo resolveInfo : resolveInfoList) {
+        if (resolveInfo != null && resolveInfo.activityInfo != null &&
+            resolveInfo.activityInfo.name != null) {
+          if (resolveInfo.activityInfo.name.contains(context.getPackageName())) {
+            // If url can be handled by current app - set package name to intent, so url will be
+            // open by current app. Skip chooser dialog.
+            deepLinkIntent.setPackage(resolveInfo.activityInfo.packageName);
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  private static Intent getActionIntent(Context context) {
+    Class<? extends Activity> callbackClass = LeanplumPushService.getCallbackClass();
+    if (callbackClass != null) {
+      return new Intent(context, callbackClass);
+    } else {
+      PackageManager pm = context.getPackageManager();
+      return pm.getLaunchIntentForPackage(context.getPackageName());
+    }
+  }
+
+  /**
+   * Unregisters the device from all GCM push notifications. You shouldn't need to call this method
+   * in production.
+   */
+  public static void unregister() {
+    try {
+      Intent unregisterIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
+      Context context = Leanplum.getContext();
+      unregisterIntent.putExtra("app", PendingIntent.getBroadcast(context, 0, new Intent(), 0));
+      unregisterIntent.setPackage("com.google.android.gms");
+      context.startService(unregisterIntent);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Registers the application with GCM servers asynchronously.
+   * <p>
+   * Stores the registration ID and app versionCode in the application's shared preferences.
+   */
+  private static void registerInBackground() {
+    Context context = Leanplum.getContext();
+    if (context == null) {
+      Log.e("Failed to register application with GCM/FCM. Your application context is not set.");
+      return;
+    }
+    Intent registerIntent = new Intent(context, LeanplumPushRegistrationService.class);
+    context.startService(registerIntent);
+  }
+
+  /**
+   * Register manually for Google Cloud Messaging services.
+   *
+   * @param token The registration ID token or the instance ID security token.
+   */
+  public static void setGcmRegistrationId(String token) {
+    new LeanplumManualProvider(Leanplum.getContext().getApplicationContext(), token);
+  }
+
+  /**
+   * Call this when Leanplum starts.
+   */
+  static void onStart() {
+    try {
+      if (Util.hasPlayServices()) {
+        initPushService();
+      } else {
+        Log.i("No valid Google Play Services APK found.");
+      }
+    } catch (LeanplumException e) {
+      Log.e("There was an error registering for push notifications.\n" +
+          Log.getStackTraceString(e));
+    }
+  }
+
+  private static void initPushService() {
+    if (!enableServices()) {
+      return;
+    }
+    provider = new LeanplumGcmProvider();
+    if (!provider.isInitialized() || !provider.isManifestSetUp()) {
+      return;
+    }
+    if (hasAppIDChanged(Request.appId())) {
+      provider.unregister();
+    }
+    registerInBackground();
+  }
+
+
+  /**
+   * Enable Leanplum GCM or FCM services.
+   *
+   * @return True if services was enabled.
+   */
+  private static boolean enableServices() {
+    Context context = Leanplum.getContext();
+    if (context == null) {
+      return false;
+    }
+
+    PackageManager packageManager = context.getPackageManager();
+    if (packageManager == null) {
+      return false;
+    }
+
+    if (isFirebaseEnabled) {
+      Class fcmListenerClass = getClassForName(LEANPLUM_PUSH_FCM_LISTENER_SERVICE_CLASS);
+      if (fcmListenerClass == null) {
+        return false;
+      }
+
+      if (!wasComponentEnabled(context, packageManager, fcmListenerClass)) {
+        if (!enableServiceAndStart(context, packageManager, PUSH_FIREBASE_MESSAGING_SERVICE_CLASS)
+            || !enableServiceAndStart(context, packageManager, fcmListenerClass)) {
+          return false;
+        }
+      }
+    } else {
+      Class gcmPushInstanceIDClass = getClassForName(LEANPLUM_PUSH_INSTANCE_ID_SERVICE_CLASS);
+      if (gcmPushInstanceIDClass == null) {
+        return false;
+      }
+
+      if (!wasComponentEnabled(context, packageManager, gcmPushInstanceIDClass)) {
+        if (!enableComponent(context, packageManager, LEANPLUM_PUSH_LISTENER_SERVICE_CLASS) ||
+            !enableComponent(context, packageManager, gcmPushInstanceIDClass) ||
+            !enableComponent(context, packageManager, GCM_RECEIVER_CLASS)) {
+          return false;
+        }
+
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Gets Class for name.
+   *
+   * @param className - class name.
+   * @return Class for provided class name.
+   */
+  private static Class getClassForName(String className) {
+    try {
+      return Class.forName(className);
+    } catch (Throwable t) {
+      if (isFirebaseEnabled) {
+        Log.e("Please compile FCM library.");
+      } else {
+        Log.e("Please compile GCM library.");
+      }
+      return null;
+    }
+  }
+
+  /**
+   * Enables and starts service for provided class name.
+   *
+   * @param context Current Context.
+   * @param packageManager Current PackageManager.
+   * @param className Name of Class that needs to be enabled and started.
+   * @return True if service was enabled and started.
+   */
+  private static boolean enableServiceAndStart(Context context, PackageManager packageManager,
+      String className) {
+    Class clazz;
+    try {
+      clazz = Class.forName(className);
+    } catch (Throwable t) {
+      return false;
+    }
+    return enableServiceAndStart(context, packageManager, clazz);
+  }
+
+  /**
+   * Enables and starts service for provided class name.
+   *
+   * @param context Current Context.
+   * @param packageManager Current PackageManager.
+   * @param clazz Class of service that needs to be enabled and started.
+   * @return True if service was enabled and started.
+   */
+  private static boolean enableServiceAndStart(Context context, PackageManager packageManager,
+      Class clazz) {
+    if (!enableComponent(context, packageManager, clazz)) {
+      return false;
+    }
+    try {
+      context.startService(new Intent(context, clazz));
+    } catch (Throwable t) {
+      Log.w("Could not start service " + clazz.getName());
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Enables component for provided class name.
+   *
+   * @param context Current Context.
+   * @param packageManager Current PackageManager.
+   * @param className Name of Class for enable.
+   * @return True if component was enabled.
+   */
+  private static boolean enableComponent(Context context, PackageManager packageManager,
+      String className) {
+    try {
+      Class clazz = Class.forName(className);
+      return enableComponent(context, packageManager, clazz);
+    } catch (Throwable t) {
+      return false;
+    }
+  }
+
+  /**
+   * Enables component for provided class.
+   *
+   * @param context Current Context.
+   * @param packageManager Current PackageManager.
+   * @param clazz Class for enable.
+   * @return True if component was enabled.
+   */
+  private static boolean enableComponent(Context context, PackageManager packageManager,
+      Class clazz) {
+    if (clazz == null || context == null || packageManager == null) {
+      return false;
+    }
+
+    try {
+      packageManager.setComponentEnabledSetting(new ComponentName(context, clazz),
+          PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
+    } catch (Throwable t) {
+      Log.w("Could not enable component " + clazz.getName());
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Checks if component for provided class enabled before.
+   *
+   * @param context Current Context.
+   * @param packageManager Current PackageManager.
+   * @param clazz Class for check.
+   * @return True if component was enabled before.
+   */
+  private static boolean wasComponentEnabled(Context context, PackageManager packageManager,
+      Class clazz) {
+    if (clazz == null || context == null || packageManager == null) {
+      return false;
+    }
+    int componentStatus = packageManager.getComponentEnabledSetting(new ComponentName(context,
+        clazz));
+    if (PackageManager.COMPONENT_ENABLED_STATE_DEFAULT == componentStatus ||
+        PackageManager.COMPONENT_ENABLED_STATE_DISABLED == componentStatus) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Check if current application id is different from stored one.
+   *
+   * @param currentAppId - Current application id.
+   * @return True if application id was stored before and doesn't equal to current.
+   */
+  private static boolean hasAppIDChanged(String currentAppId) {
+    if (currentAppId == null) {
+      return false;
+    }
+
+    Context context = Leanplum.getContext();
+    if (context == null) {
+      return false;
+    }
+
+    String storedAppId = SharedPreferencesUtil.getString(context, Constants.Defaults.LEANPLUM_PUSH,
+        Constants.Defaults.APP_ID);
+    if (!currentAppId.equals(storedAppId)) {
+      Log.v("Saving the application id in the shared preferences.");
+      SharedPreferencesUtil.setString(context, Constants.Defaults.LEANPLUM_PUSH,
+          Constants.Defaults.APP_ID, currentAppId);
+      // Check application id was stored before.
+      if (!SharedPreferencesUtil.DEFAULT_STRING_VALUE.equals(storedAppId)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumResources.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.DisplayMetrics;
+
+import com.leanplum.internal.CollectionUtil;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.FileManager;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.ResourceQualifiers;
+import com.leanplum.internal.ResourceQualifiers.Qualifier;
+import com.leanplum.internal.Util;
+import com.leanplum.internal.VarCache;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+// Description of resources.asrc file (we don't use this right nwo)
+// http://ekasiswanto.wordpress.com/2012/09/19/descriptions-of-androids-resources-arsc/
+
+public class LeanplumResources extends Resources {
+  public LeanplumResources(Resources base) {
+    super(base.getAssets(), base.getDisplayMetrics(), base.getConfiguration());
+  }
+
+  /* internal */
+  <T> Var<T> getOverrideResource(int id) {
+    try {
+      String name = getResourceEntryName(id);
+      String type = getResourceTypeName(id);
+      if (FileManager.resources == null) {
+        return null;
+      }
+      HashMap<String, Object> resourceValues = CollectionUtil.uncheckedCast(FileManager.resources
+          .objectForKeyPath());
+      Map<String, String> eligibleFolders = new HashMap<>();
+      synchronized (VarCache.valuesFromClient) {
+        for (String folder : resourceValues.keySet()) {
+          if (!folder.toLowerCase().startsWith(type)) {
+            continue;
+          }
+          HashMap<String, Object> files = CollectionUtil.uncheckedCast(resourceValues.get(folder));
+          String eligibleFile = null;
+          for (String filename : files.keySet()) {
+            String currentName = filename.replace("\\.", ".");
+            // Get filename without extension.
+            int dotPos = currentName.lastIndexOf('.');
+            if (dotPos >= 0) {
+              currentName = currentName.substring(0, dotPos);
+            }
+
+            if (currentName.equals(name)) {
+              eligibleFile = filename;
+            }
+          }
+          if (eligibleFile == null) {
+            continue;
+          }
+          eligibleFolders.put(folder, eligibleFile);
+        }
+      }
+
+      Map<String, ResourceQualifiers> folderQualifiers = new HashMap<>();
+      for (String folder : eligibleFolders.keySet()) {
+        folderQualifiers.put(folder, ResourceQualifiers.fromFolder(folder));
+      }
+
+      // 1. Eliminate qualifiers that contradict the device configuration.
+      // See http://developer.android.com/guide/topics/resources/providing-resources.html
+      Configuration config = getConfiguration();
+      DisplayMetrics display = getDisplayMetrics();
+      Set<String> matchedFolders = new HashSet<>();
+      for (String folder : eligibleFolders.keySet()) {
+        ResourceQualifiers qualifiers = folderQualifiers.get(folder);
+        for (Qualifier qualifier : qualifiers.qualifiers.keySet()) {
+          if (qualifier.getFilter().isMatch(
+              qualifiers.qualifiers.get(qualifier), config, display)) {
+            matchedFolders.add(folder);
+          }
+        }
+      }
+
+      // 2. Identify the next qualifier in the table (MCC first, then MNC,
+      // then language, and so on.
+      for (Qualifier qualifier : ResourceQualifiers.Qualifier.values()) {
+        Map<String, Object> betterMatchedFolders = new HashMap<>();
+        for (String folder : matchedFolders) {
+          ResourceQualifiers folderQualifier = folderQualifiers.get(folder);
+          Object qualifierValue = folderQualifier.qualifiers.get(qualifier);
+          if (qualifierValue != null) {
+            betterMatchedFolders.put(folder, qualifierValue);
+          }
+        }
+        betterMatchedFolders = qualifier.getFilter().bestMatch(
+            betterMatchedFolders, config, display);
+
+        // 3. Do any resource directories use this qualifier?
+        if (!betterMatchedFolders.isEmpty()) {
+          // Yes.
+          // 4. Eliminate directories that do not include this qualifier.
+          matchedFolders = betterMatchedFolders.keySet();
+        }
+      }
+
+      // Return result.
+      if (!eligibleFolders.isEmpty()) {
+        String folder = eligibleFolders.entrySet().iterator().next().getValue();
+        String varName = Constants.Values.RESOURCES_VARIABLE + "." + folder
+            + "." + eligibleFolders.get(folder);
+        return VarCache.getVariable(varName);
+      }
+    } catch (Exception e) {
+      Log.e("Error getting resource", e);
+    }
+    return null;
+  }
+
+  @Override
+  public Drawable getDrawable(int id) throws NotFoundException {
+    try {
+      Var<String> override = getOverrideResource(id);
+      if (override != null) {
+        int overrideResId = override.overrideResId();
+        if (overrideResId != 0) {
+          return super.getDrawable(overrideResId);
+        }
+        if (!override.stringValue.equals(override.defaultValue())) {
+          Drawable result = Drawable.createFromStream(override.stream(), override.fileValue());
+          if (result != null) {
+            return result;
+          }
+        }
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+    return super.getDrawable(id);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LeanplumUIEditor.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.Activity;
+
+/**
+ * Describes the API of the visual editor package.
+ */
+public interface LeanplumUIEditor {
+  /**
+   * Enable interface editing via Leanplum.com Visual Editor.
+   */
+  void allowInterfaceEditing(Boolean isDevelopmentModeEnabled);
+
+  /**
+   * Enables Interface editing for the desired activity.
+   *
+   * @param activity The activity to enable interface editing for.
+   */
+  void applyInterfaceEdits(Activity activity);
+
+  /**
+   * Sets the update flag to true.
+   */
+  void startUpdating();
+
+  /**
+   * Sets the update flag to false.
+   */
+  void stopUpdating();
+
+  /**
+   * Send an immediate update of the UI to the LP server.
+   */
+  void sendUpdate();
+
+  /**
+   * Send an update with given delay of the UI to the LP server.
+   */
+  void sendUpdateDelayed(int delay);
+
+  /**
+   * Send an update of the UI to the LP server, delayed by the default time.
+   */
+  void sendUpdateDelayedDefault();
+
+  /**
+   * Returns the current editor mode.
+   *
+   * @return The current editor mode.
+   */
+  LeanplumEditorMode getMode();
+
+  /**
+   * Sets the current editor mode.
+   *
+   * @param mode The editor mode to set.
+   */
+  void setMode(LeanplumEditorMode mode);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LocationManager.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Public interface to LocationManager. This is abstracted away so that the Google Play Services
+ * dependencies are constrained to {@link LocationManagerImplementation}.
+ *
+ * @author Andrew First
+ */
+public interface LocationManager {
+  void updateGeofencing();
+
+  void updateUserLocation();
+
+  void setRegionsData(Map<String, Object> regionData,
+      Set<String> foregroundRegionNames, Set<String> backgroundRegionNames);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/LocationManagerImplementation.java
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.location.Location;
+import android.os.Bundle;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
+import com.google.android.gms.location.Geofence;
+import com.google.android.gms.location.Geofence.Builder;
+import com.google.android.gms.location.LocationListener;
+import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.location.LocationServices;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.JsonConverter;
+import com.leanplum.internal.LeanplumInternal;
+import com.leanplum.internal.LeanplumMessageMatchFilter;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+class GeofenceStatus {
+  static final int UNKNOWN = 1;
+  static final int INSIDE = 2;
+  static final int OUTSIDE = 4;
+
+  static boolean shouldTriggerEnteredGeofence(Number currentStatus, Number newStatus) {
+    return ((currentStatus.intValue() == OUTSIDE || currentStatus.intValue() == UNKNOWN) &&
+        newStatus.intValue() == INSIDE);
+  }
+
+  static boolean shouldTriggerExitedGeofence(Number currentStatus, Number newStatus) {
+    return (currentStatus.intValue() == INSIDE &&
+        newStatus.intValue() == OUTSIDE);
+  }
+}
+
+/**
+ * Handles geo-fencing and sending user location.
+ *
+ * @author Atanas Dobrev
+ */
+class LocationManagerImplementation implements
+    GoogleApiClient.ConnectionCallbacks, OnConnectionFailedListener, LocationManager,
+    LocationListener {
+  private static final long LOCATION_UPDATE_INTERVAL = 7200000; // 2 hours in milliseconds.
+  private static final long LOCATION_REQUEST_INTERVAL = 60000; // a minute in milliseconds.
+  private static final double ACCURACY_THRESHOLD_GPS = 100; // 100m
+
+  private static final String PERMISSION = "android.permission.ACCESS_FINE_LOCATION";
+  private static final String METADATA = "com.google.android.gms.version";
+
+  private Map<String, Object> lastKnownState;
+  private Map<String, Object> stateBeforeBackground;
+  private List<Geofence> allGeofences;
+  private List<Geofence> backgroundGeofences;
+  private List<String> trackedGeofenceIds;
+  private boolean isInBackground;
+  private boolean isSendingLocation;
+  private Date lastLocationSentDate;
+  private LeanplumLocationAccuracyType lastLocationSentAccuracyType;
+
+  private GoogleApiClient googleApiClient;
+
+  private static LocationManagerImplementation instance;
+
+  public static synchronized LocationManager instance() {
+    if (instance == null) {
+      instance = new LocationManagerImplementation();
+    }
+    return instance;
+  }
+
+  private LocationManagerImplementation() {
+    trackedGeofenceIds = new ArrayList<>();
+    loadLastKnownRegionState();
+    isInBackground = Util.isInBackground();
+    isSendingLocation = false;
+    lastLocationSentAccuracyType = LeanplumLocationAccuracyType.IP;
+    // When an app starts LocationManager will be initialized. Update user location.
+    updateUserLocation();
+  }
+
+  @SuppressWarnings("unchecked")
+  public void setRegionsData(Map<String, Object> regionData,
+      Set<String> foregroundRegionNames, Set<String> backgroundRegionNames) {
+    if (!Util.hasPlayServices()) {
+      return;
+    }
+
+    allGeofences = new ArrayList<>();
+    backgroundGeofences = new ArrayList<>();
+    for (Map.Entry<String, Object> entry : regionData.entrySet()) {
+      String regionName = entry.getKey();
+      boolean isForeground = foregroundRegionNames.contains(regionName);
+      boolean isBackground = backgroundRegionNames.contains(regionName);
+      if (isForeground || isBackground) {
+        Geofence geofence = geofenceFromMap((Map<String, Object>) entry.getValue(),
+            regionName);
+        if (geofence != null) {
+          if (isBackground) {
+            backgroundGeofences.add(geofence);
+          }
+          allGeofences.add(geofence);
+          if (lastKnownState.get(geofence.getRequestId()) == null) {
+            lastKnownState.put(geofence.getRequestId(), GeofenceStatus.UNKNOWN);
+          }
+        }
+      }
+    }
+
+    updateGeofencing();
+  }
+
+  /**
+   * Starts location client if it has not been started, and calls requestLocation().
+   */
+  public void updateUserLocation() {
+    startLocationClient();
+    if (googleApiClient != null && googleApiClient.isConnected()) {
+      requestLocation();
+    }
+  }
+
+  /**
+   * Starts location client if it has not been started, and calls updateTrackedGeofences()
+   */
+  public void updateGeofencing() {
+    if (allGeofences != null && backgroundGeofences != null) {
+      startLocationClient();
+      if (googleApiClient != null && googleApiClient.isConnected()) {
+        updateTrackedGeofences();
+      }
+    }
+  }
+
+  private void loadLastKnownRegionState() {
+    if (lastKnownState != null) {
+      return;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(
+        "__leanplum__location", Context.MODE_PRIVATE);
+    String regionsStateJson = defaults.getString(Constants.Keys.REGION_STATE, null);
+    if (regionsStateJson == null) {
+      lastKnownState = new HashMap<>();
+    } else {
+      lastKnownState = JsonConverter.fromJson(regionsStateJson);
+    }
+  }
+
+  private void saveLastKnownRegionState() {
+    if (lastKnownState == null) {
+      return;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(
+        "__leanplum__location", Context.MODE_PRIVATE);
+    SharedPreferences.Editor editor = defaults.edit();
+    editor.putString(Constants.Keys.REGION_STATE, JsonConverter.toJson(lastKnownState));
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  private Geofence geofenceFromMap(Map<String, Object> regionData, String regionName) {
+    Number latitude = (Number) regionData.get("lat");
+    Number longitude = (Number) regionData.get("lon");
+    Number radius = (Number) regionData.get("radius");
+    Number version = (Number) regionData.get("version");
+    if (latitude == null) {
+      return null;
+    }
+    Builder geofenceBuilder = new Builder();
+    geofenceBuilder.setCircularRegion(latitude.floatValue(),
+        longitude.floatValue(), radius.floatValue());
+    geofenceBuilder.setRequestId(geofenceID(regionName, version.intValue()));
+    geofenceBuilder.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
+        Geofence.GEOFENCE_TRANSITION_EXIT);
+    geofenceBuilder.setExpirationDuration(Geofence.NEVER_EXPIRE);
+    return geofenceBuilder.build();
+  }
+
+  private String geofenceID(String regionName, Integer version) {
+    return "__leanplum" + regionName + "_" + version.toString();
+  }
+
+  private void startLocationClient() {
+    if (!isPermissionGranted() || !isMetaDataSet()) {
+      Log.i("You have to set the application meta data and location "
+          + "permission to use location services.");
+      return;
+    }
+    if (googleApiClient == null) {
+      googleApiClient = new GoogleApiClient.Builder(Leanplum.getContext())
+          .addApi(LocationServices.API)
+          .addConnectionCallbacks(this)
+          .addOnConnectionFailedListener(this)
+          .build();
+    }
+    if (!googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
+      googleApiClient.connect();
+    }
+  }
+
+  private boolean isPermissionGranted() {
+    Context context = Leanplum.getContext();
+    return context.checkCallingOrSelfPermission(PERMISSION) == PackageManager.PERMISSION_GRANTED;
+  }
+
+  private boolean isMetaDataSet() {
+    Context context = Leanplum.getContext();
+    try {
+      ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
+          context.getPackageName(), PackageManager.GET_META_DATA);
+      if (appInfo != null) {
+        if (appInfo.metaData != null) {
+          Object value = appInfo.metaData.get(METADATA);
+          if (value != null) {
+            return true;
+          }
+        }
+      }
+      return false;
+    } catch (NameNotFoundException e) {
+      return false;
+    }
+  }
+
+  private void updateTrackedGeofences() {
+    if (allGeofences == null || googleApiClient == null || !googleApiClient.isConnected()) {
+      return;
+    }
+    if (!isInBackground && Util.isInBackground()) {
+      stateBeforeBackground = new HashMap<>();
+      if (lastKnownState != null && lastKnownState.size() > 0) {
+        for (Map.Entry<String, Object> entry : lastKnownState.entrySet()) {
+          stateBeforeBackground.put(entry.getKey(), entry.getValue());
+        }
+      }
+    }
+    List<Geofence> toBeTrackedGeofences = getToBeTrackedGeofences();
+    if (trackedGeofenceIds.size() > 0) {
+      LocationServices.GeofencingApi.removeGeofences(googleApiClient, trackedGeofenceIds);
+    }
+    trackedGeofenceIds = new ArrayList<>();
+    if (toBeTrackedGeofences != null && toBeTrackedGeofences.size() > 0) {
+      LocationServices.GeofencingApi.addGeofences(
+          googleApiClient, toBeTrackedGeofences, getTransitionPendingIntent());
+      for (Geofence geofence : toBeTrackedGeofences) {
+        trackedGeofenceIds.add(geofence.getRequestId());
+        //TODO: stateBeforeBackground doesn't get persisted.
+        // If the app goes to the background and terminates, stateBeforeBackground will be reset.
+        if (isInBackground && !Util.isInBackground() && stateBeforeBackground != null
+            // This is triggered only for in-app messages, since backgroundGeofences are only for
+            // pushes.
+            // TODO(aleks): This would not work for in-app messages if we have the same geolocation
+            // triggering it, as a locally triggered push notification.
+            && !backgroundGeofences.contains(geofence)) {
+          Number lastStatus = (Number) stateBeforeBackground.get(geofence.getRequestId());
+          Number currentStatus = (Number) lastKnownState.get(geofence.getRequestId());
+          if (currentStatus != null && lastStatus != null) {
+            if (GeofenceStatus.shouldTriggerEnteredGeofence(lastStatus, currentStatus)) {
+              maybePerformActions(geofence, "enterRegion");
+            }
+            if (GeofenceStatus.shouldTriggerExitedGeofence(lastStatus, currentStatus)) {
+              maybePerformActions(geofence, "exitRegion");
+            }
+          }
+        }
+      }
+    }
+    if (isInBackground && !Util.isInBackground()) {
+      stateBeforeBackground = null;
+    }
+    isInBackground = Util.isInBackground();
+  }
+
+  private List<Geofence> getToBeTrackedGeofences() {
+    if (Util.isInBackground()) {
+      return backgroundGeofences;
+    } else {
+      return allGeofences;
+    }
+  }
+
+  void updateStatusForGeofences(List<Geofence> geofences, int transitionType) {
+    for (Geofence geofence : geofences) {
+      if (!trackedGeofenceIds.contains(geofence.getRequestId()) &&
+          geofence.getRequestId().startsWith("__leanplum")) {
+        ArrayList<String> geofencesToRemove = new ArrayList<>();
+        geofencesToRemove.add(geofence.getRequestId());
+        if (googleApiClient != null && googleApiClient.isConnected()) {
+          LocationServices.GeofencingApi.removeGeofences(googleApiClient, geofencesToRemove);
+        }
+        continue;
+      }
+      Number currentStatus = (Number) lastKnownState.get(geofence.getRequestId());
+      if (currentStatus != null) {
+        if (GeofenceStatus.shouldTriggerEnteredGeofence(currentStatus,
+            getStatusForTransitionType(transitionType))) {
+          maybePerformActions(geofence, "enterRegion");
+        }
+        if (GeofenceStatus.shouldTriggerExitedGeofence(currentStatus,
+            getStatusForTransitionType(transitionType))) {
+          maybePerformActions(geofence, "exitRegion");
+        }
+      }
+      lastKnownState.put(geofence.getRequestId(),
+          getStatusForTransitionType(transitionType));
+    }
+    saveLastKnownRegionState();
+  }
+
+  private void maybePerformActions(Geofence geofence, String action) {
+    String regionName = getRegionName(geofence.getRequestId());
+    if (regionName != null) {
+      int filter = Util.isInBackground() ?
+          LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_BACKGROUND :
+          LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_ALL;
+      LeanplumInternal.maybePerformActions(action, regionName, filter, null, null);
+    }
+  }
+
+  private int getStatusForTransitionType(int transitionType) {
+    if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER ||
+        transitionType == Geofence.GEOFENCE_TRANSITION_DWELL) {
+      return GeofenceStatus.INSIDE;
+    } else {
+      return GeofenceStatus.OUTSIDE;
+    }
+  }
+
+  private String getRegionName(String geofenceRequestId) {
+    if (geofenceRequestId.startsWith("__leanplum")) {
+      return geofenceRequestId.substring(10, geofenceRequestId.lastIndexOf("_"));
+    }
+    return null;
+  }
+
+  private PendingIntent getTransitionPendingIntent() {
+    Context context = Leanplum.getContext();
+    Intent intent = new Intent(context, ReceiveTransitionsIntentService.class);
+    return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+  }
+
+  @Override
+  public void onConnected(Bundle arg0) {
+    try {
+      updateTrackedGeofences();
+      requestLocation();
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  @Override
+  public void onConnectionSuspended(int i) {
+    // According to the Android documentation at
+    // https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks?hl=en
+    // GoogleApiClient will automatically attempt to restore the connection.
+  }
+
+  @Override
+  public void onConnectionFailed(
+      @SuppressWarnings("NullableProblems") ConnectionResult connectionResult) {
+  }
+
+  @Override
+  public void onLocationChanged(Location location) {
+    if (!location.hasAccuracy()) {
+      Log.e("Received a location with no accuracy.");
+      return;
+    }
+
+    // Currently, location segment treats GPS and CELL the same. In the future, we might want more
+    // distinction in the accuracy types. For example, a customer might want to send messages only
+    // to the ones with very accurate location information. We are assuming that it is from GPS if
+    // the location accuracy is less than or equal to |ACCURACY_THRESHOLD_GPS|.
+    LeanplumLocationAccuracyType locationAccuracyType =
+        location.getAccuracy() >= ACCURACY_THRESHOLD_GPS ?
+            LeanplumLocationAccuracyType.CELL : LeanplumLocationAccuracyType.GPS;
+
+    if (!isSendingLocation && needToSendLocation(locationAccuracyType)) {
+      try {
+        setUserAttributesForLocationUpdate(location, locationAccuracyType);
+      } catch (Throwable t) {
+        Util.handleException(t);
+      }
+    }
+
+    LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
+  }
+
+  /**
+   * Request location for user location update if googleApiClient is connected.
+   */
+  private void requestLocation() {
+    if (!Leanplum.isLocationCollectionEnabled() || googleApiClient == null
+        || !googleApiClient.isConnected()) {
+      return;
+    }
+    LocationRequest request = new LocationRequest();
+    // Although we set the interval as |LOCATION_REQUEST_INTERVAL|, we stop listening
+    // |onLocationChanged|. So we are essentially requesting location only once.
+    request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
+        .setInterval(LOCATION_REQUEST_INTERVAL)
+        .setFastestInterval(LOCATION_REQUEST_INTERVAL);
+    LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, request, this);
+  }
+
+  /**
+   * Checks whether it is needed to call setUserAttributes API for location update.
+   *
+   * @param newLocationAccuracyType LeanplumLocationAccuracyType of the new location.
+   * @return boolean Whether it is needed to call setUserAttributes API for location update.
+   */
+  private boolean needToSendLocation(LeanplumLocationAccuracyType newLocationAccuracyType) {
+    return (lastLocationSentDate == null
+        || (new Date().getTime() - lastLocationSentDate.getTime()) > LOCATION_UPDATE_INTERVAL
+        || lastLocationSentAccuracyType.value() < newLocationAccuracyType.value());
+  }
+
+  /**
+   * Call setUserAttributes API method for location update.
+   *
+   * @param location location collected from LocationServices
+   * @param locationAccuracyType LeanplumLocationAccuracyType of the location IP, CELL, or GPS
+   */
+  private void setUserAttributesForLocationUpdate(Location location,
+      final LeanplumLocationAccuracyType locationAccuracyType) {
+    isSendingLocation = true;
+    LeanplumInternal.setUserLocationAttribute(location, locationAccuracyType,
+        new LeanplumInternal.locationAttributeRequestsCallback() {
+          @Override
+          public void response(boolean success) {
+            isSendingLocation = false;
+            if (success) {
+              lastLocationSentAccuracyType = locationAccuracyType;
+              lastLocationSentDate = new Date();
+              Log.d("setUserAttributes with location is successfully called");
+            }
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/Newsfeed.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import com.leanplum.callbacks.InboxChangedCallback;
+import com.leanplum.callbacks.NewsfeedChangedCallback;
+
+/**
+ * Newsfeed class.
+ *
+ * @author Aleksandar Gyorev
+ */
+public class Newsfeed extends LeanplumInbox {
+
+  /**
+   * A private constructor, which prevents any other class from instantiating.
+   */
+  Newsfeed() {
+  }
+
+  /**
+   * Static 'getInstance' method.
+   */
+  static Newsfeed getInstance() {
+    return instance;
+  }
+
+  /**
+   * Add a callback for when the newsfeed receives new values from the server.
+   *
+   * @deprecated use {@link #addChangedHandler(InboxChangedCallback)} instead
+   */
+  @Deprecated
+  public void addNewsfeedChangedHandler(NewsfeedChangedCallback handler) {
+    super.addChangedHandler(handler);
+  }
+
+  /**
+   * Removes a newsfeed changed callback.
+   *
+   * @deprecated use {@link #removeChangedHandler(InboxChangedCallback)} instead
+   */
+  @Deprecated
+  public void removeNewsfeedChangedHandler(NewsfeedChangedCallback handler) {
+    super.removeChangedHandler(handler);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/NewsfeedMessage.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2015, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.Request;
+import com.leanplum.internal.Util;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * NewsfeedMessage class.
+ *
+ * @author Aleksandar Gyorev
+ */
+public abstract class NewsfeedMessage {
+  private String messageId;
+  private Long deliveryTimestamp;
+  private Long expirationTimestamp;
+  private boolean isRead;
+  private ActionContext context;
+
+  NewsfeedMessage(String messageId, Long deliveryTimestamp, Long expirationTimestamp,
+      boolean isRead, ActionContext context) {
+    this.messageId = messageId;
+    this.deliveryTimestamp = deliveryTimestamp;
+    this.expirationTimestamp = expirationTimestamp;
+    this.isRead = isRead;
+    this.context = context;
+  }
+
+  Map<String, Object> toJsonMap() {
+    Map<String, Object> map = new HashMap<>();
+    map.put(Constants.Keys.DELIVERY_TIMESTAMP, this.deliveryTimestamp);
+    map.put(Constants.Keys.EXPIRATION_TIMESTAMP, this.expirationTimestamp);
+    map.put(Constants.Keys.MESSAGE_DATA, this.actionArgs());
+    map.put(Constants.Keys.IS_READ, this.isRead());
+    return map;
+  }
+
+  Map<String, Object> actionArgs() {
+    return context.getArgs();
+  }
+
+  void setIsRead(boolean isRead) {
+    this.isRead = isRead;
+  }
+
+  boolean isActive() {
+    if (expirationTimestamp == null) {
+      return true;
+    }
+
+    Date now = new Date();
+    return now.before(new Date(expirationTimestamp));
+  }
+
+  static boolean isValidMessageId(String messageId) {
+    return messageId.split("##").length == 2;
+  }
+
+  ActionContext getContext() {
+    return context;
+  }
+
+  /**
+   * Returns the message identifier of the newsfeed message.
+   *
+   * @deprecated As of release 1.3.0, replaced by {@link #getMessageId()}
+   */
+  @Deprecated
+  public String messageId() {
+    return getMessageId();
+  }
+
+  /**
+   * Returns the message identifier of the newsfeed message.
+   */
+  public String getMessageId() {
+    return messageId;
+  }
+
+  /**
+   * Returns the title of the newsfeed message.
+   *
+   * @deprecated As of release 1.3.0, replaced by {@link #getTitle()}
+   */
+  @Deprecated
+  public String title() {
+    return getTitle();
+  }
+
+  /**
+   * Returns the title of the newsfeed message.
+   */
+  public String getTitle() {
+    return context.stringNamed(Constants.Keys.TITLE);
+  }
+
+  /**
+   * Returns the subtitle of the newsfeed message.
+   *
+   * @deprecated As of release 1.3.0, replaced by {@link #getSubtitle()}
+   */
+  @Deprecated
+  public String subtitle() {
+    return getSubtitle();
+  }
+
+  /**
+   * Returns the subtitle of the newsfeed message.
+   */
+  public String getSubtitle() {
+    return context.stringNamed(Constants.Keys.SUBTITLE);
+  }
+
+  /**
+   * Returns the delivery timestamp of the newsfeed message.
+   *
+   * @deprecated As of release 1.3.0, replaced by {@link #getDeliveryTimestamp()}
+   */
+  @Deprecated
+  public Date deliveryTimestamp() {
+    return getDeliveryTimestamp();
+  }
+
+  /**
+   * Returns the delivery timestamp of the newsfeed message.
+   */
+  public Date getDeliveryTimestamp() {
+    return new Date(deliveryTimestamp);
+  }
+
+  /**
+   * Return the expiration timestamp of the newsfeed message.
+   *
+   * @deprecated As of release 1.3.0, replaced by {@link #getExpirationTimestamp()}
+   */
+  @Deprecated
+  public Date expirationTimestamp() {
+    return getExpirationTimestamp();
+  }
+
+  /**
+   * Return the expiration timestamp of the newsfeed message.
+   */
+  public Date getExpirationTimestamp() {
+    if (expirationTimestamp == null) {
+      return null;
+    }
+    return new Date(expirationTimestamp);
+  }
+
+  /**
+   * Returns 'true' if the newsfeed message is read.
+   */
+  public boolean isRead() {
+    return isRead;
+  }
+
+  /**
+   * Read the newsfeed message, marking it as read and invoking its open action.
+   */
+  public void read() {
+    try {
+      if (Constants.isNoop()) {
+        return;
+      }
+
+      if (!this.isRead) {
+        setIsRead(true);
+
+        int unreadCount = Newsfeed.getInstance().unreadCount() - 1;
+        Newsfeed.getInstance().updateUnreadCount(unreadCount);
+
+        Map<String, Object> params = new HashMap<>();
+        params.put(Constants.Params.INBOX_MESSAGE_ID, messageId);
+        Request req = Request.post(Constants.Methods.MARK_INBOX_MESSAGE_AS_READ,
+            params);
+        req.send();
+      }
+      this.context.runTrackedActionNamed(Constants.Values.DEFAULT_PUSH_ACTION);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Remove the newsfeed message from the newsfeed.
+   */
+  public void remove() {
+    try {
+      Newsfeed.getInstance().removeMessage(messageId);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/ReceiveTransitionsIntentService.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+import com.google.android.gms.location.Geofence;
+import com.google.android.gms.location.GeofencingEvent;
+import com.leanplum.internal.ActionManager;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.Util;
+
+import java.util.List;
+
+/**
+ * Receives the geo-fence state changes.
+ *
+ * @author Atanas Dobrev
+ */
+public class ReceiveTransitionsIntentService extends IntentService {
+  public ReceiveTransitionsIntentService() {
+    super("ReceiveTransitionsIntentService");
+  }
+
+  @Override
+  protected void onHandleIntent(Intent intent) {
+    try {
+      GeofencingEvent event = GeofencingEvent.fromIntent(intent);
+      if (event.hasError()) {
+        int errorCode = event.getErrorCode();
+        Log.d("Location Client Error with code: " + errorCode);
+      } else {
+        int transitionType = event.getGeofenceTransition();
+        List<Geofence> triggeredGeofences = event.getTriggeringGeofences();
+        if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER ||
+            transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
+          LocationManagerImplementation locationManager = (LocationManagerImplementation)
+              ActionManager.getLocationManager();
+          if (locationManager != null) {
+            locationManager.updateStatusForGeofences(triggeredGeofences, transitionType);
+          }
+        }
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/UIEditorBridge.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import com.leanplum.internal.FileManager;
+import com.leanplum.internal.Socket;
+import com.leanplum.internal.Util;
+import com.leanplum.internal.VarCache;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Bridge class for the UI editor package to access LP internal methods.
+ *
+ * @author Ben Marten
+ */
+public class UIEditorBridge {
+  public static void setInterfaceUpdateBlock(CacheUpdateBlock block) {
+    VarCache.onInterfaceUpdate(block);
+  }
+
+  public static void setEventsUpdateBlock(CacheUpdateBlock block) {
+    VarCache.onEventsUpdate(block);
+  }
+
+  public static List<Map<String, Object>> getUpdateRuleDiffs() {
+    return VarCache.getUpdateRuleDiffs();
+  }
+
+  public static List<Map<String, Object>> getEventRuleDiffs() {
+    return VarCache.getEventRuleDiffs();
+  }
+
+  public static boolean isSocketConnected() {
+    return Socket.getInstance() != null && Socket.getInstance().isConnected();
+  }
+
+  public static <T> void socketSendEvent(String eventName, Map<String, T> data) {
+    if (Socket.getInstance() != null && eventName != null) {
+      Socket.getInstance().sendEvent(eventName, data);
+    }
+  }
+
+  public static String fileRelativeToDocuments(String path) {
+    return FileManager.fileRelativeToDocuments(path);
+  }
+
+  public static void handleException(Throwable t) {
+    Util.handleException(t);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/Var.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.text.TextUtils;
+
+import com.leanplum.callbacks.VariableCallback;
+import com.leanplum.internal.Constants;
+import com.leanplum.internal.FileManager;
+import com.leanplum.internal.FileManager.DownloadFileResult;
+import com.leanplum.internal.LeanplumInternal;
+import com.leanplum.internal.Log;
+import com.leanplum.internal.OsHandler;
+import com.leanplum.internal.Util;
+import com.leanplum.internal.VarCache;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Leanplum variable.
+ *
+ * @param <T> Type of the variable. Can be Boolean, Byte, Short, Integer, Long, Float, Double,
+ * Character, String, List, or Map. You may nest lists and maps arbitrarily.
+ * @author Andrew First
+ */
+public class Var<T> {
+  private String name;
+  private String[] nameComponents;
+  public String stringValue;
+  private Double numberValue;
+  private T defaultValue;
+  private T value;
+  private String kind;
+  private final List<VariableCallback<T>> fileReadyHandlers = new ArrayList<>();
+  private final List<VariableCallback<T>> valueChangedHandlers = new ArrayList<>();
+  private boolean fileIsPending;
+  private boolean hadStarted;
+  private boolean isAsset;
+  public boolean isResource;
+  private int size;
+  private String hash;
+  private byte[] data;
+  private boolean valueIsInAssets = false;
+  private boolean isInternal;
+  private int overrideResId;
+  private static boolean printedCallbackWarning;
+
+  private void warnIfNotStarted() {
+    if (!isInternal && !Leanplum.hasStarted() && !printedCallbackWarning) {
+      Log.w("Leanplum hasn't finished retrieving values from the server. "
+          + "You should use a callback to make sure the value for '" + name +
+          "' is ready. Otherwise, your app may not use the most up-to-date value.");
+      printedCallbackWarning = true;
+    }
+  }
+
+  private interface VarInitializer<T> {
+    void init(Var<T> var);
+  }
+
+  private static <T> Var<T> define(
+      String name, T defaultValue, String kind, VarInitializer<T> initializer) {
+    if (TextUtils.isEmpty(name)) {
+      Log.e("Empty name parameter provided.");
+      return null;
+    }
+    Var<T> existing = VarCache.getVariable(name);
+    if (existing != null) {
+      return existing;
+    }
+    if (LeanplumInternal.hasCalledStart() &&
+        !name.startsWith(Constants.Values.RESOURCES_VARIABLE)) {
+      Log.w("You should not create new variables after calling start (name=" + name + ")");
+    }
+    Var<T> var = new Var<>();
+    try {
+      var.name = name;
+      var.nameComponents = VarCache.getNameComponents(name);
+      var.defaultValue = defaultValue;
+      var.value = defaultValue;
+      var.kind = kind;
+      if (name.startsWith(Constants.Values.RESOURCES_VARIABLE)) {
+        var.isInternal = true;
+      }
+      if (initializer != null) {
+        initializer.init(var);
+      }
+      var.cacheComputedValues();
+      VarCache.registerVariable(var);
+      if (Constants.Kinds.FILE.equals(var.kind)) {
+        VarCache.registerFile(var.stringValue,
+            var.defaultValue() == null ? null : var.defaultValue().toString(),
+            var.defaultStream(), var.isResource, var.hash, var.size);
+      }
+      var.update();
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+    return var;
+  }
+
+  /**
+   * Defines a new variable with a default value.
+   *
+   * @param name Name of the variable.
+   * @param defaultValue Default value of the variable. Can't be null.
+   */
+  public static <T> Var<T> define(String name, T defaultValue) {
+    return define(name, defaultValue, VarCache.kindFromValue(defaultValue), null);
+  }
+
+  /**
+   * Defines a variable with kind. Can be Boolean, Byte, Short, Integer, Long, Float, Double,
+   * Character, String, List, or Map. You may nest lists and maps arbitrarily.
+   *
+   * @param name Name of the variable.
+   * @param defaultValue Default value.
+   * @param kind Kind of the variable.
+   * @param <T> Boolean, Byte, Short, Integer, Long, Float, Double, Character, String, List, or
+   * Map.
+   * @return Initialized variable.
+   */
+  public static <T> Var<T> define(String name, T defaultValue, String kind) {
+    return define(name, defaultValue, kind, null);
+  }
+
+  /**
+   * Defines a color.
+   *
+   * @param name Name of the variable
+   * @param defaultValue Default value.
+   * @return Initialized variable.
+   */
+  @SuppressWarnings("WeakerAccess")
+  public static Var<Integer> defineColor(String name, int defaultValue) {
+    return define(name, defaultValue, Constants.Kinds.COLOR, null);
+  }
+
+  /**
+   * Defines a variable for a file.
+   *
+   * @param name Name of the variable.
+   * @param defaultFilename Default filename.
+   * @return Initialized variable.
+   */
+  public static Var<String> defineFile(String name, String defaultFilename) {
+    return define(name, defaultFilename, Constants.Kinds.FILE, null);
+  }
+
+  /**
+   * Defines a variable for a file located in assets directory.
+   *
+   * @param name Name of the variable.
+   * @param defaultFilename Default filename.
+   * @return Initialized variable.
+   */
+  public static Var<String> defineAsset(String name, String defaultFilename) {
+    return define(name, defaultFilename, Constants.Kinds.FILE, new VarInitializer<String>() {
+      @Override
+      public void init(Var<String> var) {
+        var.isAsset = true;
+      }
+    });
+  }
+
+  /**
+   * Define a resource variable with default value referencing id of the file located in
+   * res/ directory.
+   *
+   * @param name Name of the variable.
+   * @param resId Resource id of any file located in res/ directory.
+   * @return Initalized variable.
+   */
+  public static Var<String> defineResource(String name, int resId) {
+    String resourceName = Util.generateResourceNameFromId(resId);
+    return define(name, resourceName, Constants.Kinds.FILE, new VarInitializer<String>() {
+      @Override
+      public void init(Var<String> var) {
+        var.isResource = true;
+      }
+    });
+  }
+
+  /**
+   * Defines a resource.
+   *
+   * @param name Name of the variable.
+   * @param defaultFilename Default filename.
+   * @param size Size of the data.
+   * @param hash Hash of the data.
+   * @param data Data.
+   * @return Initalized variable.
+   */
+  public static Var<String> defineResource(String name, String defaultFilename,
+      final int size, final String hash, final byte[] data) {
+    return define(name, defaultFilename, Constants.Kinds.FILE, new VarInitializer<String>() {
+      @Override
+      public void init(Var<String> var) {
+        var.isResource = true;
+        var.size = size;
+        var.hash = hash;
+        var.data = data;
+      }
+    });
+  }
+
+  protected Var() {
+  }
+
+  /**
+   * Gets name of the variable.
+   *
+   * @return Varaible name.
+   */
+  public String name() {
+    return name;
+  }
+
+  /**
+   * Gets name components of a variable.
+   *
+   * @return Name components.
+   */
+  public String[] nameComponents() {
+    return nameComponents;
+  }
+
+  /**
+   * Gets the kind of a variable.
+   *
+   * @return Kind of a variable.
+   */
+  public String kind() {
+    return kind;
+  }
+
+  /**
+   * Gets variable default value.
+   *
+   * @return Default value.
+   */
+  public T defaultValue() {
+    return defaultValue;
+  }
+
+  /**
+   * Get variable value.
+   *
+   * @return Value.
+   */
+  public T value() {
+    warnIfNotStarted();
+    return value;
+  }
+
+  /**
+   * Gets overridden resource id for variable.
+   *
+   * @return Id of the overridden resource.
+   */
+  public int overrideResId() {
+    return overrideResId;
+  }
+
+  /**
+   * Sets overridden resource id for a variable.
+   *
+   * @param resId Resource id.
+   */
+  public void setOverrideResId(int resId) {
+    overrideResId = resId;
+  }
+
+  @SuppressWarnings("unchecked")
+  private void cacheComputedValues() {
+    if (value instanceof String) {
+      stringValue = (String) value;
+      try {
+        numberValue = Double.valueOf(stringValue);
+      } catch (NumberFormatException e) {
+        numberValue = null;
+      }
+    } else if (value instanceof Number) {
+      stringValue = "" + value;
+      numberValue = ((Number) value).doubleValue();
+      if (defaultValue instanceof Byte) {
+        value = (T) (Byte) ((Number) value).byteValue();
+      } else if (defaultValue instanceof Short) {
+        value = (T) (Short) ((Number) value).shortValue();
+      } else if (defaultValue instanceof Integer) {
+        value = (T) (Integer) ((Number) value).intValue();
+      } else if (defaultValue instanceof Long) {
+        value = (T) (Long) ((Number) value).longValue();
+      } else if (defaultValue instanceof Float) {
+        value = (T) (Float) ((Number) value).floatValue();
+      } else if (defaultValue instanceof Double) {
+        value = (T) (Double) ((Number) value).doubleValue();
+      } else if (defaultValue instanceof Character) {
+        value = (T) (Character) (char) ((Number) value).intValue();
+      }
+    } else if (value != null &&
+        !(value instanceof Iterable<?>) && !(value instanceof Map<?, ?>)) {
+      stringValue = value.toString();
+      numberValue = null;
+    } else {
+      stringValue = null;
+      numberValue = null;
+    }
+  }
+
+  /**
+   * Updates variable with values from server.
+   */
+  public void update() {
+    // TODO: Clean up memory for resource variables.
+    //data = null;
+
+    T oldValue = value;
+    value = VarCache.getMergedValueFromComponentArray(nameComponents);
+    if (value == null && oldValue == null) {
+      return;
+    }
+    if (value != null && oldValue != null && value.equals(oldValue) && hadStarted) {
+      return;
+    }
+    cacheComputedValues();
+
+    if (VarCache.silent() && name.startsWith(Constants.Values.RESOURCES_VARIABLE)
+        && Constants.Kinds.FILE.equals(kind) && !fileIsPending) {
+      triggerFileIsReady();
+    }
+
+    if (VarCache.silent()) {
+      return;
+    }
+
+    if (Leanplum.hasStarted()) {
+      triggerValueChanged();
+    }
+
+    // Check if file exists, otherwise we need to download it.
+    if (Constants.Kinds.FILE.equals(kind)) {
+      if (!Constants.isNoop()) {
+        DownloadFileResult result = FileManager.maybeDownloadFile(
+            isResource, stringValue, (String) defaultValue, null,
+            new Runnable() {
+              @Override
+              public void run() {
+                triggerFileIsReady();
+              }
+            });
+        valueIsInAssets = false;
+        if (result == DownloadFileResult.DOWNLOADING) {
+          fileIsPending = true;
+        } else if (result == DownloadFileResult.EXISTS_IN_ASSETS) {
+          valueIsInAssets = true;
+        }
+      }
+      if (Leanplum.hasStarted() && !fileIsPending) {
+        triggerFileIsReady();
+      }
+    }
+
+    if (Leanplum.hasStarted()) {
+      hadStarted = true;
+    }
+  }
+
+  private void triggerValueChanged() {
+    synchronized (valueChangedHandlers) {
+      for (VariableCallback<T> callback : valueChangedHandlers) {
+        callback.setVariable(this);
+        OsHandler.getInstance().post(callback);
+      }
+    }
+  }
+
+  /**
+   * Adds value changed handler for a given variable.
+   *
+   * @param handler Handler to add.
+   */
+  public void addValueChangedHandler(VariableCallback<T> handler) {
+    if (handler == null) {
+      Log.e("Invalid handler parameter provided.");
+      return;
+    }
+
+    synchronized (valueChangedHandlers) {
+      valueChangedHandlers.add(handler);
+    }
+    if (Leanplum.hasStarted()) {
+      handler.handle(this);
+    }
+  }
+
+  /**
+   * Removes value changed handler for a given variable.
+   *
+   * @param handler Handler to be removed.
+   */
+  public void removeValueChangedHandler(VariableCallback<T> handler) {
+    synchronized (valueChangedHandlers) {
+      valueChangedHandlers.remove(handler);
+    }
+  }
+
+  private void triggerFileIsReady() {
+    synchronized (fileReadyHandlers) {
+      fileIsPending = false;
+      for (VariableCallback<T> callback : fileReadyHandlers) {
+        callback.setVariable(this);
+        OsHandler.getInstance().post(callback);
+      }
+    }
+  }
+
+  /**
+   * Adds file ready handler for a given variable.
+   *
+   * @param handler Handler to add.
+   */
+  public void addFileReadyHandler(VariableCallback<T> handler) {
+    if (handler == null) {
+      Log.e("Invalid handler parameter provided.");
+      return;
+    }
+    synchronized (fileReadyHandlers) {
+      fileReadyHandlers.add(handler);
+    }
+    if (Leanplum.hasStarted() && !fileIsPending) {
+      handler.handle(this);
+    }
+  }
+
+  /**
+   * Removes file ready handler for a given variable.
+   *
+   * @param handler Handler to be removed.
+   */
+  public void removeFileReadyHandler(VariableCallback<T> handler) {
+    if (handler == null) {
+      Log.e("Invalid handler parameter provided.");
+      return;
+    }
+    synchronized (fileReadyHandlers) {
+      fileReadyHandlers.remove(handler);
+    }
+  }
+
+  /**
+   * Returns file value for variable initialized as file/asset/resource.
+   *
+   * @return String representing file value.
+   */
+  public String fileValue() {
+    try {
+      warnIfNotStarted();
+      if (Constants.Kinds.FILE.equals(kind)) {
+        return FileManager.fileValue(stringValue, (String) defaultValue, valueIsInAssets);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+    return null;
+  }
+
+  /**
+   * Returns object for specified key path.
+   *
+   * @param keys Keys to look for.
+   * @return Object if found, null otherwise.
+   */
+  @SuppressWarnings("WeakerAccess") // Used by Air SDK.
+  public Object objectForKeyPath(Object... keys) {
+    try {
+      warnIfNotStarted();
+      List<Object> components = new ArrayList<>();
+      Collections.addAll(components, nameComponents);
+      if (keys != null && keys.length > 0) {
+        Collections.addAll(components, keys);
+      }
+      return VarCache.getMergedValueFromComponentArray(
+          components.toArray(new Object[components.size()]));
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return null;
+    }
+  }
+
+  /**
+   * Returns a number of elements contained in a List variable.
+   *
+   * @return Elements count or 0 if Variable is not a List.
+   */
+  @Deprecated
+  public int count() {
+    return countInternal();
+  }
+
+  /**
+   * Returns a number of elements contained in a List variable.
+   *
+   * @return Elements count or 0 if Variable is not a List.
+   */
+  private int countInternal() {
+    try {
+      warnIfNotStarted();
+      Object result = VarCache.getMergedValueFromComponentArray(nameComponents);
+      if (result instanceof List) {
+        return ((List<?>) result).size();
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return 0;
+    }
+    LeanplumInternal.maybeThrowException(new UnsupportedOperationException(
+        "This variable is not a list."));
+    return 0;
+  }
+
+  /**
+   * Gets a value from a variable initialized as Number.
+   *
+   * @return A Number value.
+   */
+  @Deprecated
+  public Number numberValue() {
+    return numberValueInternal();
+  }
+
+  /**
+   * Gets a value from a variable initialized as Number.
+   *
+   * @return A Number value.
+   */
+  private Number numberValueInternal() {
+    warnIfNotStarted();
+    return numberValue;
+  }
+
+  /**
+   * Gets a value from a variable initialized as String.
+   *
+   * @return A String value.
+   */
+  public String stringValue() {
+    warnIfNotStarted();
+    return stringValue;
+  }
+
+  /**
+   * Creates and returns InputStream for overridden file/asset/resource variable.
+   * Caller is responsible for closing it properly to avoid leaking resources.
+   *
+   * @return InputStream for a file.
+   */
+  public InputStream stream() {
+    try {
+      if (!Constants.Kinds.FILE.equals(kind)) {
+        return null;
+      }
+      warnIfNotStarted();
+      InputStream stream = FileManager.stream(isResource, isAsset, valueIsInAssets,
+          fileValue(), (String) defaultValue, data);
+      if (stream == null) {
+        return defaultStream();
+      }
+      return stream;
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return null;
+    }
+  }
+
+  /**
+   * Creates and returns InputStream for default file/asset/resource variable.
+   * Caller is responsible for closing it properly to avoid leaking resources.
+   *
+   * @return InputStream for a file.
+   */
+  private InputStream defaultStream() {
+    try {
+      if (!Constants.Kinds.FILE.equals(kind)) {
+        return null;
+      }
+      return FileManager.stream(isResource, isAsset, valueIsInAssets,
+          (String) defaultValue, (String) defaultValue, data);
+    } catch (Throwable t) {
+      Util.handleException(t);
+      return null;
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "Var(" + name + ")=" + value;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumAccountAuthenticatorActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.accounts.AccountAuthenticatorActivity;
+import android.annotation.SuppressLint;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumAccountAuthenticatorActivity extends AccountAuthenticatorActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumActionBarActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.content.res.Resources;
+import android.support.v7.app.ActionBarActivity;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+@SuppressWarnings("deprecation")
+public class LeanplumActionBarActivity extends ActionBarActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.app.Activity;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+public abstract class LeanplumActivity extends Activity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumActivityGroup.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.app.ActivityGroup;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+@SuppressWarnings("deprecation")
+public class LeanplumActivityGroup extends ActivityGroup {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumAliasActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.app.AliasActivity;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumAliasActivity extends AliasActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumAppCompatActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.content.res.Resources;
+import android.support.v7.app.AppCompatActivity;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumAppCompatActivity extends AppCompatActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumExpandableListActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.app.ExpandableListActivity;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumExpandableListActivity extends ExpandableListActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumFragmentActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.content.res.Resources;
+import android.support.v4.app.FragmentActivity;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+public abstract class LeanplumFragmentActivity extends FragmentActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumLauncherActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.app.LauncherActivity;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumLauncherActivity extends LauncherActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumListActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.app.ListActivity;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumListActivity extends ListActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumNativeActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.app.NativeActivity;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumNativeActivity extends NativeActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumPreferenceActivity.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.content.res.Resources;
+import android.preference.PreferenceActivity;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+public class LeanplumPreferenceActivity extends PreferenceActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/activities/LeanplumTabActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.activities;
+
+import android.annotation.SuppressLint;
+import android.app.TabActivity;
+import android.content.res.Resources;
+
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+
+@SuppressLint("Registered")
+@SuppressWarnings("deprecation")
+public class LeanplumTabActivity extends TabActivity {
+  private LeanplumActivityHelper helper;
+
+  private LeanplumActivityHelper getHelper() {
+    if (helper == null) {
+      helper = new LeanplumActivityHelper(this);
+    }
+    return helper;
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    getHelper().onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    super.onStop();
+    getHelper().onStop();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    getHelper().onResume();
+  }
+
+  @Override
+  public Resources getResources() {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      return super.getResources();
+    }
+    return getHelper().getLeanplumResources(super.getResources());
+  }
+
+  @Override
+  public void setContentView(final int layoutResID) {
+    if (Leanplum.isTestModeEnabled() || !Leanplum.isResourceSyncingEnabled()) {
+      super.setContentView(layoutResID);
+      return;
+    }
+    getHelper().setContentView(layoutResID);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/annotations/File.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Leanplum variable annotation. Use this to make this variable changeable from the Leanplum
+ * dashboard.
+ *
+ * @author Andrew First
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface File {
+  /**
+   * (Optional). The group to put the variable in. Use "." to nest groups.
+   */
+  String group() default "";
+
+  /**
+   * (Optional). The name of the variable. If not set, then uses the actual name of the field.
+   */
+  String name() default "";
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/annotations/Parser.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.annotations;
+
+import android.text.TextUtils;
+
+import com.leanplum.Var;
+import com.leanplum.callbacks.VariableCallback;
+import com.leanplum.internal.Log;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Parses Leanplum annotations.
+ *
+ * @author Andrew First
+ */
+public class Parser {
+  private static <T> void defineVariable(
+      final Object instance,
+      String name,
+      T value,
+      String kind,
+      final Field field) {
+    final Var<T> var = Var.define(name, value, kind);
+    final boolean hasInstance = instance != null;
+    final WeakReference<Object> weakInstance = new WeakReference<>(instance);
+    var.addValueChangedHandler(new VariableCallback<T>() {
+      @Override
+      public void handle(Var<T> variable) {
+        Object instance = weakInstance.get();
+        if ((hasInstance && instance == null) || field == null) {
+          var.removeValueChangedHandler(this);
+          return;
+        }
+        try {
+          boolean accessible = field.isAccessible();
+          if (!accessible) {
+            field.setAccessible(true);
+          }
+          field.set(instance, var.value());
+          if (!accessible) {
+            field.setAccessible(false);
+          }
+        } catch (IllegalArgumentException e) {
+          Log.e("Leanplum", "Invalid value " + var.value() +
+              " for field " + var.name(), e);
+        } catch (IllegalAccessException e) {
+          Log.e("Leanplum", "Error setting value for field " + var.name(), e);
+        }
+      }
+    });
+  }
+
+  private static void defineFileVariable(
+      final Object instance,
+      String name,
+      String value,
+      final Field field) {
+    final Var<String> var = Var.defineFile(name, value);
+    final boolean hasInstance = instance != null;
+    final WeakReference<Object> weakInstance = new WeakReference<>(instance);
+    var.addFileReadyHandler(new VariableCallback<String>() {
+      @Override
+      public void handle(Var<String> variable) {
+        Object instance = weakInstance.get();
+        if ((hasInstance && instance == null) || field == null) {
+          var.removeFileReadyHandler(this);
+          return;
+        }
+        try {
+          boolean accessible = field.isAccessible();
+          if (!accessible) {
+            field.setAccessible(true);
+          }
+          field.set(instance, var.fileValue());
+          if (!accessible) {
+            field.setAccessible(false);
+          }
+        } catch (IllegalArgumentException e) {
+          Log.e("Leanplum", "Invalid value " + var.value() +
+              " for field " + var.name(), e);
+        } catch (IllegalAccessException e) {
+          Log.e("Leanplum", "Error setting value for field " + var.name(), e);
+        }
+      }
+    });
+  }
+
+  /**
+   * Parses Leanplum annotations for all given object instances.
+   */
+  public static void parseVariables(Object... instances) {
+    try {
+      for (Object instance : instances) {
+        parseVariablesHelper(instance, instance.getClass());
+      }
+    } catch (Throwable t) {
+      Log.e("Leanplum", "Error parsing variables", t);
+    }
+  }
+
+  /**
+   * Parses Leanplum annotations for all given classes.
+   */
+  public static void parseVariablesForClasses(Class<?>... classes) {
+    try {
+      for (Class<?> clazz : classes) {
+        parseVariablesHelper(null, clazz);
+      }
+    } catch (Throwable t) {
+      Log.e("Leanplum", "Error parsing variables", t);
+    }
+  }
+
+  private static void parseVariablesHelper(Object instance, Class<?> clazz)
+      throws IllegalArgumentException, IllegalAccessException {
+    Field[] fields = clazz.getFields();
+
+    for (final Field field : fields) {
+      String group, name;
+      boolean isFile = false;
+      if (field.isAnnotationPresent(Variable.class)) {
+        Variable annotation = field.getAnnotation(Variable.class);
+        group = annotation.group();
+        name = annotation.name();
+      } else if (field.isAnnotationPresent(File.class)) {
+        File annotation = field.getAnnotation(File.class);
+        group = annotation.group();
+        name = annotation.name();
+        isFile = true;
+      } else {
+        continue;
+      }
+
+      String variableName = name;
+      if (TextUtils.isEmpty(variableName)) {
+        variableName = field.getName();
+      }
+      if (!TextUtils.isEmpty(group)) {
+        variableName = group + "." + variableName;
+      }
+
+      Class<?> fieldType = field.getType();
+      String fieldTypeString = fieldType.toString();
+      if (fieldTypeString.equals("int")) {
+        defineVariable(instance, variableName, field.getInt(instance), "integer", field);
+      } else if (fieldTypeString.equals("byte")) {
+        defineVariable(instance, variableName, field.getByte(instance), "integer", field);
+      } else if (fieldTypeString.equals("short")) {
+        defineVariable(instance, variableName, field.getShort(instance), "integer", field);
+      } else if (fieldTypeString.equals("long")) {
+        defineVariable(instance, variableName, field.getLong(instance), "integer", field);
+      } else if (fieldTypeString.equals("char")) {
+        defineVariable(instance, variableName, field.getChar(instance), "integer", field);
+      } else if (fieldTypeString.equals("float")) {
+        defineVariable(instance, variableName, field.getFloat(instance), "float", field);
+      } else if (fieldTypeString.equals("double")) {
+        defineVariable(instance, variableName, field.getDouble(instance), "float", field);
+      } else if (fieldTypeString.equals("boolean")) {
+        defineVariable(instance, variableName, field.getBoolean(instance), "bool", field);
+      } else if (fieldType.isPrimitive()) {
+        Log.e("Variable " + variableName + " is an unsupported primitive type.");
+      } else if (fieldType.isArray()) {
+        Log.e("Variable " + variableName + " should be a List instead of an Array.");
+      } else if (fieldType.isAssignableFrom(List.class)) {
+        defineVariable(instance, variableName, field.get(instance), "list", field);
+      } else if (fieldType.isAssignableFrom(Map.class)) {
+        defineVariable(instance, variableName, field.get(instance), "group", field);
+      } else {
+        Object value = field.get(instance);
+        String stringValue = value == null ? null : value.toString();
+        if (isFile) {
+          defineFileVariable(instance, variableName, stringValue, field);
+        } else {
+          defineVariable(instance, variableName, stringValue, "string", field);
+        }
+      }
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/annotations/Variable.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Leanplum variable annotation.
+ * <p>
+ * <p>Use this to make this variable changeable from the Leanplum dashboard. Variables must be of
+ * type boolean, byte, short, int, long, float, double, char, String, List, or Map. Lists and maps
+ * may contain other lists and maps.
+ * <p>
+ * <p>Variables with this annotation update when the API call for Leanplum.start completes
+ * successfully or fails (in which case values are loaded from a cache stored on the device).
+ *
+ * @author Andrew First
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Variable {
+  /**
+   * (Optional). The group to put the variable in. Use "." to nest groups.
+   */
+  String group() default "";
+
+  /**
+   * (Optional). The name of the variable. If not set, then uses the actual name of the field.
+   */
+  String name() default "";
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/ActionCallback.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+import com.leanplum.ActionContext;
+
+/**
+ * Callback that gets run when an action is triggered.
+ *
+ * @author Andrew First
+ */
+public abstract class ActionCallback {
+  public abstract boolean onResponse(ActionContext context);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/InboxChangedCallback.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+/**
+ * Inbox changes callback.
+ *
+ * @author Anna Orlova
+ */
+public abstract class InboxChangedCallback implements Runnable {
+  public void run() {
+    this.inboxChanged();
+  }
+
+  public abstract void inboxChanged();
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/NewsfeedChangedCallback.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+/**
+ * Newsfeed changed callback.
+ *
+ * @author Aleksandar Gyorev
+ */
+public abstract class NewsfeedChangedCallback extends InboxChangedCallback {
+  @Override
+  public void inboxChanged() {
+    newsfeedChanged();
+  }
+
+  public abstract void newsfeedChanged();
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/PostponableAction.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+import com.leanplum.LeanplumActivityHelper;
+
+/**
+ * Action callback that will not be executed for activity classes that are ignored via
+ * {@link LeanplumActivityHelper#deferMessagesForActivities(Class[])}
+ *
+ * @author Ben Marten
+ */
+public abstract class PostponableAction implements Runnable {
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/RegisterDeviceCallback.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+/**
+ * Callback that gets run when the device needs to be registered.
+ *
+ * @author Andrew First
+ */
+public abstract class RegisterDeviceCallback implements Runnable {
+  public static abstract class EmailCallback implements Runnable {
+    private String email;
+
+    public void setResponseHandler(String email) {
+      this.email = email;
+    }
+
+    public void run() {
+      this.onResponse(email);
+    }
+
+    public abstract void onResponse(String email);
+  }
+
+  private EmailCallback callback;
+
+  public void setResponseHandler(EmailCallback callback) {
+    this.callback = callback;
+  }
+
+  public void run() {
+    this.onResponse(callback);
+  }
+
+  public abstract void onResponse(EmailCallback callback);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/RegisterDeviceFinishedCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+/**
+ * Callback that gets run when the device has been registered.
+ *
+ * @author Andrew First
+ */
+public abstract class RegisterDeviceFinishedCallback implements Runnable {
+  private boolean success;
+
+  public void setSuccess(boolean success) {
+    this.success = success;
+  }
+
+  public void run() {
+    this.onResponse(success);
+  }
+
+  public abstract void onResponse(boolean success);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/StartCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+/**
+ * Callback that gets run when Leanplum is started.
+ *
+ * @author Andrew First
+ */
+public abstract class StartCallback implements Runnable {
+  private boolean success;
+
+  public void setSuccess(boolean success) {
+    this.success = success;
+  }
+
+  public void run() {
+    this.onResponse(success);
+  }
+
+  public abstract void onResponse(boolean success);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/VariableCallback.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+import com.leanplum.Var;
+
+/**
+ * Leanplum variable callback.
+ *
+ * @author Andrew First
+ */
+public abstract class VariableCallback<T> implements Runnable {
+  private Var<T> variable;
+
+  public void setVariable(Var<T> variable) {
+    this.variable = variable;
+  }
+
+  public void run() {
+    this.handle(variable);
+  }
+
+  public abstract void handle(Var<T> variable);
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/callbacks/VariablesChangedCallback.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+/**
+ * Variables changed callback.
+ *
+ * @author Andrew First
+ */
+public abstract class VariablesChangedCallback implements Runnable {
+  public void run() {
+    this.variablesChanged();
+  }
+
+  public abstract void variablesChanged();
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/AESCrypt.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.content.SharedPreferences;
+import android.util.Pair;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * AES Encryption as detailed at
+ * http://nelenkov.blogspot.com/2012/04/using-password-based-encryption-on.html
+ *
+ * @author Aakash Patel
+ */
+public class AESCrypt {
+
+  private static enum EncryptionType {
+    /**
+     * Encryption based on a token received from the server. Used in SDK versions prior to 1.2.20.
+     * <p>
+     * Corresponds to ciphertexts of the format "[12, -33, 52]", corresponding to Arrays.toString()
+     * of an encrypted byte[].
+     * <p>
+     * Legacy values may decrypt to ciphertexts. We ignore what appear to be double-encrypted
+     * ciphertexts that are stored in a legacy format.
+     */
+    LEGACY_TOKEN(0),
+
+    /**
+     * Encryption based on the app ID. Used in SDK versions since 1.2.20.
+     * <p>
+     * Corresponds to ciphertexts of the format "01[12, -33, 52]". The format adds a version
+     * identifier ("01") prefix to ciphertexts, allowing us to change the format in the future.
+     * <p>
+     * With the exception of LEGACY_TOKEN ciphertexts, which must continue to be supported, we will
+     * use the first two characters to determine the encryption protocol.
+     */
+    APP_ID_KEY(1);
+
+    public final int id;
+    public final String prefix;
+    public final String prefixWithBracket;
+
+    EncryptionType(int id) {
+      this.id = id;
+      prefix = String.format("%02d", id);
+      prefixWithBracket = prefix + "[";
+    }
+
+    private static EncryptionType forId(int id) {
+      if (id == 1) {
+        return APP_ID_KEY;
+      }
+      return null;
+    }
+
+    public static Pair<EncryptionType, String> parseCipherText(String cipherText) {
+      if (cipherText == null || cipherText.isEmpty()) {
+        return null;
+      }
+      if (cipherText.startsWith("[")) {
+        return Pair.create(LEGACY_TOKEN, cipherText);
+      }
+      if (cipherText.startsWith(APP_ID_KEY.prefixWithBracket)) {
+        return Pair.create(
+            APP_ID_KEY, cipherText.substring(APP_ID_KEY.prefixWithBracket.length() - 1));
+      }
+      return null;
+    }
+  }
+
+  // Build prefix and suffix strings longhand, to obfuscate them slightly.
+  // Probably doesn't matter.
+  private static final String APP_ID_KEY_PREFIX = new StringBuilder()
+      .append("L").append("q").append(3).append("f").append("z").toString();
+  private static final String APP_ID_KEY_SUFFIX = new StringBuilder()
+      .append("b").append("L").append("t").append("i").append(2).toString();
+
+  private final String appId;
+  private final String token;
+
+  /**
+   * Creates an AESCrypt encryption context.
+   * <p>
+   * Intended for short-term use, since the encryption token can change.
+   */
+  public AESCrypt(String appId, String token) {
+    this.appId = appId;
+    this.token = token;
+  }
+
+  private String appIdKeyPassword() {
+    return APP_ID_KEY_PREFIX + appId + APP_ID_KEY_SUFFIX;
+  }
+
+  /**
+   * Creates a ciphertext using a password based on current context parameters.
+   *
+   * @param plaintext
+   * @return A cipher text string, or null if encryption fails (unexpected).
+   */
+  public String encrypt(String plaintext) {
+    if (plaintext == null) {
+      return null;
+    }
+    // Always encrypt using the APP_ID_KEY method.
+    if (appId == null || appId.isEmpty()) {
+      Log.e("Encrypt called with null appId.");
+      return null;
+    }
+    String cipherText = encryptInternal(appIdKeyPassword(), plaintext);
+    if (cipherText == null) {
+      Log.w("Failed to encrypt.");
+      return null;
+    }
+    if (cipherText.isEmpty() || cipherText.equals(plaintext) || !cipherText.startsWith("[")) {
+      Log.w("Invalid ciphertext: " + cipherText);
+      return null;
+    }
+    return EncryptionType.APP_ID_KEY.prefix + cipherText;
+  }
+
+  public String decodePreference(SharedPreferences preferences, String key, String defaultValue) {
+    String cipherText = preferences.getString(key, null);
+    if (cipherText == null) {
+      return defaultValue;
+    }
+    String decoded = decrypt(cipherText);
+    if (decoded == null) {
+      return defaultValue;
+    }
+    return decoded;
+  }
+
+  /**
+   * Decrypts a ciphertext in either legacy or current format, using a password based on context
+   * parameters.
+   *
+   * @param cipherText The value to encrypt; tolerates null.
+   * @return A cipher text string, or null if the value can't be decrypted.
+   */
+  public String decrypt(String cipherText) {
+    Pair<EncryptionType, String> encryptionSpec = EncryptionType.parseCipherText(cipherText);
+    String result = null;
+    if (encryptionSpec == null) {
+      Log.v("Got null encryptionSpec for encrypted: " + cipherText);
+    } else {
+      switch (encryptionSpec.first) {
+        case LEGACY_TOKEN:
+          if (token == null || token.isEmpty()) {
+            Log.e("Decrypt called with null token.");
+          } else {
+            result = decryptInternal(token, encryptionSpec.second);
+            // For legacy keys only -- detect if the value we decode is a valid legacy ciphertext.
+            // If so, it was almost certainly produced by legacy decryption, which would return
+            // ciphertext on decryption failure. Discard the value and return null.
+            if (result != null && parseCiphertextInternal(result) != null) {
+              Log.e("Discarding legacy value that appears to be an encrypted value: " +
+                  result);
+              return null;
+            }
+          }
+          break;
+        case APP_ID_KEY:
+          if (appId == null || appId.isEmpty()) {
+            Log.e("Decrypt called with null appId.");
+          } else {
+            result = decryptInternal(appIdKeyPassword(), encryptionSpec.second);
+          }
+          break;
+      }
+    }
+    if (result == null) {
+      Log.w("Unable to decrypt " + cipherText);
+    }
+    return result;
+  }
+
+  /**
+   * Encrypts the plaintext using password. In case of exception, returns null.
+   */
+  // VisibleForTesting
+  public static String encryptInternal(String password, String plaintext) {
+    try {
+      return Arrays.toString(performCryptOperation(Cipher.ENCRYPT_MODE, password,
+          plaintext.getBytes("UTF-8")));
+    } catch (UnsupportedEncodingException e) {
+      Log.w("Unable to encrypt " + plaintext, e);
+      return null;
+    }
+  }
+
+  private static byte[] parseCiphertextInternal(String ciphertext) {
+    if (ciphertext == null) {
+      return null;
+    }
+    ciphertext = ciphertext.trim();
+    if (ciphertext.length() < 2) {
+      return null;
+    }
+    try {
+      String[] byteStrings =
+          ciphertext.substring(1, ciphertext.length() - 1).trim().split("\\s*,\\s*");
+      byte[] bytes = new byte[byteStrings.length];
+      for (int i = 0; i < byteStrings.length; i++) {
+        bytes[i] = Byte.parseByte(byteStrings[i]);
+      }
+      return bytes;
+    } catch (NumberFormatException e) {
+      return null;
+    }
+  }
+
+  /**
+   * Decrypts the ciphertext using password. In case of exception, returns null.
+   *
+   * @param ciphertext Must be a valid byte array represented as a string as returned by
+   * Arrays.toString().
+   */
+  private static String decryptInternal(String password, String ciphertext) {
+    try {
+      byte[] bytes = parseCiphertextInternal(ciphertext);
+      if (bytes == null) {
+        Log.w("Invalid ciphertext: " + ciphertext);
+        return null;
+      }
+      byte[] byteResult = performCryptOperation(Cipher.DECRYPT_MODE, password, bytes);
+      if (byteResult != null) {
+        return new String(byteResult, "UTF-8");
+      }
+    } catch (UnsupportedEncodingException e) {
+      // Unreachable on android, which guarantees UTF-8 support.
+      Log.w("Could not encode UTF8 string.\n" + Log.getStackTraceString(e));
+    }
+    return null;
+  }
+
+  /**
+   * Performs either an encryption or a decryption based on the mode. In case of exception, returns
+   * null.
+   *
+   * @param mode Should be either Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE
+   * @param password The password to crypt.
+   * @param text The text to crypt.
+   * @return The result of the crypt.
+   */
+  private static byte[] performCryptOperation(int mode, String password, byte[] text) {
+    byte[] result = null;
+    try {
+      byte[] SALT = Constants.Crypt.SALT.getBytes("UTF-8");
+      byte[] IV = Constants.Crypt.IV.getBytes("UTF-8");
+      KeySpec keySpec = new PBEKeySpec(password.toCharArray(), SALT, Constants.Crypt.ITER_COUNT,
+          Constants.Crypt.KEY_LENGTH);
+      SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5And128BitAES-CBC-OpenSSL");
+      byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
+      SecretKey key = new SecretKeySpec(keyBytes, "AES");
+
+      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+      IvParameterSpec ivParams = new IvParameterSpec(IV);
+      cipher.init(mode, key, ivParams);
+
+      result = cipher.doFinal(text);
+    } catch (InvalidKeyException e) {
+      // Don't log exceptions; we have more useful warning logs when this returns null.
+    } catch (NoSuchAlgorithmException e) {
+    } catch (NoSuchPaddingException e) {
+    } catch (InvalidAlgorithmParameterException e) {
+    } catch (IllegalBlockSizeException e) {
+    } catch (BadPaddingException e) {
+    } catch (UnsupportedEncodingException e) {
+    } catch (InvalidKeySpecException e) {
+    }
+    return result;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/ActionArg.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.text.TextUtils;
+
+import java.io.InputStream;
+
+/**
+ * Represents an argument for a message or action.
+ *
+ * @param <T> Type of the argument. Can be Boolean, Byte, Short, Integer, Long, Float, Double,
+ * Character, String, List, or Map.
+ * @author Andrew First
+ */
+public class ActionArg<T> {
+  private String name;
+  private String kind;
+  private T defaultValue;
+  private boolean isAsset;
+
+  private ActionArg() {
+  }
+
+  private static <T> ActionArg<T> argNamed(String name, T defaultValue, String kind) {
+    ActionArg<T> arg = new ActionArg<>();
+    arg.name = name;
+    arg.kind = kind;
+    arg.defaultValue = defaultValue;
+    return arg;
+  }
+
+  /**
+   * Creates an instance of a new arg with a default value.
+   *
+   * @param name Name of the arg.
+   * @param defaultValue Default value of the arg. Can't be null.
+   */
+  public static <T> ActionArg<T> argNamed(String name, T defaultValue) {
+    return argNamed(name, defaultValue, VarCache.kindFromValue(defaultValue));
+  }
+
+  public static ActionArg<Integer> colorArgNamed(String name, int defaultValue) {
+    return argNamed(name, defaultValue, Constants.Kinds.COLOR);
+  }
+
+  public static ActionArg<String> fileArgNamed(String name, String defaultFilename) {
+    if (TextUtils.isEmpty(defaultFilename)) {
+      defaultFilename = "";
+    }
+    ActionArg<String> arg = argNamed(name, defaultFilename, Constants.Kinds.FILE);
+    VarCache.registerFile(arg.defaultValue, arg.defaultValue,
+        arg.defaultStream(), false, null, 0);
+    return arg;
+  }
+
+  public static ActionArg<String> assetArgNamed(String name, String defaultFilename) {
+    ActionArg<String> arg = argNamed(name, defaultFilename, Constants.Kinds.FILE);
+    arg.isAsset = true;
+    VarCache.registerFile(arg.defaultValue, arg.defaultValue,
+        arg.defaultStream(), false, null, 0);
+    return arg;
+  }
+
+  public static ActionArg<String> actionArgNamed(String name, String defaultValue) {
+    if (TextUtils.isEmpty(defaultValue)) {
+      defaultValue = "";
+    }
+    return argNamed(name, defaultValue, Constants.Kinds.ACTION);
+  }
+
+  public String name() {
+    return name;
+  }
+
+  public String kind() {
+    return kind;
+  }
+
+  public T defaultValue() {
+    return defaultValue;
+  }
+
+  public InputStream defaultStream() {
+    if (!kind.equals(Constants.Kinds.FILE)) {
+      return null;
+    }
+    return FileManager.stream(false, isAsset, isAsset,
+        (String) defaultValue, (String) defaultValue, null);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/ActionManager.java
@@ -0,0 +1,658 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+
+import com.google.android.gms.location.LocationServices;
+import com.leanplum.ActionContext;
+import com.leanplum.ActionContext.ContextualValues;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumLocalPushListenerService;
+import com.leanplum.LeanplumPushService;
+import com.leanplum.LocationManager;
+import com.leanplum.callbacks.ActionCallback;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Handles in-app and push messaging.
+ *
+ * @author Andrew First
+ */
+public class ActionManager {
+  private Map<String, Map<String, Number>> messageImpressionOccurrences;
+  private Map<String, Number> messageTriggerOccurrences;
+  private Map<String, Number> sessionOccurrences;
+
+  private static ActionManager instance;
+
+  public static final String PUSH_NOTIFICATION_ACTION_NAME = "__Push Notification";
+  public static final String HELD_BACK_ACTION_NAME = "__held_back";
+
+  private static final String PREFERENCES_NAME = "__leanplum_messaging__";
+
+  public static class MessageMatchResult {
+    public boolean matchedTrigger;
+    public boolean matchedUnlessTrigger;
+    public boolean matchedLimit;
+  }
+
+  public static synchronized ActionManager getInstance() {
+    if (instance == null) {
+      instance = new ActionManager();
+    }
+    return instance;
+  }
+
+  private static boolean loggedLocationManagerFailure = false;
+
+  public static LocationManager getLocationManager() {
+    if (Util.hasPlayServices()) {
+      try {
+        if (LocationServices.API != null) {
+          // Reflection here prevents linker errors
+          // in Google Play Services is not used in the client app.
+          return (LocationManager) Class
+              .forName("com.leanplum.LocationManagerImplementation")
+              .getMethod("instance").invoke(null);
+        }
+      } catch (Throwable e) {
+        if (!loggedLocationManagerFailure) {
+          Log.e("Geofencing support requires Google Play Services v8.1 and higher.\n" +
+              "Add this to your build.gradle file:\n" +
+              "compile ('com.google.android.gms:play-services-location:8.3.0+')");
+          loggedLocationManagerFailure = true;
+        }
+      }
+    }
+    return null;
+  }
+
+  private ActionManager() {
+    listenForLocalNotifications();
+    sessionOccurrences = new HashMap<>();
+    messageImpressionOccurrences = new HashMap<>();
+    messageTriggerOccurrences = new HashMap<>();
+  }
+
+  private void listenForLocalNotifications() {
+    Leanplum.onAction(PUSH_NOTIFICATION_ACTION_NAME, new ActionCallback() {
+      @Override
+      public boolean onResponse(ActionContext actionContext) {
+        try {
+          String messageId = actionContext.getMessageId();
+
+          // Get eta.
+          Object countdownObj;
+          if (((BaseActionContext) actionContext).isPreview()) {
+            countdownObj = 5.0;
+          } else {
+            Map<String, Object> messageConfig = CollectionUtil.uncheckedCast(
+                VarCache.getMessageDiffs().get(messageId));
+            if (messageConfig == null) {
+              Log.e("Could not find message options for ID " + messageId);
+              return false;
+            }
+            countdownObj = messageConfig.get("countdown");
+          }
+          if (!(countdownObj instanceof Number)) {
+            Log.e("Invalid notification countdown: " + countdownObj);
+            return false;
+          }
+          long eta = System.currentTimeMillis() + ((Number) countdownObj).longValue() * 1000L;
+
+          Context context = Leanplum.getContext();
+          Intent intentAlarm = new Intent(context, LeanplumLocalPushListenerService.class);
+          AlarmManager alarmManager = (AlarmManager) context.getSystemService(
+              Context.ALARM_SERVICE);
+
+          // If there's already one scheduled before the eta, discard this.
+          // Otherwise, discard the scheduled one.
+          SharedPreferences preferences = context.getSharedPreferences(
+              PREFERENCES_NAME, Context.MODE_PRIVATE);
+          long existingEta = preferences.getLong(String.format(
+              Constants.Defaults.LOCAL_NOTIFICATION_KEY, messageId), 0L);
+          if (existingEta > 0L && existingEta > System.currentTimeMillis()) {
+            if (existingEta < eta) {
+              return false;
+            } else if (existingEta >= eta) {
+              PendingIntent existingIntent = PendingIntent.getService(
+                  context, messageId.hashCode(), intentAlarm,
+                  PendingIntent.FLAG_UPDATE_CURRENT);
+              alarmManager.cancel(existingIntent);
+            }
+          }
+
+          // Specify custom data for the notification
+          Map<String, Serializable> data = actionContext.objectNamed("Advanced options.Data");
+          if (data != null) {
+            for (String key : data.keySet()) {
+              intentAlarm.putExtra(key, data.get(key));
+            }
+          }
+
+          // Specify open action
+          String openAction = actionContext.stringNamed(Constants.Values.DEFAULT_PUSH_ACTION);
+          boolean muteInsideApp = Boolean.TRUE.equals(actionContext.objectNamed(
+              "Advanced options.Mute inside app"));
+          if (openAction != null) {
+            if (muteInsideApp) {
+              intentAlarm.putExtra(Constants.Keys.PUSH_MESSAGE_ID_MUTE_WITH_ACTION, messageId);
+            } else {
+              intentAlarm.putExtra(Constants.Keys.PUSH_MESSAGE_ID_NO_MUTE_WITH_ACTION, messageId);
+            }
+          } else {
+            if (muteInsideApp) {
+              intentAlarm.putExtra(Constants.Keys.PUSH_MESSAGE_ID_MUTE, messageId);
+            } else {
+              intentAlarm.putExtra(Constants.Keys.PUSH_MESSAGE_ID_NO_MUTE, messageId);
+            }
+          }
+
+          // Message.
+          String message = actionContext.stringNamed("Message");
+          intentAlarm.putExtra(Constants.Keys.PUSH_MESSAGE_TEXT,
+              message != null ? message : Constants.Values.DEFAULT_PUSH_MESSAGE);
+
+          // Collapse key.
+          String collapseKey = actionContext.stringNamed("Android options.Collapse key");
+          if (collapseKey != null) {
+            intentAlarm.putExtra("collapseKey", collapseKey);
+          }
+
+          // Delay while idle.
+          boolean delayWhileIdle = Boolean.TRUE.equals(actionContext.objectNamed(
+              "Android options.Delay while idle"));
+          if (delayWhileIdle) {
+            intentAlarm.putExtra("delayWhileIdle", true);
+          }
+
+          // Schedule notification.
+          PendingIntent operation = PendingIntent.getService(
+              context, messageId.hashCode(), intentAlarm,
+              PendingIntent.FLAG_UPDATE_CURRENT);
+          alarmManager.set(AlarmManager.RTC_WAKEUP, eta, operation);
+
+          // Save notification so we can cancel it later.
+          SharedPreferences.Editor editor = preferences.edit();
+          editor.putLong(String.format(Constants.Defaults.LOCAL_NOTIFICATION_KEY, messageId), eta);
+          try {
+            editor.apply();
+          } catch (NoSuchMethodError e) {
+            editor.commit();
+          }
+
+          Log.i("Scheduled notification");
+          return true;
+        } catch (Throwable t) {
+          Util.handleException(t);
+          return false;
+        }
+      }
+    });
+
+    Leanplum.onAction("__Cancel" + PUSH_NOTIFICATION_ACTION_NAME, new ActionCallback() {
+      @Override
+      public boolean onResponse(ActionContext actionContext) {
+        try {
+          String messageId = actionContext.getMessageId();
+
+          // Get existing eta and clear notification from preferences.
+          Context context = Leanplum.getContext();
+          SharedPreferences preferences = context.getSharedPreferences(
+              PREFERENCES_NAME, Context.MODE_PRIVATE);
+          String preferencesKey = String.format(Constants.Defaults.LOCAL_NOTIFICATION_KEY, messageId);
+          long existingEta = preferences.getLong(preferencesKey, 0L);
+          SharedPreferences.Editor editor = preferences.edit();
+          editor.remove(preferencesKey);
+          try {
+            editor.apply();
+          } catch (NoSuchMethodError e) {
+            editor.commit();
+          }
+
+          // Cancel notification.
+          Intent intentAlarm = new Intent(context, LeanplumPushService.class);
+          AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+          PendingIntent existingIntent = PendingIntent.getService(
+              context, messageId.hashCode(), intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
+          alarmManager.cancel(existingIntent);
+
+          boolean didCancel = existingEta > System.currentTimeMillis();
+          if (didCancel) {
+            Log.i("Cancelled notification");
+          }
+          return didCancel;
+        } catch (Throwable t) {
+          Util.handleException(t);
+          return false;
+        }
+      }
+    });
+  }
+
+  public Map<String, Number> getMessageImpressionOccurrences(String messageId) {
+    Map<String, Number> occurrences = messageImpressionOccurrences.get(messageId);
+    if (occurrences != null) {
+      return occurrences;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences preferences = context.getSharedPreferences(
+        PREFERENCES_NAME, Context.MODE_PRIVATE);
+    String savedValue = preferences.getString(
+        String.format(Constants.Defaults.MESSAGE_IMPRESSION_OCCURRENCES_KEY, messageId),
+        "{}");
+    occurrences = CollectionUtil.uncheckedCast(JsonConverter.fromJson(savedValue));
+    messageImpressionOccurrences.put(messageId, occurrences);
+    return occurrences;
+  }
+
+  public void saveMessageImpressionOccurrences(Map<String, Number> occurrences, String messageId) {
+    Context context = Leanplum.getContext();
+    SharedPreferences preferences = context.getSharedPreferences(
+        PREFERENCES_NAME, Context.MODE_PRIVATE);
+    SharedPreferences.Editor editor = preferences.edit();
+    editor.putString(
+        String.format(Constants.Defaults.MESSAGE_IMPRESSION_OCCURRENCES_KEY, messageId),
+        JsonConverter.toJson(occurrences));
+    messageImpressionOccurrences.put(messageId, occurrences);
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  public int getMessageTriggerOccurrences(String messageId) {
+    Number occurrences = messageTriggerOccurrences.get(messageId);
+    if (occurrences != null) {
+      return occurrences.intValue();
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences preferences = context.getSharedPreferences(
+        PREFERENCES_NAME, Context.MODE_PRIVATE);
+    int savedValue = preferences.getInt(
+        String.format(Constants.Defaults.MESSAGE_TRIGGER_OCCURRENCES_KEY, messageId), 0);
+    messageTriggerOccurrences.put(messageId, savedValue);
+    return savedValue;
+  }
+
+  public void saveMessageTriggerOccurrences(int occurrences, String messageId) {
+    Context context = Leanplum.getContext();
+    SharedPreferences preferences = context.getSharedPreferences(
+        PREFERENCES_NAME, Context.MODE_PRIVATE);
+    SharedPreferences.Editor editor = preferences.edit();
+    editor.putInt(
+        String.format(Constants.Defaults.MESSAGE_TRIGGER_OCCURRENCES_KEY, messageId), occurrences);
+    messageTriggerOccurrences.put(messageId, occurrences);
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  public MessageMatchResult shouldShowMessage(String messageId, Map<String, Object> messageConfig,
+      String when, String eventName, ContextualValues contextualValues) {
+    MessageMatchResult result = new MessageMatchResult();
+
+    // 1. Must not be muted.
+    Context context = Leanplum.getContext();
+    SharedPreferences preferences = context.getSharedPreferences(
+        PREFERENCES_NAME, Context.MODE_PRIVATE);
+    if (preferences.getBoolean(
+        String.format(Constants.Defaults.MESSAGE_MUTED_KEY, messageId), false)) {
+      return result;
+    }
+
+    // 2. Must match at least one trigger.
+    result.matchedTrigger = matchedTriggers(messageConfig.get("whenTriggers"), when, eventName,
+        contextualValues);
+    result.matchedUnlessTrigger = matchedTriggers(messageConfig.get("unlessTriggers"), when, eventName,
+        contextualValues);
+    if (!result.matchedTrigger && !result.matchedUnlessTrigger) {
+      return result;
+    }
+
+    // 3. Must match all limit conditions.
+    Object limitConfigObj = messageConfig.get("whenLimits");
+    Map<String, Object> limitConfig = null;
+    if (limitConfigObj instanceof Map<?, ?>) {
+      limitConfig = CollectionUtil.uncheckedCast(limitConfigObj);
+    }
+    result.matchedLimit = matchesLimits(messageId, limitConfig);
+    return result;
+  }
+
+  private boolean matchesLimits(String messageId, Map<String, Object> limitConfig) {
+    if (limitConfig == null) {
+      return true;
+    }
+    List<Object> limits = CollectionUtil.uncheckedCast(limitConfig.get("children"));
+    if (limits.isEmpty()) {
+      return true;
+    }
+    Map<String, Number> impressionOccurrences = getMessageImpressionOccurrences(messageId);
+    int triggerOccurrences = getMessageTriggerOccurrences(messageId) + 1;
+    for (Object limitObj : limits) {
+      Map<String, Object> limit = CollectionUtil.uncheckedCast(limitObj);
+      String subject = limit.get("subject").toString();
+      String noun = limit.get("noun").toString();
+      String verb = limit.get("verb").toString();
+
+      // E.g. 5 times per session; 2 times per 7 minutes.
+      if (subject.equals("times")) {
+        List<Object> objects = CollectionUtil.uncheckedCast(limit.get("objects"));
+        int perTimeUnit = objects.size() > 0 ?
+            Integer.parseInt(objects.get(0).toString()) : 0;
+        if (!matchesLimitTimes(Integer.parseInt(noun),
+            perTimeUnit, verb, impressionOccurrences, messageId)) {
+          return false;
+        }
+
+        // E.g. On the 5th occurrence.
+      } else if (subject.equals("onNthOccurrence")) {
+        int amount = Integer.parseInt(noun);
+        if (triggerOccurrences != amount) {
+          return false;
+        }
+
+        // E.g. Every 5th occurrence.
+      } else if (subject.equals("everyNthOccurrence")) {
+        int multiple = Integer.parseInt(noun);
+        if (multiple == 0 || triggerOccurrences % multiple != 0) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  private boolean matchesLimitTimes(int amount, int time, String units,
+      Map<String, Number> occurrences, String messageId) {
+    Number existing = 0L;
+    if (units.equals("limitSession")) {
+      existing = sessionOccurrences.get(messageId);
+      if (existing == null) {
+        existing = 0L;
+      }
+    } else {
+      if (occurrences == null || occurrences.isEmpty()) {
+        return true;
+      }
+      Number min = occurrences.get("min");
+      Number max = occurrences.get("max");
+      if (min == null) {
+        min = 0L;
+      }
+      if (max == null) {
+        max = 0L;
+      }
+      if (units.equals("limitUser")) {
+        existing = max.longValue() - min.longValue() + 1;
+      } else {
+        if (units.equals("limitMinute")) {
+          time *= 60;
+        } else if (units.equals("limitHour")) {
+          time *= 3600;
+        } else if (units.equals("limitDay")) {
+          time *= 86400;
+        } else if (units.equals("limitWeek")) {
+          time *= 604800;
+        } else if (units.equals("limitMonth")) {
+          time *= 2592000;
+        }
+        long now = System.currentTimeMillis();
+        int matchedOccurrences = 0;
+        for (long i = max.longValue(); i >= min.longValue(); i--) {
+          if (occurrences.containsKey("" + i)) {
+            long timeAgo = (now - occurrences.get("" + i).longValue()) / 1000;
+            if (timeAgo > time) {
+              break;
+            }
+            matchedOccurrences++;
+            if (matchedOccurrences >= amount) {
+              return false;
+            }
+          }
+        }
+      }
+    }
+    return existing.longValue() < amount;
+  }
+
+  private boolean matchedTriggers(Object triggerConfigObj, String when, String eventName,
+      ContextualValues contextualValues) {
+    if (triggerConfigObj instanceof Map<?, ?>) {
+      Map<String, Object> triggerConfig = CollectionUtil.uncheckedCast(triggerConfigObj);
+      List<Object> triggers = CollectionUtil.uncheckedCast(triggerConfig.get("children"));
+      for (Object triggerObj : triggers) {
+        Map<String, Object> trigger = CollectionUtil.uncheckedCast(triggerObj);
+        if (matchedTrigger(trigger, when, eventName, contextualValues)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  private boolean matchedTrigger(Map<String, Object> trigger, String when, String eventName,
+      ContextualValues contextualValues) {
+    String subject = (String) trigger.get("subject");
+    if (subject.equals(when)) {
+      String noun = (String) trigger.get("noun");
+      if ((noun == null && eventName == null) || (noun != null && noun.equals(eventName))) {
+        String verb = (String) trigger.get("verb");
+        List<Object> objects = CollectionUtil.uncheckedCast(trigger.get("objects"));
+
+        // Evaluate user attribute changed to value.
+        if ("changesTo".equals(verb)) {
+          if (contextualValues != null && objects != null) {
+            for (Object object : objects) {
+              if ((object == null && contextualValues.attributeValue == null) ||
+                  (object != null && object.toString().equalsIgnoreCase(
+                      contextualValues.attributeValue.toString()))) {
+                return true;
+              }
+            }
+          }
+          return false;
+        }
+
+        // Evaluate user attribute changed from value to value.
+        if ("changesFromTo".equals(verb)) {
+          return contextualValues != null &&
+              objects.size() == 2 && objects.get(0) != null && objects.get(1) != null &&
+              contextualValues.previousAttributeValue != null &&
+              contextualValues.attributeValue != null &&
+              objects.get(0).toString().equalsIgnoreCase(
+                  contextualValues.previousAttributeValue.toString()) &&
+              objects.get(1).toString().equalsIgnoreCase(
+                  contextualValues.attributeValue.toString());
+        }
+
+        // Evaluate event parameter is value.
+        if ("triggersWithParameter".equals(verb)) {
+          if (contextualValues != null &&
+              objects.size() == 2 && objects.get(0) != null && objects.get(1) != null &&
+              contextualValues.parameters != null) {
+            Object parameterValue = contextualValues.parameters.get(objects.get(0));
+            return parameterValue != null && parameterValue.toString().equalsIgnoreCase(
+                objects.get(1).toString());
+          }
+          return false;
+        }
+
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public void recordMessageTrigger(String messageId) {
+    int occurrences = getMessageTriggerOccurrences(messageId);
+    occurrences++;
+    saveMessageTriggerOccurrences(occurrences, messageId);
+  }
+
+  /**
+   * Tracks the "Held Back" event for a message and records the held back occurrences.
+   *
+   * @param messageId The spoofed ID of the message.
+   * @param originalMessageId The original ID of the held back message.
+   */
+  public void recordHeldBackImpression(String messageId, String originalMessageId) {
+    recordImpression(messageId, originalMessageId);
+  }
+
+  /**
+   * Tracks the "Open" event for a message and records it's occurrence.
+   *
+   * @param messageId The ID of the message
+   */
+  public void recordMessageImpression(String messageId) {
+    recordImpression(messageId, null);
+  }
+
+  /**
+   * Records the occurrence of a message and tracks the correct impression event.
+   *
+   * @param messageId The ID of the message.
+   * @param originalMessageId The original message ID of the held back message. Supply this only if
+   * the message is held back. Otherwise, use null.
+   */
+  private void recordImpression(String messageId, String originalMessageId) {
+    Map<String, String> requestArgs = new HashMap<>();
+    if (originalMessageId != null) {
+      // This is a held back message - track the event with the original message ID.
+      requestArgs.put(Constants.Params.MESSAGE_ID, originalMessageId);
+      LeanplumInternal.track(Constants.HELD_BACK_EVENT_NAME, 0.0, null, null, requestArgs);
+    } else {
+      // Track the message impression and occurrence.
+      requestArgs.put(Constants.Params.MESSAGE_ID, messageId);
+      LeanplumInternal.track(null, 0.0, null, null, requestArgs);
+    }
+
+    // Record session occurrences.
+    Number existing = sessionOccurrences.get(messageId);
+    if (existing == null) {
+      existing = 0L;
+    }
+    existing = existing.longValue() + 1L;
+    sessionOccurrences.put(messageId, existing);
+
+    // Record cross-session occurrences.
+    Map<String, Number> occurrences = getMessageImpressionOccurrences(messageId);
+    if (occurrences == null || occurrences.isEmpty()) {
+      occurrences = new HashMap<>();
+      occurrences.put("min", 0L);
+      occurrences.put("max", 0L);
+      occurrences.put("0", System.currentTimeMillis());
+    } else {
+      Number min = occurrences.get("min");
+      Number max = occurrences.get("max");
+      if (min == null) {
+        min = 0L;
+      }
+      if (max == null) {
+        max = 0L;
+      }
+      max = max.longValue() + 1L;
+      occurrences.put("" + max, System.currentTimeMillis());
+      if (max.longValue() - min.longValue() + 1 >
+          Constants.Messaging.MAX_STORED_OCCURRENCES_PER_MESSAGE) {
+        occurrences.remove("" + min);
+        min = min.longValue() + 1L;
+        occurrences.put("min", min);
+      }
+      occurrences.put("max", max);
+    }
+    saveMessageImpressionOccurrences(occurrences, messageId);
+  }
+
+  public void muteFutureMessagesOfKind(String messageId) {
+    if (messageId != null) {
+      Context context = Leanplum.getContext();
+      SharedPreferences preferences = context.getSharedPreferences(
+          PREFERENCES_NAME, Context.MODE_PRIVATE);
+      SharedPreferences.Editor editor = preferences.edit();
+      editor.putBoolean(
+          String.format(Constants.Defaults.MESSAGE_MUTED_KEY, messageId),
+          true);
+      try {
+        editor.apply();
+      } catch (NoSuchMethodError e) {
+        editor.commit();
+      }
+    }
+  }
+
+
+  public static void getForegroundandBackgroundRegionNames(Set<String> foregroundRegionNames,
+      Set<String> backgroundRegionNames) {
+    Map<String, Object> messages = VarCache.messages();
+    for (String messageId : messages.keySet()) {
+      Map<String, Object> messageConfig = CollectionUtil.uncheckedCast(messages.get(messageId));
+      Set<String> regionNames;
+      Object action = messageConfig.get("action");
+      if (action instanceof String) {
+        if (action.equals(PUSH_NOTIFICATION_ACTION_NAME)) {
+          regionNames = backgroundRegionNames;
+        } else {
+          regionNames = foregroundRegionNames;
+        }
+
+        Map<String, Object> whenTriggers = CollectionUtil.uncheckedCast(messageConfig.get
+            ("whenTriggers"));
+        Map<String, Object> unlessTriggers = CollectionUtil.uncheckedCast(messageConfig.get
+            ("unlessTriggers"));
+
+        addRegionNamesFromTriggersToSet(whenTriggers, regionNames);
+        addRegionNamesFromTriggersToSet(unlessTriggers, regionNames);
+      }
+    }
+  }
+
+  public static void addRegionNamesFromTriggersToSet(
+      Map<String, Object> triggerConfig, Set<String> set) {
+    if (triggerConfig == null) {
+      return;
+    }
+    List<Map<String, Object>> triggers = CollectionUtil.uncheckedCast(triggerConfig.get
+        ("children"));
+    for (Map<String, Object> trigger : triggers) {
+      String subject = (String) trigger.get("subject");
+      if (subject.equals("enterRegion") || subject.equals("exitRegion")) {
+        set.add((String) trigger.get("noun"));
+      }
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/BaseActionContext.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import java.util.Map;
+
+/**
+ * Base class for ActionContext that contains internal methods.
+ *
+ * @author Andrew First
+ */
+public abstract class BaseActionContext {
+  protected String messageId = null;
+  protected String originalMessageId = null;
+  protected int priority;
+  protected Map<String, Object> args;
+  protected boolean isRooted = true;
+  private boolean isPreview = false;
+
+  public BaseActionContext(String messageId, String originalMessageId) {
+    this.messageId = messageId;
+    this.originalMessageId = originalMessageId;
+  }
+
+  void setIsRooted(boolean value) {
+    isRooted = value;
+  }
+
+  void setIsPreview(boolean isPreview) {
+    this.isPreview = isPreview;
+  }
+
+  boolean isPreview() {
+    return isPreview;
+  }
+
+  public String getMessageId() {
+    return messageId;
+  }
+
+  public String getOriginalMessageId() {
+    return originalMessageId;
+  }
+
+  public int getPriority() {
+    return priority;
+  }
+
+  public Map<String, Object> getArgs() {
+    return args;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/CollectionUtil.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class to easily create new list, map or set objects containing provided parameters.
+ *
+ * @author Ben Marten
+ */
+public class CollectionUtil {
+  /**
+   * Creates a new ArrayList and adds the passed arguments to it.
+   *
+   * @param items The items to add to the list.
+   * @param <T> The type of the list to be created.
+   * @return A typed list that contains the passed arguments.
+   */
+  @SafeVarargs
+  public static <T> ArrayList<T> newArrayList(T... items) {
+    ArrayList<T> result = new ArrayList<>((items != null) ? items.length : 0);
+    if (items != null) {
+      Collections.addAll(result, items);
+    }
+    return result;
+  }
+
+  /**
+   * Creates a new HashSet and adds the passed arguments to it.
+   *
+   * @param items The items to add to the set.
+   * @param <T> The type of the set to be created.
+   * @return A typed set that contains the passed arguments.
+   */
+  @SafeVarargs
+  static <T> HashSet<T> newHashSet(T... items) {
+    HashSet<T> result = new HashSet<>((items != null) ? items.length : 0);
+    if (items != null) {
+      Collections.addAll(result, items);
+    }
+    return result;
+  }
+
+  /**
+   * Creates a new HashMap and adds the passed arguments to it in pairs.
+   *
+   * @param items The keys and values, to add to the map in pairs.
+   * @param <T> The type of the map to be created.
+   * @return A typed map that contains the passed arguments.
+   * @throws IllegalArgumentException Throws an exception when an uneven number of arguments are
+   * passed.
+   */
+  @SuppressWarnings("unchecked")
+  public static <T, U> HashMap<T, U> newHashMap(Object... items) {
+    return (HashMap<T, U>) newMap(
+        new HashMap((items != null) ? items.length : 0),
+        (items != null) ? items : null);
+  }
+
+  /**
+   * Creates a new HashMap and adds the passed arguments to it in pairs.
+   *
+   * @param items The keys and values, to add to the map in pairs.
+   * @param <T> The type of the map to be created.
+   * @return A typed map that contains the passed arguments.
+   * @throws IllegalArgumentException Throws an exception when an uneven number of arguments are
+   * passed.
+   */
+  @SuppressWarnings("unchecked")
+  static <T, U> LinkedHashMap<T, U> newLinkedHashMap(Object... items) {
+    return (LinkedHashMap<T, U>) newMap(
+        new LinkedHashMap((items != null) ? items.length : 0),
+        (items != null) ? items : null);
+  }
+
+  /**
+   * Creates a new Map and adds the passed arguments to it in pairs.
+   *
+   * @param items The keys and values, to add to the map in pairs.
+   * @param <T> The type of the map to be created.
+   * @return A typed map that contains the passed arguments.
+   * @throws IllegalArgumentException Throws an exception when an even number of arguments are
+   * passed, or the type parameter is not a subclass of map.
+   */
+  @SuppressWarnings("unchecked")
+  private static <T, U> Map<T, U> newMap(Map<T, U> map, T[] items) {
+    if (items == null || items.length == 0) {
+      return map;
+    }
+    if (items.length % 2 != 0) {
+      throw new IllegalArgumentException("newMap requires an even number of items.");
+    }
+
+    for (int i = 0; i < items.length; i += 2) {
+      map.put(items[i], (U) items[i + 1]);
+    }
+    return map;
+  }
+
+  /**
+   * Returns the components of an array as concatenated String by calling toString() on each item.
+   *
+   * @param array The array to be concatenated.
+   * @param separator The separator between elements.
+   * @return A concatenated string of the items in list.
+   */
+  static <T> String concatenateArray(T[] array, String separator) {
+    if (array == null) {
+      return null;
+    }
+    return concatenateList(Arrays.asList(array), separator);
+  }
+
+  /**
+   * Returns the components of a list as concatenated String by calling toString() on each item.
+   *
+   * @param list The list to be concatenated.
+   * @param separator The separator between elements.
+   * @return A concatenated string of the items in list.
+   */
+  static String concatenateList(List<?> list, String separator) {
+    if (list == null) {
+      return null;
+    }
+    if (separator == null) {
+      separator = "";
+    }
+    StringBuilder stringBuilder = new StringBuilder();
+    for (Object item : list) {
+      if (item != null) {
+        stringBuilder.append(item.toString());
+        stringBuilder.append(separator);
+      }
+    }
+    String result = stringBuilder.toString();
+
+    if (result.length() > 0) {
+      return result.substring(0, result.length() - separator.length());
+    } else {
+      return result;
+    }
+  }
+
+  @SuppressWarnings({"unchecked"})
+  public static <T> T uncheckedCast(Object obj) {
+    return (T) obj;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Constants.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import com.leanplum.BuildConfig;
+
+/**
+ * Leanplum constants.
+ *
+ * @author Andrew First.
+ */
+public class Constants {
+  public static String API_HOST_NAME = "www.leanplum.com";
+  public static String SOCKET_HOST = "dev.leanplum.com";
+  public static int SOCKET_PORT = 80;
+  public static boolean API_SSL = true;
+  public static int NETWORK_TIMEOUT_SECONDS = 10;
+  public static int NETWORK_TIMEOUT_SECONDS_FOR_DOWNLOADS = 10;
+  static final String LEANPLUM_PACKAGE_IDENTIFIER = BuildConfig.LEANPLUM_PACKAGE_IDENTIFIER;
+
+  public static String LEANPLUM_VERSION = "2.2.2-SNAPSHOT";
+  public static String CLIENT = "android";
+
+  static final String INVALID_MAC_ADDRESS = "02:00:00:00:00:00";
+  static final String INVALID_MAC_ADDRESS_HASH = "0f607264fc6318a92b9e13c65db7cd3c";
+
+  /**
+   * From very old versions of the SDK, leading zeros were stripped from the mac address.
+   */
+  static final String OLD_INVALID_MAC_ADDRESS_HASH = "f607264fc6318a92b9e13c65db7cd3c";
+
+  static final String INVALID_ANDROID_ID = "9774d56d682e549c";
+  static final int MAX_DEVICE_ID_LENGTH = 400;
+  static final int MAX_USER_ID_LENGTH = 400;
+
+  public static String defaultDeviceId = null;
+  public static boolean hashFilesToDetermineModifications = true;
+  public static boolean isDevelopmentModeEnabled = false;
+  public static boolean loggingEnabled = false;
+  public static boolean isTestMode = false;
+  public static boolean enableVerboseLoggingInDevelopmentMode = false;
+  public static boolean enableFileUploadingInDevelopmentMode = true;
+  public static boolean canDownloadContentMidSessionInProduction = false;
+  static boolean isInPermanentFailureState = false;
+
+  public static boolean isNoop() {
+    return isTestMode || isInPermanentFailureState;
+  }
+
+  public static String API_SERVLET = "api";
+
+  public static class Defaults {
+    public static final String COUNT_KEY = "__leanplum_unsynced";
+    public static final String ITEM_KEY = "__leanplum_unsynced_%d";
+    public static final String VARIABLES_KEY = "__leanplum_variables";
+    public static final String ATTRIBUTES_KEY = "__leanplum_attributes";
+    public static final String TOKEN_KEY = "__leanplum_token";
+    public static final String MESSAGES_KEY = "__leanplum_messages";
+    public static final String UPDATE_RULES_KEY = "__leanplum_update_rules";
+    public static final String EVENT_RULES_KEY = "__leanplum_event_rules";
+    public static final String REGIONS_KEY = "regions";
+    public static final String MESSAGE_TRIGGER_OCCURRENCES_KEY =
+        "__leanplum_message_trigger_occurrences_%s";
+    public static final String MESSAGE_IMPRESSION_OCCURRENCES_KEY =
+        "__leanplum_message_occurrences_%s";
+    public static final String MESSAGE_MUTED_KEY = "__leanplum_message_muted_%s";
+    public static final String LOCAL_NOTIFICATION_KEY = "__leanplum_local_message_%s";
+    public static final String INBOX_KEY = "__leanplum_newsfeed";
+    public static final String LEANPLUM_PUSH = "__leanplum_push__";
+    public static final String APP_ID = "__app_id";
+    public static final String PROPERTY_REGISTRATION_ID = "registration_id";
+    public static final String PROPERTY_SENDER_IDS = "sender_ids";
+  }
+
+  public static class Methods {
+    public static final String ADVANCE = "advance";
+    public static final String DELETE_INBOX_MESSAGE = "deleteNewsfeedMessage";
+    public static final String DOWNLOAD_FILE = "downloadFile";
+    public static final String GET_INBOX_MESSAGES = "getNewsfeedMessages";
+    public static final String GET_VARS = "getVars";
+    public static final String HEARTBEAT = "heartbeat";
+    public static final String LOG = "log";
+    public static final String MARK_INBOX_MESSAGE_AS_READ = "markNewsfeedMessageAsRead";
+    public static final String MULTI = "multi";
+    public static final String PAUSE_SESSION = "pauseSession";
+    public static final String PAUSE_STATE = "pauseState";
+    public static final String REGISTER_FOR_DEVELOPMENT = "registerDevice";
+    public static final String RESUME_SESSION = "resumeSession";
+    public static final String RESUME_STATE = "resumeState";
+    public static final String SET_DEVICE_ATTRIBUTES = "setDeviceAttributes";
+    public static final String SET_TRAFFIC_SOURCE_INFO = "setTrafficSourceInfo";
+    public static final String SET_USER_ATTRIBUTES = "setUserAttributes";
+    public static final String SET_VARS = "setVars";
+    public static final String START = "start";
+    public static final String STOP = "stop";
+    public static final String TRACK = "track";
+    public static final String UPLOAD_FILE = "uploadFile";
+  }
+
+  public static class Params {
+    public static final String ACTION = "action";
+    public static final String ACTION_DEFINITIONS = "actionDefinitions";
+    public static final String APP_ID = "appId";
+    public static final String BACKGROUND = "background";
+    public static final String CLIENT = "client";
+    public static final String CLIENT_KEY = "clientKey";
+    public static final String DATA = "data";
+    public static final String DEV_MODE = "devMode";
+    public static final String DEVICE_ID = "deviceId";
+    public static final String DEVICE_MODEL = "deviceModel";
+    public static final String DEVICE_NAME = "deviceName";
+    public static final String DEVICE_PUSH_TOKEN = "gcmRegistrationId";
+    public static final String DEVICE_SYSTEM_NAME = "systemName";
+    public static final String DEVICE_SYSTEM_VERSION = "systemVersion";
+    public static final String EMAIL = "email";
+    public static final String EVENT = "event";
+    public static final String FILE = "file";
+    public static final String FILE_ATTRIBUTES = "fileAttributes";
+    public static final String GOOGLE_PLAY_PURCHASE_DATA = "googlePlayPurchaseData";
+    public static final String GOOGLE_PLAY_PURCHASE_DATA_SIGNATURE =
+        "googlePlayPurchaseDataSignature";
+    public static final String IAP_CURRENCY_CODE = "currencyCode";
+    public static final String IAP_ITEM = "item";
+    public static final String INCLUDE_DEFAULTS = "includeDefaults";
+    public static final String INCLUDE_MESSAGE_ID = "includeMessageId";
+    public static final String INFO = "info";
+    public static final String INSTALL_DATE = "installDate";
+    public static final String KINDS = "kinds";
+    public static final String LIMIT_TRACKING = "limitTracking";
+    public static final String MESSAGE = "message";
+    public static final String MESSAGE_ID = "messageId";
+    public static final String NEW_USER_ID = "newUserId";
+    public static final String INBOX_MESSAGE_ID = "newsfeedMessageId";
+    public static final String INBOX_MESSAGES = "newsfeedMessages";
+    public static final String PARAMS = "params";
+    public static final String SDK_VERSION = "sdkVersion";
+    public static final String STATE = "state";
+    public static final String TIME = "time";
+    public static final String TYPE = "type";
+    public static final String TOKEN = "token";
+    public static final String TRAFFIC_SOURCE = "trafficSource";
+    public static final String UPDATE_DATE = "updateDate";
+    public static final String USER_ID = "userId";
+    public static final String USER_ATTRIBUTES = "userAttributes";
+    public static final String VALUE = "value";
+    public static final String VARS = "vars";
+    public static final String VERSION_NAME = "versionName";
+  }
+
+  public static class Keys {
+    public static final String CITY = "city";
+    public static final String COUNTRY = "country";
+    public static final String DELIVERY_TIMESTAMP = "deliveryTimestamp";
+    public static final String EXPIRATION_TIMESTAMP = "expirationTimestamp";
+    public static final String FILENAME = "filename";
+    public static final String HASH = "hash";
+    public static final String INSTALL_TIME_INITIALIZED = "installTimeInitialized";
+    public static final String IS_READ = "isRead";
+    public static final String IS_REGISTERED = "isRegistered";
+    public static final String IS_REGISTERED_FROM_OTHER_APP = "isRegisteredFromOtherApp";
+    public static final String LATEST_VERSION = "latestVersion";
+    public static final String LOCALE = "locale";
+    public static final String LOCATION = "location";
+    public static final String LOCATION_ACCURACY_TYPE = "locationAccuracyType";
+    public static final String MESSAGE_DATA = "messageData";
+    public static final String MESSAGES = "messages";
+    public static final String UPDATE_RULES = "interfaceRules";
+    public static final String EVENT_RULES = "interfaceEvents";
+    public static final String INBOX_MESSAGES = "newsfeedMessages";
+    public static final String PUSH_MESSAGE_ACTION = "_lpx";
+    public static final String PUSH_MESSAGE_ID_NO_MUTE_WITH_ACTION = "_lpm";
+    public static final String PUSH_MESSAGE_ID_MUTE_WITH_ACTION = "_lpu";
+    public static final String PUSH_MESSAGE_ID_NO_MUTE = "_lpn";
+    public static final String PUSH_MESSAGE_ID_MUTE = "_lpv";
+    public static final String PUSH_MESSAGE_ID = "lp_messageId";
+    public static final String PUSH_MESSAGE_TEXT = "lp_message";
+    public static final String PUSH_MESSAGE_IMAGE_URL = "lp_imageUrl";
+    public static final String REGION = "region";
+    public static final String REGION_STATE = "regionState";
+    public static final String REGIONS = "regions";
+    public static final String SIZE = "size";
+    public static final String SUBTITLE = "Subtitle";
+    public static final String SYNC_INBOX = "syncNewsfeed";
+    public static final String LOGGING_ENABLED = "loggingEnabled";
+    public static final String TIMEZONE = "timezone";
+    public static final String TIMEZONE_OFFSET_SECONDS = "timezoneOffsetSeconds";
+    public static final String TITLE = "Title";
+    public static final String INBOX_IMAGE = "Image";
+    public static final String DATA = "Data";
+    public static final String TOKEN = "token";
+    public static final String VARIANTS = "variants";
+    public static final String VARS = "vars";
+    public static final String VARS_FROM_CODE = "varsFromCode";
+  }
+
+  public static class Kinds {
+    public static final String INT = "integer";
+    public static final String FLOAT = "float";
+    public static final String STRING = "string";
+    public static final String BOOLEAN = "bool";
+    public static final String FILE = "file";
+    public static final String DICTIONARY = "group";
+    public static final String ARRAY = "list";
+    public static final String ACTION = "action";
+    public static final String COLOR = "color";
+  }
+
+  static class Files {
+    public static final int MAX_UPLOAD_BATCH_SIZES = (25 * (1 << 20));
+    public static final int MAX_UPLOAD_BATCH_FILES = 16;
+  }
+
+  public static final String HELD_BACK_EVENT_NAME = "Held Back";
+  public static final String HELD_BACK_MESSAGE_PREFIX = "__held_back__";
+
+  public static class Values {
+    public static final String DETECT = "(detect)";
+    public static final String RESOURCES_VARIABLE = "__Android Resources";
+    public static final String ACTION_ARG = "__name__";
+    public static final String CHAIN_MESSAGE_ARG = "Chained message";
+    public static final String DEFAULT_PUSH_ACTION = "Open action";
+    public static final String CHAIN_MESSAGE_ACTION_NAME = "Chain to Existing Message";
+    public static final String DEFAULT_PUSH_MESSAGE = "Push message goes here.";
+    public static final String SDK_LOG = "sdkLog";
+    public static final String SDK_ERROR = "sdkError";
+    public static final String FILE_PREFIX = "__file__";
+  }
+
+  public static class Crypt {
+    public static final int ITER_COUNT = 1000;
+    public static final int KEY_LENGTH = 256;
+    public static final String SALT = "L3@nP1Vm"; // Must have 8 bytes
+    public static final String IV = "__l3anplum__iv__"; // Must have 16 bytes
+  }
+
+  public static class Messaging {
+    public static final int MAX_STORED_OCCURRENCES_PER_MESSAGE = 100;
+    public static final int DEFAULT_PRIORITY = 1000;
+  }
+
+  public static class ClassUtil {
+    public static final String UI_INTERFACE_EDITOR = "com.leanplum.uieditor.LeanplumUIEditor";
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/FileManager.java
@@ -0,0 +1,501 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+
+import com.leanplum.Leanplum;
+import com.leanplum.Var;
+
+import org.json.JSONObject;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Leanplum file manager.
+ *
+ * @author Andrew First
+ */
+public class FileManager {
+  interface ResourceUpdateCallback {
+    void onResourceSyncFinish();
+  }
+
+  private static ResourceUpdateCallback updateCallback;
+  private static boolean isInitialized = false;
+  private static boolean initializing = false;
+  static final Object initializingLock = new Object();
+  public static Var<HashMap<String, Object>> resources = null;
+
+  public enum DownloadFileResult {
+    NONE,
+    EXISTS_IN_ASSETS,
+    DOWNLOADING
+  }
+
+  static class HashResults {
+    final String hash;
+    final int size;
+
+    public HashResults(String hash, int size) {
+      this.hash = hash;
+      this.size = size;
+    }
+  }
+
+  public static DownloadFileResult maybeDownloadFile(boolean isResource, String stringValue,
+      String defaultValue, String urlValue, final Runnable onComplete) {
+    if (stringValue != null && !stringValue.equals(defaultValue) &&
+        (!isResource || VarCache.getResIdFromPath(stringValue) == 0)) {
+      InputStream inputStream = null;
+      try {
+        Context context = Leanplum.getContext();
+        inputStream = context.getResources().getAssets().open(stringValue);
+        if (inputStream != null) {
+          return DownloadFileResult.EXISTS_IN_ASSETS;
+        }
+      } catch (IOException ignored) {
+      } finally {
+        if (inputStream != null) {
+          try {
+            inputStream.close();
+          } catch (IOException e) {
+            Log.w("Failed to close InputStream.", e.getMessage());
+          }
+        }
+      }
+      String realPath = FileManager.fileRelativeToAppBundle(stringValue);
+      if (!FileManager.fileExistsAtPath(realPath)) {
+        realPath = FileManager.fileRelativeToDocuments(stringValue);
+        if (!FileManager.fileExistsAtPath(realPath)) {
+          Request downloadRequest = Request.get(Constants.Methods.DOWNLOAD_FILE, null);
+          downloadRequest.onResponse(new Request.ResponseCallback() {
+            @Override
+            public void response(JSONObject response) {
+              if (onComplete != null) {
+                onComplete.run();
+              }
+            }
+          });
+          downloadRequest.onError(new Request.ErrorCallback() {
+            @Override
+            public void error(Exception e) {
+              if (onComplete != null) {
+                onComplete.run();
+              }
+            }
+          });
+          downloadRequest.downloadFile(stringValue, urlValue);
+          return DownloadFileResult.DOWNLOADING;
+        }
+      }
+    }
+    return DownloadFileResult.NONE;
+  }
+
+  static HashResults fileMD5HashCreateWithPath(InputStream is) {
+    try {
+      MessageDigest md = MessageDigest.getInstance("MD5");
+      int size = 0;
+      try {
+        is = new DigestInputStream(is, md);
+        byte[] buffer = new byte[8192];
+        int bytesRead;
+        while ((bytesRead = is.read(buffer)) != -1) {
+          size += bytesRead;
+        }
+      } finally {
+        if (is != null) {
+          try {
+            is.close();
+          } catch (IOException e) {
+            Log.w("Failed to close InputStream.", e.getMessage());
+          }
+        }
+      }
+      byte[] digest = md.digest();
+
+      StringBuilder hexString = new StringBuilder();
+      for (byte dig : digest) {
+        String hex = Integer.toHexString(0xFF & dig);
+        if (hex.length() == 1) {
+          hexString.append('0');
+        }
+        hexString.append(hex);
+      }
+      return new HashResults(hexString.toString(), size);
+    } catch (NoSuchAlgorithmException e) {
+      e.printStackTrace();
+      return null;
+    } catch (IOException e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+
+  static int getFileSize(String path) {
+    if (path == null) {
+      return -1;
+    }
+    return (int) new File(path).length();
+  }
+
+  public static boolean fileExistsAtPath(String path) {
+    return path != null && new File(path).exists();
+  }
+
+  @SuppressWarnings("SameReturnValue")
+  private static String appBundlePath() {
+    return "";
+  }
+
+  private static String documentsPath() {
+    Context context = Leanplum.getContext();
+    if (context != null) {
+      return context.getDir("Leanplum_Documents", Context.MODE_PRIVATE).getAbsolutePath();
+    }
+    return null;
+  }
+
+  private static String bundlePath() {
+    Context context = Leanplum.getContext();
+    return context.getDir("Leanplum_Bundle", Context.MODE_PRIVATE).getAbsolutePath();
+  }
+
+  private static String fileRelativeTo(String root, String path) {
+    return root + "/" + path;
+  }
+
+  static String fileRelativeToAppBundle(String path) {
+    if (path == null) {
+      return null;
+    }
+    return fileRelativeTo(appBundlePath(), path);
+  }
+
+  static String fileRelativeToLPBundle(String path) {
+    if (path == null) {
+      return null;
+    }
+    return fileRelativeTo(bundlePath(), path);
+  }
+
+  public static String fileRelativeToDocuments(String path) {
+    if (path == null) {
+      return null;
+    }
+    return fileRelativeTo(documentsPath(), path);
+  }
+
+  static boolean isNewerLocally(
+      Map<String, Object> localAttributes,
+      Map<String, Object> serverAttributes) {
+    if (serverAttributes == null) {
+      return true;
+    }
+    String localHash = (String) localAttributes.get(Constants.Keys.HASH);
+    String serverHash = (String) serverAttributes.get(Constants.Keys.HASH);
+    Integer localSize = (Integer) localAttributes.get(Constants.Keys.SIZE);
+    Integer serverSize = (Integer) serverAttributes.get(Constants.Keys.SIZE);
+    return (serverSize == null || (localSize != null && !localSize.equals(serverSize))) ||
+        (localHash != null && (serverHash == null || !localHash.equals(serverHash)));
+  }
+
+  static void setResourceSyncFinishBlock(ResourceUpdateCallback callback) {
+    updateCallback = callback;
+  }
+
+  static boolean initializing() {
+    return initializing;
+  }
+
+  public static boolean isResourceSyncingEnabled() {
+    return initializing || isInitialized;
+  }
+
+  private static void enableResourceSyncing(List<Pattern> patternsToInclude,
+      List<Pattern> patternsToExclude) {
+    resources = Var.define(Constants.Values.RESOURCES_VARIABLE, new HashMap<String, Object>());
+
+    // This is from http://stackoverflow.com/questions/3052964/is-there-any-way-to-tell-what-folder-a-drawable-resource-was-inflated-from.
+    String drawableDirPrefix = "res/drawable";
+    String layoutDirPrefix = "res/layout";
+    ZipInputStream apk = null;
+    Context context = Leanplum.getContext();
+    try {
+      apk = new ZipInputStream(new FileInputStream(context.getPackageResourcePath()));
+      ZipEntry entry;
+      while ((entry = apk.getNextEntry()) != null) {
+        String resourcePath = entry.getName();
+        if (resourcePath.startsWith(drawableDirPrefix) ||
+            resourcePath.startsWith(layoutDirPrefix)) {
+          String unprefixedResourcePath = resourcePath.substring(4);
+
+          if (patternsToInclude != null &&
+              patternsToInclude.size() > 0) {
+            boolean included = false;
+            for (Pattern pattern : patternsToInclude) {
+              if (pattern.matcher(unprefixedResourcePath).matches()) {
+                included = true;
+                break;
+              }
+            }
+            if (!included) {
+              continue;
+            }
+          }
+          if (patternsToExclude != null) {
+            boolean excluded = false;
+            for (Pattern pattern : patternsToExclude) {
+              if (pattern.matcher(unprefixedResourcePath).matches()) {
+                excluded = true;
+                break;
+              }
+            }
+            if (excluded) {
+              continue;
+            }
+          }
+
+          ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+          int bytesRead;
+          int size = 0;
+          byte[] buffer = new byte[8192];
+          while ((bytesRead = apk.read(buffer)) != -1) {
+            outputStream.write(buffer, 0, bytesRead);
+            size += bytesRead;
+          }
+          apk.closeEntry();
+
+          String hash = ("" + entry.getTime()) + ("" + size);
+
+          Var.defineResource(
+              Constants.Values.RESOURCES_VARIABLE
+                  + "." + unprefixedResourcePath.replace(".", "\\.").replace('/', '.'),
+              resourcePath, size, hash, outputStream.toByteArray());
+        }
+      }
+    } catch (IOException e) {
+      Log.w("Error occurred when trying " +
+          "to enable resource syncing." + e.getMessage());
+    } finally {
+      if (apk != null) {
+        try {
+          apk.close();
+        } catch (IOException e) {
+          Log.w("Failed to close ZipInputStream.", e.getMessage());
+        }
+      }
+    }
+    isInitialized = true;
+    synchronized (initializingLock) {
+      initializing = false;
+      if (updateCallback != null) {
+        updateCallback.onResourceSyncFinish();
+      }
+    }
+  }
+
+  private static List<Pattern> compilePatterns(List<String> patterns) {
+    if (patterns == null) {
+      return new ArrayList<>(0);
+    }
+    List<Pattern> compiledPatterns = new ArrayList<>(patterns.size());
+    for (String pattern : patterns) {
+      try {
+        compiledPatterns.add(Pattern.compile(pattern));
+      } catch (PatternSyntaxException e) {
+        Log.e("Ignoring malformed resource syncing pattern: \"" + pattern +
+            "\". Patterns must be regular expressions.");
+      }
+    }
+    return compiledPatterns;
+  }
+
+  public static void enableResourceSyncing(final List<String> patternsToInclude,
+      final List<String> patternsToExclude, boolean isAsync) {
+    initializing = true;
+    if (isInitialized) {
+      return;
+    }
+
+    try {
+      final List<Pattern> compiledIncludePatterns = compilePatterns(patternsToInclude);
+      final List<Pattern> compiledExcludePatterns = compilePatterns(patternsToExclude);
+
+      if (isAsync) {
+        Util.executeAsyncTask(new AsyncTask<Void, Void, Void>() {
+          @Override
+          protected Void doInBackground(Void... params) {
+            try {
+              enableResourceSyncing(compiledIncludePatterns, compiledExcludePatterns);
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+            return null;
+          }
+        });
+      } else {
+        enableResourceSyncing(compiledIncludePatterns, compiledExcludePatterns);
+      }
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Returns an String with path for a specified file/resource/asset variable.
+   *
+   * @param stringValue Name of the file.
+   * @return String Path for a given variable.
+   */
+  public static String fileValue(String stringValue) {
+    return fileValue(stringValue, stringValue, null);
+  }
+
+  public static String fileValue(String stringValue, String defaultValue,
+      Boolean valueIsInAssets) {
+    String result;
+    if (stringValue == null) {
+      return null;
+    }
+    if (stringValue.equals(defaultValue)) {
+      result = FileManager.fileRelativeToAppBundle(defaultValue);
+      if (FileManager.fileExistsAtPath(result)) {
+        return result;
+      }
+    }
+
+    if (valueIsInAssets == null) {
+      InputStream inputStream = null;
+      try {
+        Context context = Leanplum.getContext();
+        inputStream = context.getAssets().open(stringValue);
+        return stringValue;
+      } catch (Exception ignored) {
+      } finally {
+        if (inputStream != null) {
+          try {
+            inputStream.close();
+          } catch (Exception e) {
+            Log.w("Failed to close InputStream: " + e);
+          }
+        }
+      }
+    } else if (valueIsInAssets) {
+      return stringValue;
+    }
+
+    result = FileManager.fileRelativeToLPBundle(stringValue);
+    if (!FileManager.fileExistsAtPath(result)) {
+      result = FileManager.fileRelativeToDocuments(stringValue);
+      if (!FileManager.fileExistsAtPath(result)) {
+        result = FileManager.fileRelativeToAppBundle(stringValue);
+        if (!FileManager.fileExistsAtPath(result)) {
+          result = FileManager.fileRelativeToLPBundle(defaultValue);
+          if (!FileManager.fileExistsAtPath(result)) {
+            result = FileManager.fileRelativeToAppBundle(defaultValue);
+            if (!FileManager.fileExistsAtPath(result)) {
+              return defaultValue;
+            }
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns an InputStream for a specified file/resource/asset variable. It will automatically find
+   * a proper file based on provided data. File can be located in either assets, res or in-memory.
+   * Caller is responsible for closing the returned InputStream.
+   *
+   * @param isResource Whether variable is resource.
+   * @param isAsset Whether variable is asset.
+   * @param valueIsInAssets Whether variable is located in assets directory.
+   * @param value Name of the file.
+   * @param defaultValue Default name of the file.
+   * @param resourceData Data if file is not located on internal storage.
+   * @return InputStream for a given variable.
+   */
+  public static InputStream stream(boolean isResource, Boolean isAsset, Boolean valueIsInAssets,
+      String value, String defaultValue, byte[] resourceData) {
+    if (TextUtils.isEmpty(value)) {
+      return null;
+    }
+    try {
+      Context context = Leanplum.getContext();
+      if (isResource && value.equals(defaultValue) && resourceData != null) {
+        return new ByteArrayInputStream(resourceData);
+      } else if (isResource && value.equals(defaultValue) && resourceData == null) {
+        // Convert resource name into resource id.
+        int resourceId = Util.generateIdFromResourceName(value);
+        // Android only generates id's greater then 0.
+        if (resourceId != 0) {
+          Resources res = context.getResources();
+          // Based on resource Id, we can extract package it belongs, directory where it is stored
+          // and name of the file.
+          Uri resourceUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
+              "://" + res.getResourcePackageName(resourceId)
+              + '/' + res.getResourceTypeName(resourceId)
+              + '/' + res.getResourceEntryName(resourceId));
+          return context.getContentResolver().openInputStream(resourceUri);
+        }
+        return null;
+      }
+      if (valueIsInAssets == null) {
+        try {
+          return context.getAssets().open(value);
+        } catch (IOException ignored) {
+        }
+      } else if (valueIsInAssets || (isAsset && value.equals(defaultValue))) {
+        return context.getAssets().open(value);
+      }
+      return new FileInputStream(new File(value));
+    } catch (IOException e) {
+      Log.w("Failed to load a stream." + e.getMessage());
+      return null;
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/HybiParser.java
@@ -0,0 +1,422 @@
+//
+// HybiParser.java: draft-ietf-hybi-thewebsocketprotocol-13 parser
+//
+// Based on code from the faye project.
+// https://github.com/faye/faye-websocket-node
+// Copyright (c) 2009-2012 James Coglan
+//
+// Ported from Javascript to Java by Eric Butler <eric@codebutler.com>
+//
+// (The MIT License)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package com.leanplum.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.List;
+
+class HybiParser {
+  private WebSocketClient mClient;
+
+  private boolean mMasking = true;
+
+  private int mStage;
+
+  private boolean mFinal;
+  private boolean mMasked;
+  private int mOpcode;
+  private int mLengthSize;
+  private int mLength;
+  private int mMode;
+
+  private byte[] mMask = new byte[0];
+  private byte[] mPayload = new byte[0];
+
+  private boolean mClosed = false;
+
+  private ByteArrayOutputStream mBuffer = new ByteArrayOutputStream();
+
+  private static final int BYTE = 255;
+  private static final int FIN = 128;
+  private static final int MASK = 128;
+  private static final int RSV1 = 64;
+  private static final int RSV2 = 32;
+  private static final int RSV3 = 16;
+  private static final int OPCODE = 15;
+  private static final int LENGTH = 127;
+
+  private static final int MODE_TEXT = 1;
+  private static final int MODE_BINARY = 2;
+
+  private static final int OP_CONTINUATION = 0;
+  private static final int OP_TEXT = 1;
+  private static final int OP_BINARY = 2;
+  private static final int OP_CLOSE = 8;
+  private static final int OP_PING = 9;
+  private static final int OP_PONG = 10;
+
+  private static final List<Integer> OPCODES = Arrays.asList(OP_CONTINUATION,
+      OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG);
+
+  private static final List<Integer> FRAGMENTED_OPCODES = Arrays.asList(
+      OP_CONTINUATION, OP_TEXT, OP_BINARY);
+
+  public HybiParser(WebSocketClient client) {
+    mClient = client;
+  }
+
+  private static byte[] mask(byte[] payload, byte[] mask, int offset) {
+    if (mask.length == 0)
+      return payload;
+
+    for (int i = 0; i < payload.length - offset; i++) {
+      payload[offset + i] = (byte) (payload[offset + i] ^ mask[i % 4]);
+    }
+    return payload;
+  }
+
+  public void start(HappyDataInputStream stream) throws IOException {
+    while (true) {
+      if (stream.available() == -1)
+        break;
+      switch (mStage) {
+        case 0:
+          parseOpcode(stream.readByte());
+          break;
+        case 1:
+          parseLength(stream.readByte());
+          break;
+        case 2:
+          parseExtendedLength(stream.readBytes(mLengthSize));
+          break;
+        case 3:
+          mMask = stream.readBytes(4);
+          mStage = 4;
+          break;
+        case 4:
+          mPayload = stream.readBytes(mLength);
+          emitFrame();
+          mStage = 0;
+          break;
+        default:
+          break;
+      }
+    }
+    mClient.getListener().onDisconnect(0, "EOF");
+  }
+
+  private void parseOpcode(byte data) throws ProtocolError {
+    boolean rsv1 = (data & RSV1) == RSV1;
+    boolean rsv2 = (data & RSV2) == RSV2;
+    boolean rsv3 = (data & RSV3) == RSV3;
+
+    if (rsv1 || rsv2 || rsv3) {
+      throw new ProtocolError("RSV not zero");
+    }
+
+    mFinal = (data & FIN) == FIN;
+    mOpcode = (data & OPCODE);
+    mMask = new byte[0];
+    mPayload = new byte[0];
+
+    if (!OPCODES.contains(mOpcode)) {
+      throw new ProtocolError("Bad opcode");
+    }
+
+    if (!FRAGMENTED_OPCODES.contains(mOpcode) && !mFinal) {
+      throw new ProtocolError("Expected non-final packet");
+    }
+
+    mStage = 1;
+  }
+
+  private void parseLength(byte data) {
+    mMasked = (data & MASK) == MASK;
+    mLength = (data & LENGTH);
+
+    if (mLength >= 0 && mLength <= 125) {
+      mStage = mMasked ? 3 : 4;
+    } else {
+      mLengthSize = (mLength == 126) ? 2 : 8;
+      mStage = 2;
+    }
+  }
+
+  private void parseExtendedLength(byte[] buffer) throws ProtocolError {
+    mLength = getInteger(buffer);
+    mStage = mMasked ? 3 : 4;
+  }
+
+  public byte[] frame(String data) {
+    return frame(data, OP_TEXT, -1);
+  }
+
+  public byte[] frame(byte[] data) {
+    return frame(data, OP_BINARY, -1);
+  }
+
+  private byte[] frame(byte[] data, int opcode, int errorCode) {
+    return frame((Object) data, opcode, errorCode);
+  }
+
+  private byte[] frame(String data, int opcode, int errorCode) {
+    return frame((Object) data, opcode, errorCode);
+  }
+
+  private byte[] frame(Object data, int opcode, int errorCode) {
+    if (mClosed)
+      return null;
+
+    // Log.d("Creating frame for: " + data + " op: " + opcode + " err: " +
+    // errorCode);
+
+    byte[] buffer = (data instanceof String) ? decode((String) data)
+        : (byte[]) data;
+    int insert = (errorCode > 0) ? 2 : 0;
+    int length = buffer.length + insert;
+    int header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10);
+    int offset = header + (mMasking ? 4 : 0);
+    int masked = mMasking ? MASK : 0;
+    byte[] frame = new byte[length + offset];
+
+    frame[0] = (byte) ((byte) FIN | (byte) opcode);
+
+    if (length <= 125) {
+      frame[1] = (byte) (masked | length);
+    } else if (length <= 65535) {
+      frame[1] = (byte) (masked | 126);
+      frame[2] = (byte) Math.floor(length / 256f);
+      frame[3] = (byte) (length & BYTE);
+    } else {
+      frame[1] = (byte) (masked | 127);
+      frame[2] = (byte) (((int) Math.floor(length / Math.pow(2, 56))) & BYTE);
+      frame[3] = (byte) (((int) Math.floor(length / Math.pow(2, 48))) & BYTE);
+      frame[4] = (byte) (((int) Math.floor(length / Math.pow(2, 40))) & BYTE);
+      frame[5] = (byte) (((int) Math.floor(length / Math.pow(2, 32))) & BYTE);
+      frame[6] = (byte) (((int) Math.floor(length / Math.pow(2, 24))) & BYTE);
+      frame[7] = (byte) (((int) Math.floor(length / Math.pow(2, 16))) & BYTE);
+      frame[8] = (byte) (((int) Math.floor(length / Math.pow(2, 8))) & BYTE);
+      frame[9] = (byte) (length & BYTE);
+    }
+
+    if (errorCode > 0) {
+      frame[offset] = (byte) (((int) Math.floor(errorCode / 256f)) & BYTE);
+      frame[offset + 1] = (byte) (errorCode & BYTE);
+    }
+    System.arraycopy(buffer, 0, frame, offset + insert, buffer.length);
+
+    if (mMasking) {
+      byte[] mask = {(byte) Math.floor(Math.random() * 256),
+          (byte) Math.floor(Math.random() * 256),
+          (byte) Math.floor(Math.random() * 256),
+          (byte) Math.floor(Math.random() * 256)};
+      System.arraycopy(mask, 0, frame, header, mask.length);
+      mask(frame, mask, offset);
+    }
+
+    return frame;
+  }
+
+  public void ping(String message) {
+    mClient.send(frame(message, OP_PING, -1));
+  }
+
+  public void close(int code, String reason) {
+    if (mClosed)
+      return;
+    mClient.send(frame(reason, OP_CLOSE, code));
+    mClosed = true;
+  }
+
+  private void emitFrame() throws IOException {
+    byte[] payload = mask(mPayload, mMask, 0);
+    int opcode = mOpcode;
+
+    if (opcode == OP_CONTINUATION) {
+      if (mMode == 0) {
+        throw new ProtocolError("Mode was not set.");
+      }
+      mBuffer.write(payload);
+      if (mFinal) {
+        byte[] message = mBuffer.toByteArray();
+        if (mMode == MODE_TEXT) {
+          mClient.getListener().onMessage(encode(message));
+        } else {
+          mClient.getListener().onMessage(message);
+        }
+        reset();
+      }
+
+    } else if (opcode == OP_TEXT) {
+      if (mFinal) {
+        String messageText = encode(payload);
+        mClient.getListener().onMessage(messageText);
+      } else {
+        mMode = MODE_TEXT;
+        mBuffer.write(payload);
+      }
+
+    } else if (opcode == OP_BINARY) {
+      if (mFinal) {
+        mClient.getListener().onMessage(payload);
+      } else {
+        mMode = MODE_BINARY;
+        mBuffer.write(payload);
+      }
+
+    } else if (opcode == OP_CLOSE) {
+      int code = (payload.length >= 2) ? 256 * payload[0] + payload[1] : 0;
+      String reason = (payload.length > 2) ? encode(slice(payload, 2)) : null;
+      // Log.d("Got close op! " + code + " " + reason);
+      mClient.getListener().onDisconnect(code, reason);
+
+    } else if (opcode == OP_PING) {
+      if (payload.length > 125) {
+        throw new ProtocolError("Ping payload too large");
+      }
+      // Log.d("Sending pong!!");
+      mClient.sendFrame(frame(payload, OP_PONG, -1));
+
+    } else if (opcode == OP_PONG) {
+      // String message = encode(payload);
+      // FIXME: Fire callback...
+      // Log.d("Got pong! " + message);
+    }
+  }
+
+  private void reset() {
+    mMode = 0;
+    mBuffer.reset();
+  }
+
+  private String encode(byte[] buffer) {
+    try {
+      return new String(buffer, "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private byte[] decode(String string) {
+    try {
+      return (string).getBytes("UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private int getInteger(byte[] bytes) throws ProtocolError {
+    long i = byteArrayToLong(bytes, 0, bytes.length);
+    if (i < 0 || i > Integer.MAX_VALUE) {
+      throw new ProtocolError("Bad integer: " + i);
+    }
+    return (int) i;
+  }
+
+  /**
+   * Copied from AOSP Arrays.java.
+   */
+  /**
+   * Copies elements from {@code original} into a new array, from indexes start (inclusive) to end
+   * (exclusive). The original order of elements is preserved. If {@code end} is greater than {@code
+   * original.length}, the result is padded with the value {@code (byte) 0}.
+   *
+   * @param original the original array
+   * @param start the start index, inclusive
+   * @param end the end index, exclusive
+   * @return the new array
+   * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}
+   * @throws IllegalArgumentException if {@code start > end}
+   * @throws NullPointerException if {@code original == null}
+   * @since 1.6
+   */
+  private static byte[] copyOfRange(byte[] original, int start, int end) {
+    if (start > end) {
+      throw new IllegalArgumentException();
+    }
+    int originalLength = original.length;
+    if (start < 0 || start > originalLength) {
+      throw new ArrayIndexOutOfBoundsException();
+    }
+    int resultLength = end - start;
+    int copyLength = Math.min(resultLength, originalLength - start);
+    byte[] result = new byte[resultLength];
+    System.arraycopy(original, start, result, 0, copyLength);
+    return result;
+  }
+
+  private byte[] slice(byte[] array, int start) {
+    return copyOfRange(array, start, array.length);
+  }
+
+  @SuppressWarnings("serial")
+  static class ProtocolError extends IOException {
+    public ProtocolError(String detailMessage) {
+      super(detailMessage);
+    }
+  }
+
+  private static long byteArrayToLong(byte[] b, int offset, int length) {
+    if (b.length < length)
+      throw new IllegalArgumentException(
+          "length must be less than or equal to b.length");
+
+    long value = 0;
+    for (int i = 0; i < length; i++) {
+      int shift = (length - 1 - i) * 8;
+      value += (b[i + offset] & 0x000000FF) << shift;
+    }
+    return value;
+  }
+
+  static class HappyDataInputStream extends DataInputStream {
+    public HappyDataInputStream(InputStream in) {
+      super(in);
+    }
+
+    public byte[] readBytes(int length) throws IOException {
+      byte[] buffer = new byte[length];
+
+      int total = 0;
+
+      while (total < length) {
+        int count = read(buffer, total, length - total);
+        if (count == -1) {
+          break;
+        }
+        total += count;
+      }
+
+      if (total != length) {
+        throw new IOException(
+            String.format("Read wrong number of bytes. Got: %s, Expected: %s.",
+                total, length));
+      }
+
+      return buffer;
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/JsonConverter.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.text.Editable;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Converts objects to/from JSON.
+ *
+ * @author Andrew First
+ */
+public class JsonConverter {
+  public static String toJson(Map<String, ?> map) {
+    if (map == null) {
+      return null;
+    }
+    try {
+      return mapToJsonObject(map).toString();
+    } catch (JSONException e) {
+      Log.e("Error converting " + map + " to JSON", e);
+      return null;
+    }
+  }
+
+  public static Map<String, Object> fromJson(String json) {
+    if (json == null) {
+      return null;
+    }
+    try {
+      return mapFromJson(new JSONObject(json));
+    } catch (JSONException e) {
+      Log.e("Error converting " + json + " from JSON", e);
+      return null;
+    }
+  }
+
+  public static JSONObject mapToJsonObject(Map<String, ?> map) throws JSONException {
+    if (map == null) {
+      return null;
+    }
+    JSONObject obj = new JSONObject();
+    for (Map.Entry<String, ?> entry : map.entrySet()) {
+      String key = entry.getKey();
+      Object value = entry.getValue();
+      if (value instanceof Map) {
+        Map<String, ?> mappedValue = CollectionUtil.uncheckedCast(value);
+        value = mapToJsonObject(mappedValue);
+      } else if (value instanceof Iterable) {
+        value = listToJsonArray((Iterable<?>) value);
+      } else if (value instanceof Editable) {
+        value = value.toString();
+      } else if (value == null) {
+        value = JSONObject.NULL;
+      }
+      obj.put(key, value);
+    }
+    return obj;
+  }
+
+
+  public static JSONArray listToJsonArray(Iterable<?> list) throws JSONException {
+    if (list == null) {
+      return null;
+    }
+    JSONArray obj = new JSONArray();
+    for (Object value : list) {
+      if (value instanceof Map) {
+        Map<String, ?> mappedValue = CollectionUtil.uncheckedCast(value);
+        value = mapToJsonObject(mappedValue);
+      } else if (value instanceof Iterable) {
+        value = listToJsonArray((Iterable<?>) value);
+      } else if (value == null) {
+        value = JSONObject.NULL;
+      }
+      obj.put(value);
+    }
+    return obj;
+  }
+
+  public static <T> Map<String, T> mapFromJson(JSONObject object) {
+    if (object == null) {
+      return null;
+    }
+    Map<String, T> result = new HashMap<>();
+    Iterator<?> keysIterator = object.keys();
+    while (keysIterator.hasNext()) {
+      String key = (String) keysIterator.next();
+      Object value = object.opt(key);
+      if (value == null || value == JSONObject.NULL) {
+        value = null;
+      } else if (value instanceof JSONObject) {
+        value = mapFromJson((JSONObject) value);
+      } else if (value instanceof JSONArray) {
+        value = listFromJson((JSONArray) value);
+      } else if (JSONObject.NULL.equals(value)) {
+        value = null;
+      }
+      T castedValue = CollectionUtil.uncheckedCast(value);
+      result.put(key, castedValue);
+    }
+    return result;
+  }
+
+  public static <T> Map<String, T> mapFromJsonOrDefault(JSONObject object) {
+    if (object == null) {
+      return new HashMap<>();
+    }
+    return mapFromJson(object);
+  }
+
+  public static <T> List<T> listFromJson(JSONArray json) {
+    if (json == null) {
+      return null;
+    }
+    List<Object> result = new ArrayList<>(json.length());
+    for (int i = 0; i < json.length(); i++) {
+      Object value = json.opt(i);
+      if (value == null || value == JSONObject.NULL) {
+        value = null;
+      } else if (value instanceof JSONObject) {
+        value = mapFromJson((JSONObject) value);
+      } else if (value instanceof JSONArray) {
+        value = listFromJson((JSONArray) value);
+      } else if (JSONObject.NULL.equals(value)) {
+        value = null;
+      }
+      result.add(value);
+    }
+    return CollectionUtil.uncheckedCast(result);
+  }
+
+  public static <T> List<T> listFromJsonOrDefault(JSONArray json) {
+    if (json == null) {
+      return new ArrayList<>();
+    }
+    return listFromJson(json);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumInternal.java
@@ -0,0 +1,666 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.location.Address;
+import android.location.Geocoder;
+import android.location.Location;
+import android.os.AsyncTask;
+
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.LeanplumException;
+import com.leanplum.LeanplumLocationAccuracyType;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.StartCallback;
+import com.leanplum.callbacks.VariablesChangedCallback;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Internal leanplum methods that are very generic but should not be exposed to the public.
+ *
+ * @author Ben Marten
+ */
+public class LeanplumInternal {
+  private static final String ACTION = "action";
+  private static boolean hasStartedAndRegisteredAsDeveloper;
+  private static final Map<String, List<ActionCallback>> actionHandlers = new HashMap<>();
+  private static boolean issuedStart;
+  private static boolean hasStarted;
+  private static boolean startSuccessful;
+  private static boolean calledStart;
+  private static boolean isPaused;
+
+  private static boolean startedInBackground;
+  private static boolean inForeground;
+  private static final Object inForegroundLock = new Object();
+  private static final Queue<Map<String, ?>> userAttributeChanges = new ConcurrentLinkedQueue<>();
+  private static final ArrayList<Runnable> startIssuedHandlers = new ArrayList<>();
+  private static boolean isScreenTrackingEnabled = false;
+
+  private static void onHasStartedAndRegisteredAsDeveloperAndFinishedSyncing() {
+    if (!hasStartedAndRegisteredAsDeveloper) {
+      hasStartedAndRegisteredAsDeveloper = true;
+    }
+  }
+
+  /**
+   * Called when the development mode has started and the device is registered successfully.
+   */
+  public static void onHasStartedAndRegisteredAsDeveloper() {
+    synchronized (FileManager.initializingLock) {
+      if (FileManager.initializing()) {
+        FileManager.setResourceSyncFinishBlock(new FileManager.ResourceUpdateCallback() {
+          @Override
+          public void onResourceSyncFinish() {
+            try {
+              onHasStartedAndRegisteredAsDeveloperAndFinishedSyncing();
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+          }
+        });
+      } else {
+        onHasStartedAndRegisteredAsDeveloperAndFinishedSyncing();
+      }
+    }
+  }
+
+  public static void triggerAction(ActionContext context) {
+    triggerAction(context, null);
+  }
+
+  private static void triggerAction(final ActionContext context,
+      final VariablesChangedCallback handledCallback) {
+    List<ActionCallback> callbacks;
+    synchronized (actionHandlers) {
+      List<ActionCallback> handlers = actionHandlers.get(context.actionName());
+      if (handlers == null) {
+        // Handled by default.
+        if (handledCallback != null) {
+          handledCallback.variablesChanged();
+        }
+        return;
+      }
+      callbacks = new ArrayList<>(handlers);
+    }
+    final AtomicBoolean handled = new AtomicBoolean(false);
+    for (final ActionCallback callback : callbacks) {
+      OsHandler.getInstance().post(new Runnable() {
+        @Override
+        public void run() {
+          if (callback.onResponse(context) && handledCallback != null) {
+            if (!handled.getAndSet(true)) {
+              handledCallback.variablesChanged();
+            }
+          }
+        }
+      });
+    }
+  }
+
+  public static void maybePerformActions(String when, String eventName, int filter,
+      String fromMessageId, ActionContext.ContextualValues contextualValues) {
+    maybePerformActions(new String[] {when}, eventName, filter, fromMessageId, contextualValues);
+  }
+
+  static void maybePerformActions(String[] whenConditions, String eventName, int filter,
+      String fromMessageId, ActionContext.ContextualValues contextualValues) {
+    Map<String, Object> messages = VarCache.messages();
+    if (messages == null) {
+      return;
+    }
+
+    ArrayList<ActionContext> actionContexts = new ArrayList<>();
+    for (final String messageId : messages.keySet()) {
+      if (messageId != null && messageId.equals(fromMessageId)) {
+        continue;
+      }
+
+      Map<String, Object> messageConfig = CollectionUtil.uncheckedCast(messages.get(messageId));
+
+      String actionType = (String) messageConfig.get(ACTION);
+      if (actionType == null) {
+        continue;
+      }
+
+      final String internalMessageId;
+      if (actionType.equals(ActionManager.HELD_BACK_ACTION_NAME)) {
+        // Spoof the message ID for held back messages,
+        // and store the original ID for the track event.
+        internalMessageId = Constants.HELD_BACK_MESSAGE_PREFIX + messageId;
+      } else {
+        // If this is not a holdback, the internal message ID is the same as the original.
+        internalMessageId = messageId;
+      }
+
+      boolean isForeground = !actionType.equals(ActionManager.PUSH_NOTIFICATION_ACTION_NAME);
+      if (isForeground &&
+          ((filter & LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_FOREGROUND) == 0)) {
+        continue;
+      }
+
+      ActionManager.MessageMatchResult result = new ActionManager.MessageMatchResult();
+      for (String when : whenConditions) {
+        ActionManager.MessageMatchResult conditionResult = ActionManager.getInstance()
+            .shouldShowMessage(internalMessageId, messageConfig, when, eventName, contextualValues);
+        result.matchedTrigger |= conditionResult.matchedTrigger;
+        result.matchedUnlessTrigger |= conditionResult.matchedUnlessTrigger;
+        result.matchedLimit |= conditionResult.matchedLimit;
+      }
+
+      // Make sure we cancel before matching in case the criteria overlap.
+      if (result.matchedUnlessTrigger) {
+        String cancelActionName = "__Cancel" + messageConfig.get(ACTION);
+        LeanplumInternal.triggerAction(new ActionContext(
+                cancelActionName, new HashMap<String, Object>(), messageId),
+            new VariablesChangedCallback() {
+              @Override
+              public void variablesChanged() {
+                // Track cancel.
+                try {
+                  Map<String, String> requestArgs = new HashMap<>();
+                  requestArgs.put(Constants.Params.MESSAGE_ID, messageId);
+                  track("Cancel", 0.0, null, null, requestArgs);
+                } catch (Throwable t) {
+                  Util.handleException(t);
+                }
+              }
+            });
+      }
+
+      if (result.matchedTrigger) {
+        ActionManager.getInstance().recordMessageTrigger(internalMessageId);
+
+        if (result.matchedLimit) {
+          int priority;
+          if (messageConfig.containsKey("priority")) {
+            priority = (int) messageConfig.get("priority");
+          } else {
+            priority = Constants.Messaging.DEFAULT_PRIORITY;
+          }
+          Map<String, Object> vars = CollectionUtil.uncheckedCast(messageConfig.get(Constants
+              .Keys.VARS));
+          ActionContext actionContext = new ActionContext(
+              messageConfig.get(ACTION).toString(),
+              vars,
+              internalMessageId,
+              messageId,
+              priority);
+          actionContext.setContextualValues(contextualValues);
+          actionContexts.add(actionContext);
+        }
+      }
+    }
+
+    if (!actionContexts.isEmpty()) {
+      Collections.sort(actionContexts);
+      int priorityThreshold = actionContexts.get(0).getPriority();
+      for (final ActionContext actionContext : actionContexts) {
+        if (actionContext.getPriority() <= priorityThreshold) {
+          if (actionContext.actionName().equals(ActionManager.HELD_BACK_ACTION_NAME)) {
+            ActionManager.getInstance().recordHeldBackImpression(
+                actionContext.getMessageId(), actionContext.getOriginalMessageId());
+          } else {
+            LeanplumInternal.triggerAction(actionContext, new VariablesChangedCallback() {
+              @Override
+              public void variablesChanged() {
+                try {
+                  ActionManager.getInstance().recordMessageImpression(actionContext.getMessageId());
+                } catch (Throwable t) {
+                  Util.handleException(t);
+                }
+              }
+            });
+          }
+        } else {
+          break;
+        }
+      }
+    }
+  }
+
+  public static void track(final String event, double value, String info,
+      Map<String, ?> params, Map<String, String> args) {
+    if (Constants.isNoop()) {
+      return;
+    }
+
+    try {
+      final Map<String, Object> requestParams = new HashMap<>();
+      if (args != null) {
+        requestParams.putAll(args);
+      }
+      requestParams.put(Constants.Params.VALUE, Double.toString(value));
+      requestParams.put(Constants.Params.INFO, info);
+      if (event != null) {
+        requestParams.put(Constants.Params.EVENT, event);
+      }
+      if (params != null) {
+        params = validateAttributes(params, "params", false);
+        requestParams.put(Constants.Params.PARAMS, JsonConverter.toJson(params));
+      }
+      if (!inForeground || LeanplumActivityHelper.isActivityPaused()) {
+        requestParams.put("allowOffline", Boolean.TRUE.toString());
+      }
+
+      trackInternalWhenStarted(event, params, requestParams);
+    } catch (Throwable t) {
+      Util.handleException(t);
+    }
+  }
+
+  /**
+   * Performs the track operation once Leanplum has started. If Leanplum is already started, perform
+   * the track immediately.
+   *
+   * @param event The event name. Event may be empty for message impression events.
+   * @param params The event parameters.
+   * @param requestArgs The arguments to send with the API request.
+   */
+  private static void trackInternalWhenStarted(final String event,
+      final Map<String, ?> params, final Map<String, Object> requestArgs) {
+    if (issuedStart) {
+      trackInternal(event, params, requestArgs);
+    } else {
+      addStartIssuedHandler(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            trackInternal(event, params, requestArgs);
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+        }
+      });
+    }
+  }
+
+  /**
+   * Performs the track API and any actions that are associated with the event.
+   *
+   * @param event The event name. Event may be empty for message impression events.
+   * @param params The event parameters.
+   * @param requestArgs The arguments to send with the API request.
+   */
+  private static void trackInternal(String event, Map<String, ?> params,
+      Map<String, Object> requestArgs) {
+    Request.post(Constants.Methods.TRACK, requestArgs).send();
+
+    String eventTriggerName = event;
+    String messageId = null;
+    if (requestArgs.get(Constants.Params.MESSAGE_ID) != null) {
+      messageId = requestArgs.get(Constants.Params.MESSAGE_ID).toString();
+      eventTriggerName = ".m" + messageId;
+      if (event != null && event.length() > 0) {
+        eventTriggerName += " " + event;
+      }
+    }
+
+    ActionContext.ContextualValues contextualValues = new ActionContext.ContextualValues();
+    contextualValues.parameters = params;
+    contextualValues.arguments = requestArgs;
+    if (contextualValues.arguments.containsKey(Constants.Params.PARAMS)) {
+      try {
+        contextualValues.arguments.put(Constants.Params.PARAMS,
+            new JSONObject(contextualValues.arguments.get(Constants.Params.PARAMS).toString()));
+      } catch (JSONException ignored) {
+      }
+    }
+    LeanplumInternal.maybePerformActions("event", eventTriggerName,
+        LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_ALL, messageId, contextualValues);
+  }
+
+  public static void performTrackedAction(String actionName, String messageId) {
+    Map<String, Object> messages = VarCache.messages();
+    if (messages == null) {
+      return;
+    }
+    Map<String, Object> messageConfig = CollectionUtil.uncheckedCast(messages.get(messageId));
+    if (messageConfig == null) {
+      return;
+    }
+    Map<String, Object> vars = CollectionUtil.uncheckedCast(messageConfig.get(Constants.Keys.VARS));
+    ActionContext context = new ActionContext(
+        messageConfig.get(ACTION).toString(),
+        vars,
+        messageId);
+    context.runTrackedActionNamed(actionName);
+  }
+
+  /**
+   * Callback for setUserLocationAttribute.
+   */
+  public interface locationAttributeRequestsCallback {
+    void response(boolean success);
+  }
+
+  /**
+   * Callback for setUserLocationAttribute.
+   *
+   * @param location Location of the device.
+   * @param locationAccuracyType LocationAccuracyType of the location.
+   * @param callback Callback for the requests was made.
+   */
+  public static void setUserLocationAttribute(final Location location,
+      final LeanplumLocationAccuracyType locationAccuracyType,
+      final locationAttributeRequestsCallback callback) {
+    Leanplum.addStartResponseHandler(new StartCallback() {
+      @Override
+      public void onResponse(final boolean success) {
+        // Geocoder query must be executed on background thread.
+        Util.executeAsyncTask(new AsyncTask<Void, Void, Void>() {
+          @Override
+          protected Void doInBackground(Void... voids) {
+            if (!success) {
+              return null;
+            }
+            if (location == null) {
+              Log.e("Location can't be null in setUserLocationAttribute.");
+              return null;
+            }
+            String latLongLocation = String.format(Locale.US, "%.6f,%.6f", location.getLatitude(),
+                location.getLongitude());
+            HashMap<String, Object> params = new HashMap<>();
+            params.put(Constants.Keys.LOCATION, latLongLocation);
+            params.put(Constants.Keys.LOCATION_ACCURACY_TYPE,
+                locationAccuracyType.name().toLowerCase());
+            if (Leanplum.getContext() != null && Locale.US != null) {
+              Geocoder geocoder = new Geocoder(Leanplum.getContext(), Locale.US);
+              try {
+                List<Address> addresses = geocoder.getFromLocation(location.getLatitude(),
+                    location.getLongitude(), 1);
+                if (addresses != null && addresses.size() > 0) {
+                  Address address = addresses.get(0);
+                  params.put(Constants.Keys.CITY, address.getLocality());
+                  params.put(Constants.Keys.REGION, address.getAdminArea());
+                  params.put(Constants.Keys.COUNTRY, address.getCountryCode());
+                }
+              } catch (IOException e) {
+                Log.e("Failed to connect to Geocoder: " + e);
+              }
+            }
+            Request req = Request.post(Constants.Methods.SET_USER_ATTRIBUTES, params);
+            req.onResponse(new Request.ResponseCallback() {
+              @Override
+              public void response(JSONObject response) {
+                callback.response(true);
+              }
+            });
+            req.onError(new Request.ErrorCallback() {
+              @Override
+              public void error(Exception e) {
+                callback.response(false);
+                Log.e("setUserAttributes failed when specifying location with error: " +
+                    e.getMessage());
+              }
+            });
+            req.send();
+            return null;
+          }
+        });
+      }
+    });
+  }
+
+  public static void recordAttributeChanges() {
+    boolean madeChanges = false;
+    for (Map<String, ?> attributes : userAttributeChanges) {
+      Map<String, Object> existingAttributes = VarCache.userAttributes();
+      if (existingAttributes == null) {
+        existingAttributes = new HashMap<>();
+      }
+      for (String attributeName : attributes.keySet()) {
+        Object existingValue = existingAttributes.get(attributeName);
+        Object value = attributes.get(attributeName);
+        if ((existingValue == null && value != null) ||
+            (existingValue != null && !existingValue.equals(value))) {
+          ActionContext.ContextualValues contextualValues = new ActionContext.ContextualValues();
+          contextualValues.previousAttributeValue = existingValue;
+          contextualValues.attributeValue = value;
+          existingAttributes.put(attributeName, value);
+          LeanplumInternal.maybePerformActions("userAttribute", attributeName,
+              LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_ALL, null, contextualValues);
+          madeChanges = true;
+        }
+      }
+    }
+    userAttributeChanges.clear();
+    if (madeChanges) {
+      VarCache.saveUserAttributes();
+    }
+  }
+
+  public static void moveToForeground() {
+    synchronized (inForegroundLock) {
+      if (inForeground) {
+        return;
+      }
+      inForeground = true;
+    }
+
+    Leanplum.addStartResponseHandler(new StartCallback() {
+      @Override
+      public void onResponse(boolean success) {
+        if (!success) {
+          return;
+        }
+        if (Constants.isDevelopmentModeEnabled && !Constants.isNoop()) {
+          Socket.getInstance();
+        }
+        maybePerformActions(new String[] {"start", "resume"}, null,
+            LeanplumMessageMatchFilter.LEANPLUM_ACTION_FILTER_ALL, null, null);
+        recordAttributeChanges();
+      }
+    });
+  }
+
+  public static void addStartIssuedHandler(Runnable handler) {
+    if (handler == null) {
+      Log.e("addStartIssuedHandler - Invalid handler parameter provided.");
+      return;
+    }
+
+    synchronized (startIssuedHandlers) {
+      if (!issuedStart) {
+        startIssuedHandlers.add(handler);
+        return;
+      }
+    }
+    handler.run();
+  }
+
+  public static void triggerStartIssued() {
+    synchronized (startIssuedHandlers) {
+      LeanplumInternal.setIssuedStart(true);
+      for (Runnable callback : startIssuedHandlers) {
+        OsHandler.getInstance().post(callback);
+      }
+      startIssuedHandlers.clear();
+    }
+  }
+
+  /**
+   * Validates that the attributes are of the correct format. User attributes must be Strings,
+   * Booleans, or Numbers.
+   *
+   * @param argName Argument name used for error messages.
+   * @param allowLists Whether attribute values can be lists.
+   */
+  public static <T> Map<String, T> validateAttributes(Map<String, T> attributes, String argName,
+      boolean allowLists) {
+    if (attributes == null) {
+      return null;
+    }
+    Map<String, T> validAttributes = new HashMap<>();
+    try {
+      for (Map.Entry<String, T> entry : attributes.entrySet()) {
+        T value = entry.getValue();
+
+        if (value == null) {
+          continue;
+        }
+
+        // Validate lists.
+        if (allowLists && value instanceof Iterable<?>) {
+          boolean valid = true;
+          Iterable<Object> iterable = CollectionUtil.uncheckedCast(value);
+          for (Object item : iterable) {
+            if (!isValidScalarValue(item, argName)) {
+              valid = false;
+              break;
+            }
+          }
+          if (!valid) {
+            continue;
+          }
+
+          // Validate scalars.
+        } else {
+          if (value instanceof Date) {
+            Date date = CollectionUtil.uncheckedCast(value);
+            value = CollectionUtil.uncheckedCast(date.getTime());
+          }
+          if (!isValidScalarValue(value, argName)) {
+            continue;
+          }
+        }
+        validAttributes.put(entry.getKey(), value);
+      }
+    } catch (ConcurrentModificationException e) {
+      maybeThrowException(new LeanplumException("ConcurrentModificationException: You cannot " +
+          "modify Map<String, ?> attributes/parameters. Will override with an empty map"));
+      validAttributes = new HashMap<>();
+    }
+    return validAttributes;
+  }
+
+  @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+  private static boolean isValidScalarValue(Object value, String argName) {
+    if (!(value instanceof Number) && !(value instanceof String) && !(value instanceof Boolean)) {
+      maybeThrowException(new LeanplumException(
+          argName + " values must be of type String, Number, or Boolean."));
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Throws a LeanplumException when in development mode. Otherwise, logs the exception to prevent
+   * the app from crashing.
+   */
+  public static void maybeThrowException(RuntimeException e) {
+    if (Constants.isDevelopmentModeEnabled) {
+      throw e;
+    } else {
+      Log.e(e.getMessage() + " This error is only thrown in development mode.", e);
+    }
+  }
+
+  /***
+   * Getters & Setters
+   ***/
+  public static boolean hasStartedAndRegisteredAsDeveloper() {
+    return hasStartedAndRegisteredAsDeveloper;
+  }
+
+  public static Map<String, List<ActionCallback>> getActionHandlers() {
+    return actionHandlers;
+  }
+
+  public static boolean issuedStart() {
+    return issuedStart;
+  }
+
+  @SuppressWarnings("SameParameterValue")
+  private static void setIssuedStart(boolean issuedStart) {
+    LeanplumInternal.issuedStart = issuedStart;
+  }
+
+  public static boolean hasStarted() {
+    return hasStarted;
+  }
+
+  public static void setHasStarted(boolean hasStarted) {
+    LeanplumInternal.hasStarted = hasStarted;
+  }
+
+  public static boolean isStartSuccessful() {
+    return startSuccessful;
+  }
+
+  public static void setStartSuccessful(boolean startSuccessful) {
+    LeanplumInternal.startSuccessful = startSuccessful;
+  }
+
+  public static boolean hasCalledStart() {
+    return calledStart;
+  }
+
+  public static void setCalledStart(boolean calledStart) {
+    LeanplumInternal.calledStart = calledStart;
+  }
+
+  public static boolean isPaused() {
+    return isPaused;
+  }
+
+  public static void setIsPaused(boolean isPaused) {
+    LeanplumInternal.isPaused = isPaused;
+  }
+
+  public static boolean hasStartedInBackground() {
+    return startedInBackground;
+  }
+
+  public static void setStartedInBackground(boolean startedInBackground) {
+    LeanplumInternal.startedInBackground = startedInBackground;
+  }
+
+  public static Queue<Map<String, ?>> getUserAttributeChanges() {
+    return userAttributeChanges;
+  }
+
+  public static boolean getIsScreenTrackingEnabled() {
+    return isScreenTrackingEnabled;
+  }
+
+  public static void enableAutomaticScreenTracking() {
+    isScreenTrackingEnabled = true;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumManifestHelper.java
@@ -0,0 +1,583 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.text.TextUtils;
+
+import com.leanplum.Leanplum;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+/**
+ * LeanplumManifestHelper class to work with AndroidManifest components.
+ *
+ * @author Anna Orlova
+ */
+public class LeanplumManifestHelper {
+  private static final String MANIFEST = "manifest";
+  private static final String APPLICATION = "application";
+  private static final String SERVICE = "service";
+  private static final String ACTIVITY = "activity";
+  private static final String ACTIVITY_ALIAS = "activity-alias";
+  private static final String RECEIVER = "receiver";
+  private static final String PROVIDER = "provider";
+  private static final String ANDROID_NAME = "android:name";
+  private static final String ANDROID_SCHEME = "android:scheme";
+  private static final String ACTION = "action";
+  private static final String CATEGORY = "category";
+  private static final String DATA = "data";
+  private static final String ANDROID_HOST = "android:host";
+  private static final String ANDROID_PORT = "android:port";
+  private static final String ANDROID_PATH = "android:path";
+  private static final String ANDROID_PATH_PATTERN = "android:pathPattern";
+  private static final String ANDROID_PATH_PREFIX = "android:pathPrefix";
+  private static final String ANDROID_MIME_TYPE = "android:mimeType";
+  private static final String ANDROID_TYPE = "android:type";
+  private static final String INTENT_FILTER = "intent-filter";
+  private static final String ANDROID_PERMISSION = "android:permission";
+  private static final String ANDROID_MANIFEST = "AndroidManifest.xml";
+  private static final String VERSION_NAME = "versionName";
+
+  private static ManifestData manifestData;
+
+  /**
+   * Gets application components from AndroidManifest.xml file.
+   */
+  private static void parseManifestNodeChildren() {
+    manifestData = new ManifestData();
+    byte[] manifestXml = getByteArrayOfManifest();
+    Document manifestDocument = getManifestDocument(manifestXml);
+    parseManifestDocument(manifestDocument);
+  }
+
+  /**
+   * Parse AndroidManifest.xml file to byte array.
+   *
+   * @return byte[] Byte array of AndroidManifest.xml file
+   */
+  private static byte[] getByteArrayOfManifest() {
+    Context context = Leanplum.getContext();
+    if (context == null) {
+      Log.e("Context is null. Cannot parse " + ANDROID_MANIFEST + " file.");
+      return null;
+    }
+    byte[] manifestXml = null;
+    try {
+      JarFile jarFile = new JarFile(context.getPackageResourcePath());
+      ZipEntry entry = jarFile.getEntry(ANDROID_MANIFEST);
+      manifestXml = new byte[(int) entry.getSize()];
+      DataInputStream dataInputStream = new DataInputStream(jarFile.getInputStream(entry));
+      dataInputStream.readFully(manifestXml);
+      dataInputStream.close();
+    } catch (Exception e) {
+      Log.e("Cannot parse " + ANDROID_MANIFEST + " file: " + e.getMessage());
+    }
+    return manifestXml;
+  }
+
+  /**
+   * Gets Document {@link Document} of AndroidManifest.xml file.
+   *
+   * @param manifestXml Byte array of AndroidManifest.xml file data.
+   * @return Document Document with date of AndroidManifest.xml file.
+   */
+  private static Document getManifestDocument(byte[] manifestXml) {
+    Document document = null;
+    try {
+      DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+      DocumentBuilder builder = builderFactory.newDocumentBuilder();
+      document = builder.parse(new ByteArrayInputStream(
+          LeanplumManifestParser.decompressXml(manifestXml).getBytes("UTF-8")));
+    } catch (Exception e) {
+      Log.e("Cannot parse " + ANDROID_MANIFEST + " file: " + e.getMessage());
+    }
+    return document;
+  }
+
+  /**
+   * Parse data from Document {@link Document} with date of AndroidManifest.xml file.
+   *
+   * @param document Document {@link Document} with date of AndroidManifest.xml file.
+   */
+  private static void parseManifestDocument(Document document) {
+    if (document == null) {
+      return;
+    }
+    parseManifestNode(document.getElementsByTagName(MANIFEST).item(0));
+  }
+
+  private static void parseManifestNode(Node manifestNode) {
+    if (manifestNode == null) {
+      return;
+    }
+    manifestData.appVersionName = getAttribute(manifestNode.getAttributes(), VERSION_NAME);
+    NodeList manifestChildren = manifestNode.getChildNodes();
+    if (manifestChildren == null) {
+      return;
+    }
+    for (int i = 0; i < manifestChildren.getLength(); i++) {
+      Node currentNode = manifestChildren.item(i);
+      if (currentNode == null) {
+        continue;
+      }
+      String currentNodeName = currentNode.getNodeName();
+      if (APPLICATION.equals(currentNodeName)) {
+        parseChildNodeList(currentNode.getChildNodes());
+      }
+    }
+  }
+
+  private static void parseChildNodeList(NodeList childrenList) {
+    if (childrenList == null) {
+      return;
+    }
+    for (int j = 0; j < childrenList.getLength(); j++) {
+      parseChildNode(childrenList.item(j));
+    }
+  }
+
+  private static void parseChildNode(Node child) {
+    if (child == null) {
+      return;
+    }
+    String childName = child.getNodeName();
+    if (childName == null) {
+      return;
+    }
+    switch (childName) {
+      case SERVICE:
+        manifestData.services.add(parseManifestComponent(child,
+            ManifestComponent.ApplicationComponent.SERVICE));
+        break;
+      case RECEIVER:
+        manifestData.receivers.add(parseManifestComponent(child,
+            ManifestComponent.ApplicationComponent.RECEIVER));
+        break;
+      case ACTIVITY:
+      case ACTIVITY_ALIAS:
+        manifestData.activities.add(parseManifestComponent(child,
+            ManifestComponent.ApplicationComponent.ACTIVITY));
+        break;
+      case PROVIDER:
+        manifestData.providers.add(parseManifestComponent(child,
+            ManifestComponent.ApplicationComponent.PROVIDER));
+        break;
+      default:
+        break;
+    }
+  }
+
+  /**
+   * Parse AndroidManifest.xml components from XML.
+   *
+   * @param node XML node to parse.
+   * @param type Type of application component {@link ManifestComponent.ApplicationComponent}.
+   * @return Return ManifestComponent {@link ManifestComponent} with information from manifest.
+   */
+  private static ManifestComponent parseManifestComponent(Node node,
+      ManifestComponent.ApplicationComponent type) {
+    ManifestComponent manifestComponent = new ManifestComponent(type);
+    NamedNodeMap attributes = node.getAttributes();
+    manifestComponent.name = getAttribute(attributes, ANDROID_NAME);
+    manifestComponent.permission = getAttribute(attributes, ANDROID_PERMISSION);
+    List<ManifestIntentFilter> intentFilters = new ArrayList<>();
+    NodeList childrenList = node.getChildNodes();
+    for (int i = 0; i < childrenList.getLength(); i++) {
+      Node child = childrenList.item(i);
+      String childName = child.getNodeName();
+      if (INTENT_FILTER.equals(childName)) {
+        ManifestIntentFilter intentFilter = parseManifestIntentFilter(child);
+        if (intentFilter != null) {
+          intentFilters.add(intentFilter);
+        }
+      }
+    }
+    manifestComponent.intentFilters = intentFilters;
+    return manifestComponent;
+  }
+
+  /**
+   * Parse intent filter from XML node.
+   *
+   * @param intentNode XML node to parse.
+   * @return Return ManifestIntentFilter {@link ManifestIntentFilter} with information from
+   * manifest.
+   */
+  private static ManifestIntentFilter parseManifestIntentFilter(Node intentNode) {
+    if (intentNode == null) {
+      return null;
+    }
+
+    NodeList intentChildren = intentNode.getChildNodes();
+    if (intentChildren == null) {
+      return null;
+    }
+
+    ManifestIntentFilter intentFilter = new ManifestIntentFilter();
+    intentFilter.attributes = intentNode.getAttributes();
+    for (int j = 0; j < intentChildren.getLength(); j++) {
+      Node intentChild = intentChildren.item(j);
+      String intentChildName = intentChild.getNodeName();
+      NamedNodeMap intentChildAttributes = intentChild.getAttributes();
+      switch (intentChildName) {
+        case ACTION:
+          intentFilter.actions.add(getAttribute(intentChildAttributes, ANDROID_NAME));
+          break;
+        case CATEGORY:
+          intentFilter.categories.add(getAttribute(intentChildAttributes, ANDROID_NAME));
+          break;
+        case DATA:
+          String scheme = getAttribute(intentChildAttributes, ANDROID_SCHEME);
+          String host = getAttribute(intentChildAttributes, ANDROID_HOST);
+          String port = getAttribute(intentChildAttributes, ANDROID_PORT);
+          String path = getAttribute(intentChildAttributes, ANDROID_PATH);
+          String pathPattern = getAttribute(intentChildAttributes, ANDROID_PATH_PATTERN);
+          String pathPrefix = getAttribute(intentChildAttributes, ANDROID_PATH_PREFIX);
+          String mimeType = getAttribute(intentChildAttributes, ANDROID_MIME_TYPE);
+          String type = getAttribute(intentChildAttributes, ANDROID_TYPE);
+          intentFilter.dataList.add(new ManifestIntentFilter.IntentData(scheme, host, port, path,
+              pathPattern, pathPrefix, mimeType, type));
+          break;
+        default:
+          break;
+      }
+    }
+    return intentFilter;
+  }
+
+  /**
+   * @return Return String with attribute value or null if attribute with this name not found.
+   */
+  private static String getAttribute(NamedNodeMap namedNodeMap, String name) {
+    Node node = namedNodeMap.getNamedItem(name);
+    if (node == null) {
+      if (name.startsWith("android:")) {
+        name = name.substring("android:".length());
+      }
+      node = namedNodeMap.getNamedItem(name);
+      if (node == null) {
+        return null;
+      }
+    }
+    return node.getNodeValue();
+  }
+
+  /**
+   * @return Return List of services from manifest.
+   */
+  public static List<ManifestComponent> getServices() {
+    if (manifestData == null) {
+      parseManifestNodeChildren();
+    }
+    return manifestData.services;
+  }
+
+  /**
+   * @return Return List of activities from manifest.
+   */
+  static List<ManifestComponent> getActivities() {
+    if (manifestData == null) {
+      parseManifestNodeChildren();
+    }
+    return manifestData.activities;
+  }
+
+  /**
+   * @return Return List of providers from manifest.
+   */
+  static List<ManifestComponent> getProviders() {
+    if (manifestData == null) {
+      parseManifestNodeChildren();
+    }
+    return manifestData.providers;
+  }
+
+  /**
+   * @return Return List of receivers from manifest.
+   */
+  public static List<ManifestComponent> getReceivers() {
+    if (manifestData == null) {
+      parseManifestNodeChildren();
+    }
+    return manifestData.receivers;
+  }
+
+  /**
+   * @return String String of application version name.
+   */
+  public static String getAppVersionName() {
+    if (manifestData == null) {
+      parseManifestNodeChildren();
+    }
+    return manifestData.appVersionName;
+  }
+
+  /**
+   * Verifies that a certain component (receiver or service) is implemented in the
+   * AndroidManifest.xml file or the application, in order to make sure that push notifications
+   * work.
+   *
+   * @param componentsList List of application components(services or receivers).
+   * @param name The name of the class.
+   * @param exported What the exported option should be.
+   * @param permission Whether we need any permission.
+   * @param actions What actions we need to check for in the intent-filter.
+   * @param packageName The package name for the category tag, if we require one.
+   * @return true if the respective component is in the manifest file, and false otherwise.
+   */
+  public static boolean checkComponent(List<ManifestComponent> componentsList,
+      String name, boolean exported, String permission, List<String> actions, String packageName) {
+    boolean hasComponent = hasComponent(componentsList, name, permission, actions);
+    if (!hasComponent && !componentsList.isEmpty()) {
+      Log.e(getComponentError(componentsList.get(0).type, name, exported, permission, actions,
+          packageName));
+    }
+    return hasComponent;
+  }
+
+  /**
+   * Check if list of application components contains class instance of class with name className.
+   *
+   * @param componentsList List of application components(services or receivers).
+   * @param className The name of the class.
+   * @param permission Whether we need any permission..
+   * @param actions What actions we need to check for in the intent-filter.
+   * @return boolean True if componentList contains class instance of class with name className.
+   */
+  private static boolean hasComponent(List<ManifestComponent> componentsList, String className,
+      String permission, List<String> actions) {
+    for (ManifestComponent component : componentsList) {
+      if (isInstance(component, className)) {
+        if (hasPermission(component, permission, actions)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Check if component instance of class with name className.
+   *
+   * @param component Application component(service or receiver).
+   * @param className The name of the class.
+   * @return boolean True if component instance of class with name className.
+   */
+  private static boolean isInstance(ManifestComponent component, String className) {
+    try {
+      if (component.name.equals(className)) {
+        return true;
+      } else {
+        Class clazz = null;
+        try {
+          clazz = Class.forName(component.name);
+        } catch (Throwable ignored) {
+        }
+        if (clazz == null) {
+          Log.w("Cannot find class with name: " + component.name);
+          return false;
+        }
+        while (clazz != Object.class) {
+          clazz = clazz.getSuperclass();
+          if (clazz.getName().equals(className)) {
+            return true;
+          }
+        }
+      }
+      return false;
+    } catch (Exception e) {
+      Util.handleException(e);
+      return false;
+    }
+  }
+
+  /**
+   * Check if application component has permission with provided actions.
+   *
+   * @param component application component(service or receiver).
+   * @param permission Whether we need any permission.
+   * @param actions What actions we need to check for in the intent-filter.
+   * @return boolean True if component has permission with actions.
+   */
+  private static boolean hasPermission(ManifestComponent component, String permission,
+      List<String> actions) {
+    Boolean hasPermissions = TextUtils.equals(component.permission, permission);
+    if (hasPermissions && actions != null) {
+      HashSet<String> actionsToCheck = new HashSet<>(actions);
+      for (ManifestIntentFilter intentFilter : component.intentFilters) {
+        actionsToCheck.removeAll(intentFilter.actions);
+      }
+      if (actionsToCheck.isEmpty()) {
+        return true;
+      }
+    } else if (hasPermissions) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Gets string of error message with instruction how to set up AndroidManifest.xml for push
+   * notifications.
+   *
+   * @return String String of error message with instruction how to set up AndroidManifest.xml for
+   * push notifications.
+   */
+  private static String getComponentError(ManifestComponent.ApplicationComponent componentType,
+      String name, boolean exported, String permission, List<String> actions, String packageName) {
+    StringBuilder errorMessage = new StringBuilder("Push notifications requires you to add the " +
+        componentType.name().toLowerCase() + " " + name + " to your AndroidManifest.xml file." +
+        "Add this code within the <application> section:\n");
+    errorMessage.append("<").append(componentType.name().toLowerCase()).append("\n");
+    errorMessage.append("    android:name=\"").append(name).append("\"\n");
+    errorMessage.append("    android:exported=\"").append(Boolean.toString(exported)).append("\"");
+    if (permission != null) {
+      errorMessage.append("\n    android:permission=\"").append(permission).append("\"");
+    }
+    errorMessage.append(">\n");
+    if (actions != null) {
+      errorMessage.append("    <intent-filter>\n");
+      for (String action : actions) {
+        errorMessage.append("        <action android:name=\"").append(action).append("\" />\n");
+      }
+      if (packageName != null) {
+        errorMessage.append("        <category android:name=\"").append(packageName)
+            .append("\" />\n");
+      }
+      errorMessage.append("    </intent-filter>\n");
+    }
+    errorMessage.append("</").append(componentType.name().toLowerCase()).append(">");
+    return errorMessage.toString();
+  }
+
+  /**
+   * Check if the application has registered for a certain permission.
+   *
+   * @param permission Requested permission.
+   * @param definesPermission Permission need definition or not.
+   * @param logError Need print log or not.
+   * @return boolean True if application has permission.
+   */
+  public static boolean checkPermission(String permission, boolean definesPermission,
+      boolean logError) {
+    Context context = Leanplum.getContext();
+    if (context == null) {
+      return false;
+    }
+    if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+      String definition;
+      if (definesPermission) {
+        definition = "<permission android:name=\"" + permission +
+            "\" android:protectionLevel=\"signature\" />\n";
+      } else {
+        definition = "";
+      }
+      if (logError) {
+        Log.e("In order to use push notifications, you need to enable " +
+            "the " + permission + " permission in your AndroidManifest.xml file. " +
+            "Add this within the <manifest> section:\n" +
+            definition + "<uses-permission android:name=\"" + permission + "\" />");
+      }
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Class with Android manifest data.
+   */
+  private static class ManifestData {
+    private List<ManifestComponent> services = new ArrayList<>();
+    private List<ManifestComponent> activities = new ArrayList<>();
+    private List<ManifestComponent> receivers = new ArrayList<>();
+    private List<ManifestComponent> providers = new ArrayList<>();
+    private String appVersionName;
+  }
+
+  /**
+   * Class with application component from AndroidManifest.xml.
+   */
+  private static class ManifestComponent {
+    enum ApplicationComponent {SERVICE, RECEIVER, ACTIVITY, PROVIDER}
+
+    ApplicationComponent type;
+    String name;
+    String permission;
+    List<ManifestIntentFilter> intentFilters = new ArrayList<>();
+
+    ManifestComponent(ApplicationComponent type) {
+      this.type = type;
+    }
+  }
+
+  /**
+   * Class for declaration of intent filter from AndroidManifest.
+   */
+  private static class ManifestIntentFilter {
+    final List<String> actions = new ArrayList<>();
+    final List<String> categories = new ArrayList<>();
+    final List<IntentData> dataList = new ArrayList<>();
+    public NamedNodeMap attributes;
+
+    /**
+     * Class for data of intent filter from AndroidManifest.
+     */
+    static class IntentData {
+      final String scheme;
+      final String host;
+      final String port;
+      final String path;
+      final String pathPattern;
+      final String pathPrefix;
+      final String mimeType;
+      final String type;
+
+      IntentData(String scheme, String host, String port, String path, String pathPattern,
+          String pathPrefix, String mimeType, String type) {
+        this.scheme = scheme;
+        this.host = host;
+        this.port = port;
+        this.path = path;
+        this.pathPattern = pathPattern;
+        this.pathPrefix = pathPrefix;
+        this.mimeType = mimeType;
+        this.type = type;
+      }
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumManifestParser.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+/**
+ * LeanplumManifestParser class for get AndroidManifest.xml. http://stackoverflow.com/questions/2097813/how-to-parse-the-androidmanifest-xml-file-inside-an-apk-package
+ *
+ * @author Anna Orlova
+ */
+class LeanplumManifestParser {
+  // XML tags and attributes:
+  // Every XML start and end tag consists of 6 32 bit words:
+  //   0th word: 02011000 for START_TAG and 03011000 for END_TAG
+  //   1st word: a flag?, like 38000000
+  //   2nd word: Line of where this tag appeared in the original source file
+  //   3rd word: FFFFFFFF ??
+  //   4th word: StringIndex of NameSpace name, or FFFFFFFF for default NS
+  //   5th word: StringIndex of Element Name
+  //   (Note: 01011000 in 0th word means end of XML document, END_DOC_TAG).
+
+  // Start tags (not end tags) contain 3 more words:
+  //   6th word: 14001400 meaning??
+  //   7th word: Number of Attributes that follow this tag(follow word 8th)
+  //   8th word: 00000000 meaning??
+
+  // Attributes consist of 5 words:
+  //   0th word: StringIndex of Attribute Name's Namespace, or FFFFFFFF
+  //   1st word: StringIndex of Attribute Name
+  //   2nd word: StringIndex of Attribute Value, or FFFFFFF if ResourceId used
+  //   3rd word: Flags?
+  //   4th word: str ind of attr value again, or ResourceId of value.
+  // END_DOC_TAG = 0x00100101;
+  private static final int START_TAG = 0x00100102;
+  private static final int END_TAG = 0x00100103;
+  private static final String SPACES = "                                             ";
+
+  /**
+   * Parse the 'compressed' binary form of Android XML docs such as for AndroidManifest.xml in .apk
+   * files.
+   *
+   * @param xml byte array of AndroidManifest.xml.
+   * @return String with data of AndroidManifest.xml.
+   */
+  static String decompressXml(byte[] xml) {
+    String out = "";
+    // Compressed XML file/bytes starts with 24x bytes of data,
+    // 9 32 bit words in little endian order (LSB first):
+    //   0th word is 03 00 08 00
+    //   3rd word SEEMS TO BE:  Offset at then of StringTable
+    //   4th word is: Number of strings in string table
+    // WARNING: Sometime I indiscriminately display or refer to word in
+    //   little endian storage format, or in integer format (ie MSB first).
+    int numbStrings = littleEndianValue(xml, 4 * 4);
+    // StringIndexTable starts at offset 24x, an array of 32 bit LE offsets
+    // of the length/string data in the StringTable.
+    int sitOff = 0x24;  // Offset of start of StringIndexTable.
+    // StringTable, each string is represented with a 16 bit little endian
+    // character count, followed by that number of 16 bit (LE) (Unicode) chars.
+    int stOff = sitOff + numbStrings * 4;  // StringTable follows StrIndexTable.
+    // Step through the XML tree element tags and attributes.
+    int off = scanForFirstStartTag(xml);
+    int indent = 0;
+
+    while (off < xml.length) {
+      int tag0 = littleEndianValue(xml, off);
+      int nameSi = littleEndianValue(xml, off + 5 * 4);
+      if (tag0 == START_TAG) {
+        int numbAttrs = littleEndianValue(xml, off + 7 * 4);  // Number of Attributes to follow.
+        off += 9 * 4;  // Skip over 6+3 words of START_TAG data
+        String name = compXmlString(xml, sitOff, stOff, nameSi);
+        // Look for the Attributes
+        StringBuilder sb = new StringBuilder();
+        for (int ii = 0; ii < numbAttrs; ii++) {
+          int attrNameSi = littleEndianValue(xml, off + 4);  // AttrName String Index.
+          int attrValueSi = littleEndianValue(xml, off + 2 * 4); // AttrValue Str Ind, or FFFFFFFF.
+          int attrResId = littleEndianValue(xml, off + 4 * 4);  // AttrValue ResourceId or dup.
+          // AttrValue StrInd.
+          off += 5 * 4;  // Skip over the 5 words of an attribute.
+          String attrName = compXmlString(xml, sitOff, stOff, attrNameSi);
+          String attrValue = attrValueSi != -1
+              ? compXmlString(xml, sitOff, stOff, attrValueSi)
+              : "resourceID 0x" + Integer.toHexString(attrResId);
+          sb.append(" ").append(attrName).append("=\"").append(attrValue).append("\"");
+        }
+        out += SPACES.substring(0, Math.min(indent * 2, SPACES.length())) + "<" + name + sb + ">";
+        indent++;
+      } else if (tag0 == END_TAG) {
+        indent--;
+        off += 6 * 4;  // Skip over 6 words of END_TAG data
+        String name = compXmlString(xml, sitOff, stOff, nameSi);
+        out += SPACES.substring(0, Math.min(indent * 2, SPACES.length())) + "</" + name + ">";
+
+      } else {
+        break;
+      }
+    }
+    return out;
+  }
+
+  private static String compXmlString(byte[] xml, int sitOff, int stOff, int strInd) {
+    if (strInd < 0) return null;
+    int strOff = stOff + littleEndianValue(xml, sitOff + strInd * 4);
+    return compXmlStringAt(xml, strOff);
+  }
+
+  /**
+   * @return Return the string stored in StringTable format at offset strOff.  This offset points to
+   * the 16 bit string length, which is followed by that number of 16 bit (Unicode) chars.
+   */
+  private static String compXmlStringAt(byte[] arr, int strOff) {
+    int strLen = arr[strOff + 1] << 8 & 0xff00 | arr[strOff] & 0xff;
+    byte[] chars = new byte[strLen];
+    for (int ii = 0; ii < strLen; ii++) {
+      chars[ii] = arr[strOff + 2 + ii * 2];
+    }
+    return new String(chars);  // Hack, just use 8 byte chars.
+  }
+
+  /**
+   * @return Return value of a Little Endian 32 bit word from the byte array at offset off.
+   */
+  private static int littleEndianValue(byte[] arr, int off) {
+    return arr[off + 3] << 24 & 0xff000000 | arr[off + 2] << 16 & 0xff0000
+        | arr[off + 1] << 8 & 0xff00 | arr[off] & 0xFF;
+  }
+
+  private static int scanForFirstStartTag(byte[] xml) {
+    // XMLTags, The XML tag tree starts after some unknown content after the
+    // StringTable.  There is some unknown data after the StringTable, scan forward
+    // from this point to the flag for the start of an XML start tag.
+    int xmlTagOff = littleEndianValue(xml, 3 * 4);  // Start from the offset in the 3rd word.
+    // Scan forward until we find the bytes: 0x02011000(x00100102 in normal int).
+    for (int ii = xmlTagOff; ii < xml.length - 4; ii += 4) {
+      if (littleEndianValue(xml, ii) == START_TAG) {
+        xmlTagOff = ii;
+        break;
+      }
+    }
+    return xmlTagOff;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumMessageMatchFilter.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+/**
+ * Messaging filter.
+ *
+ * @author Atanas Dobrev
+ */
+public class LeanplumMessageMatchFilter {
+  public static final int LEANPLUM_ACTION_FILTER_FOREGROUND = 1;
+  public static final int LEANPLUM_ACTION_FILTER_BACKGROUND = 2;
+  public static final int LEANPLUM_ACTION_FILTER_ALL = 3;
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/LeanplumUIEditorWrapper.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.app.Activity;
+
+import com.leanplum.LeanplumEditorMode;
+import com.leanplum.LeanplumUIEditor;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import static com.leanplum.internal.Constants.ClassUtil.UI_INTERFACE_EDITOR;
+
+/**
+ * Wrapper class for the UI Editor. Method calls will be forwarded to UI Editor package if its
+ * available.
+ */
+public class LeanplumUIEditorWrapper implements LeanplumUIEditor {
+  private static LeanplumUIEditor interfaceEditorSingleton;
+  private static LeanplumUIEditorWrapper instance = null;
+
+  protected LeanplumUIEditorWrapper() {
+    // Exists only to defeat instantiation.
+  }
+
+  static {
+    Class clazz = null;
+    try {
+      clazz = Class.forName(UI_INTERFACE_EDITOR);
+    } catch (ClassNotFoundException ignored) {
+    }
+    if (clazz != null) {
+      Method method = null;
+      try {
+        method = clazz.getMethod("getInstance", null);
+      } catch (NoSuchMethodException e) {
+        Util.handleException(e);
+      }
+      if (method != null) {
+        try {
+          interfaceEditorSingleton = (LeanplumUIEditor) method.invoke(null);
+          if (interfaceEditorSingleton != null) {
+            interfaceEditorSingleton.allowInterfaceEditing(Constants.isDevelopmentModeEnabled);
+          }
+        } catch (IllegalAccessException e) {
+          Util.handleException(e);
+        } catch (InvocationTargetException e) {
+          Util.handleException(e);
+        }
+      }
+    }
+  }
+
+  public static LeanplumUIEditorWrapper getInstance() {
+    if (instance == null) {
+      instance = new LeanplumUIEditorWrapper();
+    }
+    return instance;
+  }
+
+  public static boolean isUIEditorAvailable() {
+    return interfaceEditorSingleton != null;
+  }
+
+  @Override
+  public void allowInterfaceEditing(Boolean isDevelopmentModeEnabled) {
+    if (interfaceEditorSingleton != null) {
+      interfaceEditorSingleton.allowInterfaceEditing(isDevelopmentModeEnabled);
+    }
+  }
+
+  @Override
+  public void applyInterfaceEdits(Activity activity) {
+    if (interfaceEditorSingleton != null && activity != null) {
+      interfaceEditorSingleton.applyInterfaceEdits(activity);
+    }
+  }
+
+  /**
+   * Sets the update flag to true.
+   */
+  @Override
+  public void startUpdating() {
+    if (interfaceEditorSingleton != null) {
+      interfaceEditorSingleton.startUpdating();
+    }
+  }
+
+  /**
+   * Sets the update flag to false.
+   */
+  @Override
+  public void stopUpdating() {
+    if (interfaceEditorSingleton != null) {
+      interfaceEditorSingleton.stopUpdating();
+    }
+  }
+
+  @Override
+  public void sendUpdate() {
+    if (interfaceEditorSingleton != null) {
+      interfaceEditorSingleton.sendUpdate();
+    }
+  }
+
+  @Override
+  public void sendUpdateDelayed(int delay) {
+    if (interfaceEditorSingleton != null) {
+      interfaceEditorSingleton.sendUpdateDelayed(delay);
+    }
+  }
+
+  @Override
+  public void sendUpdateDelayedDefault() {
+    if (interfaceEditorSingleton != null) {
+      interfaceEditorSingleton.sendUpdateDelayedDefault();
+    }
+  }
+
+  @Override
+  public LeanplumEditorMode getMode() {
+    if (interfaceEditorSingleton != null) {
+      return interfaceEditorSingleton.getMode();
+    }
+    return null;
+  }
+
+  @Override
+  public void setMode(LeanplumEditorMode mode) {
+    if (interfaceEditorSingleton != null) {
+      interfaceEditorSingleton.setMode(mode);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Log.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import com.leanplum.BuildConfig;
+
+import java.util.HashMap;
+
+/**
+ * Handles logging within the Leanplum SDK.
+ *
+ * @author Ben Marten
+ */
+public class Log {
+  public enum LeanplumLogType {
+    /**
+     * Always visible to customers. Sent to us when remote logging is enabled.
+     */
+    ERROR,
+
+    /**
+     * Always visible to customers. Sent to us when remote logging is enabled.
+     */
+    WARNING,
+
+    /**
+     * Always visible to customers. Sent to us when remote logging is enabled.
+     */
+    INFO,
+
+    /**
+     * Visible to customers only when verbose logging is enabled. Sent to us when remote logging is
+     * enabled.
+     */
+    VERBOSE,
+
+    /**
+     * Not visible to customers. Sent to us when remote logging is enabled.
+     */
+    PRIVATE,
+
+    /**
+     * Used only for Leanplum SDK debugging. Not visible to customers. Not sent to us when remote
+     * logging is enabled.
+     */
+    DEBUG
+  }
+
+  private static final ThreadLocal<Boolean> isLogging = new ThreadLocal<Boolean>() {
+    @Override
+    protected Boolean initialValue() {
+      return false;
+    }
+  };
+
+  public static void e(Object... objects) {
+    log(LeanplumLogType.ERROR, CollectionUtil.concatenateArray(objects, ", "));
+  }
+
+  public static void w(Object... objects) {
+    log(LeanplumLogType.WARNING, CollectionUtil.concatenateArray(objects, ", "));
+  }
+
+  public static void i(Object... objects) {
+    log(LeanplumLogType.INFO, CollectionUtil.concatenateArray(objects, ", "));
+  }
+
+  public static void v(Object... objects) {
+    log(LeanplumLogType.VERBOSE, CollectionUtil.concatenateArray(objects, ", "));
+  }
+
+  public static void p(Object... objects) {
+    log(LeanplumLogType.PRIVATE, CollectionUtil.concatenateArray(objects, ", "));
+  }
+
+  public static void d(Object... objects) {
+    log(LeanplumLogType.DEBUG, CollectionUtil.concatenateArray(objects, ", "));
+  }
+
+  /**
+   * Handle Leanplum log messages, which may be sent to the server for remote logging if
+   * Constants.loggingEnabled is set.
+   * <p/>
+   * This will format the string in all cases, and is therefore less efficient than checking the
+   * conditionals inline. Avoid this in performance-critical code.
+   *
+   * @param type The log type level of the message.
+   * @param message The message to be logged.
+   */
+  public static void log(LeanplumLogType type, String message) {
+    String tag = generateTag(type);
+    String prefix = generateMessagePrefix();
+
+    switch (type) {
+      case ERROR:
+        android.util.Log.e(tag, prefix + message);
+        maybeSendLog(tag + prefix + message);
+        return;
+      case WARNING:
+        android.util.Log.w(tag, prefix + message);
+        maybeSendLog(tag + prefix + message);
+        return;
+      case INFO:
+        android.util.Log.i(tag, prefix + message);
+        maybeSendLog(tag + prefix + message);
+        return;
+      case VERBOSE:
+        if (Constants.isDevelopmentModeEnabled
+            && Constants.enableVerboseLoggingInDevelopmentMode) {
+          android.util.Log.v(tag, prefix + message);
+          maybeSendLog(tag + prefix + message);
+        }
+        return;
+      case PRIVATE:
+        maybeSendLog(tag + prefix + message);
+        return;
+      default: // DEBUG
+        if (BuildConfig.DEBUG) {
+          android.util.Log.d(tag, prefix + message);
+        }
+    }
+  }
+
+  /**
+   * Generates tag for logging purpose in format [LogType][Leanplum]
+   *
+   * @param type log type
+   * @return generated tag
+   */
+  private static String generateTag(LeanplumLogType type) {
+    return "[" + type.name() + "][Leanplum]";
+  }
+
+  /**
+   * Generates a log message prefix based on current class and method name in format
+   * [ClassName::MethodName::LineNumber].
+   * This shouldn't be called directly, since getting className and methodName is hardcoded and
+   * extracted based on StackTrace.
+   *
+   * @return a message prefix for logging purpose
+   */
+  private static String generateMessagePrefix() {
+    // Since this is called from log method, caller method should be on index 5.
+    int callerIndex = 5;
+    int minimumStackTraceIndex = 5;
+
+    StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
+    if (stackTraceElements.length >= minimumStackTraceIndex) {
+      String tag = "[";
+      tag += stackTraceElements[callerIndex].getClassName();
+      tag += "::";
+      tag += stackTraceElements[callerIndex].getMethodName();
+      tag += "::";
+      tag += stackTraceElements[callerIndex].getLineNumber();
+      tag += "]: ";
+      return tag;
+    }
+    return "";
+  }
+
+  private static void maybeSendLog(String message) {
+    if (!Constants.loggingEnabled || isLogging.get()) {
+      return;
+    }
+
+    isLogging.set(true);
+    try {
+      HashMap<String, Object> params = new HashMap<>();
+      params.put(Constants.Params.TYPE, Constants.Values.SDK_LOG);
+      params.put(Constants.Params.MESSAGE, message);
+      Request.post(Constants.Methods.LOG, params).sendEventually();
+    } catch (Throwable t) {
+      android.util.Log.e("Leanplum", "Unable to send log.", t);
+    } finally {
+      isLogging.remove();
+    }
+  }
+
+  /**
+   * Handy function to get a loggable stack trace from a Throwable.
+   *
+   * @param throwable An exception to log.
+   */
+  public static String getStackTraceString(Throwable throwable) {
+    return android.util.Log.getStackTraceString(throwable);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/OsHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.os.Handler;
+import android.os.Looper;
+
+/**
+ * Wraps Handler while allowing overriding of methods that are needed for unit testing
+ *
+ * @author kkafadarov
+ */
+public class OsHandler {
+  // Posts to UI thread. Visible for testing.
+  public static OsHandler instance;
+
+  final Handler handler = new Handler(Looper.getMainLooper());
+
+  public Boolean post(Runnable runnable) {
+    return handler.post(runnable);
+  }
+
+  public Boolean postDelayed(Runnable runnable, long lng) {
+    return handler.postDelayed(runnable, lng);
+  }
+
+  public static OsHandler getInstance() {
+    if (instance == null) {
+      instance = new OsHandler();
+    }
+    return instance;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Registration.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import com.leanplum.callbacks.StartCallback;
+
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Registration {
+  public static void registerDevice(String email, final StartCallback callback) {
+    Map<String, Object> params = new HashMap<>();
+    params.put(Constants.Params.EMAIL, email);
+    Request request = Request.post(Constants.Methods.REGISTER_FOR_DEVELOPMENT, params);
+    request.onResponse(new Request.ResponseCallback() {
+      @Override
+      public void response(final JSONObject response) {
+        OsHandler.getInstance().post(new Runnable() {
+          @Override
+          public void run() {
+            try {
+              JSONObject registerResponse = Request.getLastResponse(response);
+              boolean isSuccess = Request.isResponseSuccess(registerResponse);
+              if (isSuccess) {
+                if (callback != null) {
+                  callback.onResponse(true);
+                }
+              } else {
+                Log.e(Request.getResponseError(registerResponse));
+                if (callback != null) {
+                  callback.onResponse(false);
+                }
+              }
+            } catch (Throwable t) {
+              Util.handleException(t);
+            }
+          }
+        });
+      }
+    });
+    request.onError(new Request.ErrorCallback() {
+      @Override
+      public void error(final Exception e) {
+        OsHandler.getInstance().post(new Runnable() {
+          @Override
+          public void run() {
+            if (callback != null) {
+              callback.onResponse(false);
+            }
+          }
+        });
+      }
+    });
+    request.sendIfConnected();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Request.java
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+
+import com.leanplum.Leanplum;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Leanplum request class.
+ *
+ * @author Andrew First
+ */
+public class Request {
+  private static final long DEVELOPMENT_MIN_DELAY_MS = 100;
+  private static final long DEVELOPMENT_MAX_DELAY_MS = 5000;
+  private static final long PRODUCTION_DELAY = 60000;
+  private static final String LEANPLUM = "__leanplum__";
+
+  private static String appId;
+  private static String accessKey;
+  private static String deviceId;
+  private static String userId;
+  private static final Map<String, Boolean> fileTransferStatus = new HashMap<>();
+  private static int pendingDownloads;
+  private static NoPendingDownloadsCallback noPendingDownloadsBlock;
+
+  // The token is saved primarily for legacy SharedPreferences decryption. This could
+  // likely be removed in the future.
+  private static String token = null;
+  private static final Object lock = Request.class;
+  private static final Map<File, Long> fileUploadSize = new HashMap<>();
+  private static final Map<File, Double> fileUploadProgress = new HashMap<>();
+  private static String fileUploadProgressString = "";
+  private static long lastSendTimeMs;
+  private static final Object uploadFileLock = new Object();
+
+  private final String httpMethod;
+  private final String apiMethod;
+  private final Map<String, Object> params;
+  private ResponseCallback response;
+  private ErrorCallback error;
+  private boolean sent;
+
+  private static ApiResponseCallback apiResponse;
+
+  public static void setAppId(String appId, String accessKey) {
+    Request.appId = appId;
+    Request.accessKey = accessKey;
+  }
+
+  public static void setDeviceId(String deviceId) {
+    Request.deviceId = deviceId;
+  }
+
+  public static void setUserId(String userId) {
+    Request.userId = userId;
+  }
+
+  public static void setToken(String token) {
+    Request.token = token;
+  }
+
+  public static String token() {
+    return token;
+  }
+
+  public static void loadToken() {
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(
+        LEANPLUM, Context.MODE_PRIVATE);
+    String token = defaults.getString(Constants.Defaults.TOKEN_KEY, null);
+    if (token == null) {
+      return;
+    }
+    setToken(token);
+  }
+
+  public static void saveToken() {
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(
+        LEANPLUM, Context.MODE_PRIVATE);
+    SharedPreferences.Editor editor = defaults.edit();
+    editor.putString(Constants.Defaults.TOKEN_KEY, Request.token());
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  public static String appId() {
+    return appId;
+  }
+
+  public static String deviceId() {
+    return deviceId;
+  }
+
+  public static String userId() {
+    return Request.userId;
+  }
+
+  public Request(String httpMethod, String apiMethod, Map<String, Object> params) {
+    this.httpMethod = httpMethod;
+    this.apiMethod = apiMethod;
+    this.params = params != null ? params : new HashMap<String, Object>();
+
+    // Make sure the Handler is initialized on the main thread.
+    OsHandler.getInstance();
+  }
+
+  public static Request get(String apiMethod, Map<String, Object> params) {
+    Log.LeanplumLogType level = Constants.Methods.LOG.equals(apiMethod) ?
+        Log.LeanplumLogType.DEBUG : Log.LeanplumLogType.VERBOSE;
+    Log.log(level, "Will call API method " + apiMethod + " with arguments " + params);
+    return RequestFactory.getInstance().createRequest("GET", apiMethod, params);
+  }
+
+  public static Request post(String apiMethod, Map<String, Object> params) {
+    Log.LeanplumLogType level = Constants.Methods.LOG.equals(apiMethod) ?
+        Log.LeanplumLogType.DEBUG : Log.LeanplumLogType.VERBOSE;
+    Log.log(level, "Will call API method " + apiMethod + " with arguments " + params);
+    return RequestFactory.getInstance().createRequest("POST", apiMethod, params);
+  }
+
+  public void onResponse(ResponseCallback response) {
+    this.response = response;
+  }
+
+  public void onError(ErrorCallback error) {
+    this.error = error;
+  }
+
+  public void onApiResponse(ApiResponseCallback apiResponse) {
+    Request.apiResponse = apiResponse;
+  }
+
+  private Map<String, Object> createArgsDictionary() {
+    Map<String, Object> args = new HashMap<>();
+    args.put(Constants.Params.DEVICE_ID, deviceId);
+    args.put(Constants.Params.USER_ID, userId);
+    args.put(Constants.Params.ACTION, apiMethod);
+    args.put(Constants.Params.SDK_VERSION, Constants.LEANPLUM_VERSION);
+    args.put(Constants.Params.DEV_MODE, Boolean.toString(Constants.isDevelopmentModeEnabled));
+    args.put(Constants.Params.TIME, Double.toString(new Date().getTime() / 1000.0));
+    if (token != null) {
+      args.put(Constants.Params.TOKEN, token);
+    }
+    args.putAll(params);
+    return args;
+  }
+
+  private static void saveRequestForLater(Map<String, Object> args) {
+    synchronized (lock) {
+      Context context = Leanplum.getContext();
+      SharedPreferences preferences = context.getSharedPreferences(
+          LEANPLUM, Context.MODE_PRIVATE);
+      SharedPreferences.Editor editor = preferences.edit();
+      int count = preferences.getInt(Constants.Defaults.COUNT_KEY, 0);
+      String itemKey = String.format(Locale.US, Constants.Defaults.ITEM_KEY, count);
+      editor.putString(itemKey, JsonConverter.toJson(args));
+      count++;
+      editor.putInt(Constants.Defaults.COUNT_KEY, count);
+      try {
+        editor.apply();
+      } catch (NoSuchMethodError e) {
+        editor.commit();
+      }
+    }
+  }
+
+  public void send() {
+    this.sendEventually();
+    if (Constants.isDevelopmentModeEnabled) {
+      long currentTimeMs = System.currentTimeMillis();
+      long delayMs;
+      if (lastSendTimeMs == 0 || currentTimeMs - lastSendTimeMs > DEVELOPMENT_MAX_DELAY_MS) {
+        delayMs = DEVELOPMENT_MIN_DELAY_MS;
+      } else {
+        delayMs = (lastSendTimeMs + DEVELOPMENT_MAX_DELAY_MS) - currentTimeMs;
+      }
+      OsHandler.getInstance().postDelayed(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            sendIfConnected();
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+        }
+      }, delayMs);
+    }
+  }
+
+  /**
+   * Wait 1 second for potential other API calls, and then sends the call synchronously if no other
+   * call has been sent within 1 minute.
+   */
+  public void sendIfDelayed() {
+    sendEventually();
+    OsHandler.getInstance().postDelayed(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          sendIfDelayedHelper();
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+    }, 1000);
+  }
+
+  /**
+   * Sends the call synchronously if no other call has been sent within 1 minute.
+   */
+  private void sendIfDelayedHelper() {
+    if (Constants.isDevelopmentModeEnabled) {
+      send();
+    } else {
+      long currentTimeMs = System.currentTimeMillis();
+      if (lastSendTimeMs == 0 || currentTimeMs - lastSendTimeMs > PRODUCTION_DELAY) {
+        sendIfConnected();
+      }
+    }
+  }
+
+  public void sendIfConnected() {
+    if (Util.isConnected()) {
+      this.sendNow();
+    } else {
+      this.sendEventually();
+      Log.i("Device is offline, will send later");
+      triggerErrorCallback(new Exception("Not connected to the Internet"));
+    }
+  }
+
+  private void triggerErrorCallback(Exception e) {
+    if (error != null) {
+      error.error(e);
+    }
+    if (apiResponse != null) {
+      List<Map<String, Object>> requests = getUnsentRequests();
+      apiResponse.response(requests, null);
+    }
+  }
+
+  @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+  private boolean attachApiKeys(Map<String, Object> dict) {
+    if (appId == null || accessKey == null) {
+      Log.e("API keys are not set. Please use Leanplum.setAppIdForDevelopmentMode or "
+          + "Leanplum.setAppIdForProductionMode.");
+      return false;
+    }
+    dict.put(Constants.Params.APP_ID, appId);
+    dict.put(Constants.Params.CLIENT_KEY, accessKey);
+    dict.put(Constants.Params.CLIENT, Constants.CLIENT);
+    return true;
+  }
+
+  public interface ResponseCallback {
+    void response(JSONObject response);
+  }
+
+  public interface ApiResponseCallback {
+    void response(List<Map<String, Object>> requests, JSONObject response);
+  }
+
+  public interface ErrorCallback {
+    void error(Exception e);
+  }
+
+  public interface NoPendingDownloadsCallback {
+    void noPendingDownloads();
+  }
+
+  private void parseResponseJson(JSONObject responseJson, List<Map<String, Object>> requestsToSend,
+      Exception error) {
+    if (apiResponse != null) {
+      apiResponse.response(requestsToSend, responseJson);
+    }
+
+    if (responseJson != null) {
+      Exception lastResponseError = null;
+      int numResponses = Request.numResponses(responseJson);
+      for (int i = 0; i < numResponses; i++) {
+        JSONObject response = Request.getResponseAt(responseJson, i);
+        if (!Request.isResponseSuccess(response)) {
+          String errorMessage = Request.getResponseError(response);
+          if (errorMessage == null || errorMessage.length() == 0) {
+            errorMessage = "API error";
+          } else if (errorMessage.startsWith("App not found")) {
+            errorMessage = "No app matching the provided app ID was found.";
+            Constants.isInPermanentFailureState = true;
+          } else if (errorMessage.startsWith("Invalid access key")) {
+            errorMessage = "The access key you provided is not valid for this app.";
+            Constants.isInPermanentFailureState = true;
+          } else if (errorMessage.startsWith("Development mode requested but not permitted")) {
+            errorMessage = "A call to Leanplum.setAppIdForDevelopmentMode "
+                + "with your production key was made, which is not permitted.";
+            Constants.isInPermanentFailureState = true;
+          } else {
+            errorMessage = "API error: " + errorMessage;
+          }
+          Log.e(errorMessage);
+          if (i == numResponses - 1) {
+            lastResponseError = new Exception(errorMessage);
+          }
+        }
+      }
+
+      if (lastResponseError == null) {
+        lastResponseError = error;
+      }
+
+      if (lastResponseError != null && this.error != null) {
+        this.error.error(lastResponseError);
+      } else if (this.response != null) {
+        this.response.response(responseJson);
+      }
+    } else if (error != null && this.error != null) {
+      this.error.error(error);
+    }
+  }
+
+  private void sendNow() {
+    if (Constants.isTestMode) {
+      return;
+    }
+    if (appId == null) {
+      Log.e("Cannot send request. appId is not set.");
+      return;
+    }
+    if (accessKey == null) {
+      Log.e("Cannot send request. accessKey is not set.");
+      return;
+    }
+
+    this.sendEventually();
+
+    final List<Map<String, Object>> requestsToSend = popUnsentRequests();
+    if (requestsToSend.isEmpty()) {
+      return;
+    }
+
+    final Map<String, Object> multiRequestArgs = new HashMap<>();
+    multiRequestArgs.put(Constants.Params.DATA, jsonEncodeUnsentRequests(requestsToSend));
+    multiRequestArgs.put(Constants.Params.SDK_VERSION, Constants.LEANPLUM_VERSION);
+    multiRequestArgs.put(Constants.Params.ACTION, Constants.Methods.MULTI);
+    multiRequestArgs.put(Constants.Params.TIME, Double.toString(new Date().getTime() / 1000.0));
+    if (!this.attachApiKeys(multiRequestArgs)) {
+      return;
+    }
+
+    Util.executeAsyncTask(new AsyncTask<Void, Void, Void>() {
+      @Override
+      protected Void doInBackground(Void... params) {
+        JSONObject result = null;
+        HttpURLConnection op = null;
+        try {
+          try {
+            op = Util.operation(
+                Constants.API_HOST_NAME,
+                Constants.API_SERVLET,
+                multiRequestArgs,
+                httpMethod,
+                Constants.API_SSL,
+                Constants.NETWORK_TIMEOUT_SECONDS);
+
+            result = Util.getJsonResponse(op);
+            int statusCode = op.getResponseCode();
+
+            Exception errorException = null;
+            if (statusCode >= 400) {
+              errorException = new Exception("HTTP error " + statusCode);
+              if (statusCode == 408 || (statusCode >= 500 && statusCode <= 599)) {
+                pushUnsentRequests(requestsToSend);
+              }
+            } else {
+              if (result != null) {
+                int numResponses = Request.numResponses(result);
+                if (numResponses != requestsToSend.size()) {
+                  Log.w("Sent " + requestsToSend.size() +
+                      " requests but only" + " received " + numResponses);
+                }
+              } else {
+                errorException = new Exception("Response JSON is null.");
+              }
+            }
+            parseResponseJson(result, requestsToSend, errorException);
+          } catch (JSONException e) {
+            Log.e("Error parsing JSON response: " + e.toString() + "\n" +
+                Log.getStackTraceString(e));
+            parseResponseJson(null, requestsToSend, e);
+          } catch (Exception e) {
+            pushUnsentRequests(requestsToSend);
+            Log.e("Unable to send request: " + e.toString() + "\n" +
+                Log.getStackTraceString(e));
+            parseResponseJson(result, requestsToSend, e);
+          } finally {
+            if (op != null) {
+              op.disconnect();
+            }
+          }
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+        return null;
+      }
+    });
+  }
+
+  public void sendEventually() {
+    if (Constants.isTestMode) {
+      return;
+    }
+    if (!sent) {
+      sent = true;
+      Map<String, Object> args = createArgsDictionary();
+      saveRequestForLater(args);
+    }
+  }
+
+  static List<Map<String, Object>> popUnsentRequests() {
+    return getUnsentRequests(true);
+  }
+
+  static List<Map<String, Object>> getUnsentRequests() {
+    return getUnsentRequests(false);
+  }
+
+  private static List<Map<String, Object>> getUnsentRequests(boolean remove) {
+    List<Map<String, Object>> requestData = new ArrayList<>();
+
+    synchronized (lock) {
+      lastSendTimeMs = System.currentTimeMillis();
+
+      Context context = Leanplum.getContext();
+      SharedPreferences preferences = context.getSharedPreferences(
+          LEANPLUM, Context.MODE_PRIVATE);
+      SharedPreferences.Editor editor = preferences.edit();
+
+      int count = preferences.getInt(Constants.Defaults.COUNT_KEY, 0);
+      if (count == 0) {
+        return new ArrayList<>();
+      }
+      if (remove) {
+        editor.remove(Constants.Defaults.COUNT_KEY);
+      }
+
+      for (int i = 0; i < count; i++) {
+        String itemKey = String.format(Locale.US, Constants.Defaults.ITEM_KEY, i);
+        Map<String, Object> requestArgs;
+        try {
+          requestArgs = JsonConverter.mapFromJson(new JSONObject(
+              preferences.getString(itemKey, "{}")));
+          requestData.add(requestArgs);
+        } catch (JSONException e) {
+          e.printStackTrace();
+        }
+        if (remove) {
+          editor.remove(itemKey);
+        }
+      }
+      if (remove) {
+        try {
+          editor.apply();
+        } catch (NoSuchMethodError e) {
+          editor.commit();
+        }
+      }
+    }
+
+    requestData = removeIrrelevantBackgroundStartRequests(requestData);
+    return requestData;
+  }
+
+  /**
+   * In various scenarios we can end up batching a big number of requests (e.g. device is offline,
+   * background sessions), which could make the stored API calls batch look something like:
+   * <p>
+   * <code>start(B), start(B), start(F), track, start(B), track, start(F), resumeSession</code>
+   * <p>
+   * where <code>start(B)</code> indicates a start in the background, and <code>start(F)</code>
+   * one in the foreground.
+   * <p>
+   * In this case the first two <code>start(B)</code> can be dropped because they don't contribute
+   * any relevant information for the batch call.
+   * <p>
+   * Essentially we drop every <code>start(B)</code> call, that is directly followed by any kind of
+   * a <code>start</code> call.
+   *
+   * @param requestData A list of the requests, stored on the device.
+   * @return A list of only these requests, which contain relevant information for the API call.
+   */
+  private static List<Map<String, Object>> removeIrrelevantBackgroundStartRequests(
+      List<Map<String, Object>> requestData) {
+    List<Map<String, Object>> relevantRequests = new ArrayList<>();
+
+    int requestCount = requestData.size();
+    if (requestCount > 0) {
+      for (int i = 0; i < requestCount; i++) {
+        Map<String, Object> currentRequest = requestData.get(i);
+        if (i < requestCount - 1
+            && Constants.Methods.START.equals(requestData.get(i + 1).get(Constants.Params.ACTION))
+            && Constants.Methods.START.equals(currentRequest.get(Constants.Params.ACTION))
+            && Boolean.TRUE.toString().equals(currentRequest.get(Constants.Params.BACKGROUND))) {
+          continue;
+        }
+        relevantRequests.add(currentRequest);
+      }
+    }
+
+    return relevantRequests;
+  }
+
+  private static String jsonEncodeUnsentRequests(List<Map<String, Object>> requestData) {
+    Map<String, Object> data = new HashMap<>();
+    data.put(Constants.Params.DATA, requestData);
+    return JsonConverter.toJson(data);
+  }
+
+  private static void pushUnsentRequests(List<Map<String, Object>> requestData) {
+    if (requestData == null) {
+      return;
+    }
+    for (Map<String, Object> args : requestData) {
+      Object retryCountString = args.get("retryCount");
+      int retryCount;
+      if (retryCountString != null) {
+        retryCount = Integer.parseInt(retryCountString.toString()) + 1;
+      } else {
+        retryCount = 1;
+      }
+      args.put("retryCount", Integer.toString(retryCount));
+      saveRequestForLater(args);
+    }
+  }
+
+  private static String getSizeAsString(int bytes) {
+    if (bytes < (1 << 10)) {
+      return bytes + " B";
+    } else if (bytes < (1 << 20)) {
+      return (bytes >> 10) + " KB";
+    } else {
+      return (bytes >> 20) + " MB";
+    }
+  }
+
+  private static void printUploadProgress() {
+    int totalFiles = fileUploadSize.size();
+    int sentFiles = 0;
+    int totalBytes = 0;
+    int sentBytes = 0;
+    for (Map.Entry<File, Long> entry : fileUploadSize.entrySet()) {
+      File file = entry.getKey();
+      long fileSize = entry.getValue();
+      double fileProgress = fileUploadProgress.get(file);
+      if (fileProgress == 1) {
+        sentFiles++;
+      }
+      sentBytes += (int) (fileSize * fileProgress);
+      totalBytes += fileSize;
+    }
+    String progressString = "Uploading resources. " +
+        sentFiles + '/' + totalFiles + " files completed; " +
+        getSizeAsString(sentBytes) + '/' + getSizeAsString(totalBytes) + " transferred.";
+    if (!fileUploadProgressString.equals(progressString)) {
+      fileUploadProgressString = progressString;
+      Log.i(progressString);
+    }
+  }
+
+  public void sendFilesNow(final List<String> filenames, final List<InputStream> streams) {
+    if (Constants.isTestMode) {
+      return;
+    }
+    final Map<String, Object> dict = createArgsDictionary();
+    if (!attachApiKeys(dict)) {
+      return;
+    }
+    final List<File> filesToUpload = new ArrayList<>();
+
+    // First set up the files for upload
+    for (int i = 0; i < filenames.size(); i++) {
+      String filename = filenames.get(i);
+      if (filename == null || Boolean.TRUE.equals(fileTransferStatus.get(filename))) {
+        continue;
+      }
+      File file = new File(filename);
+      long size;
+      try {
+        size = streams.get(i).available();
+      } catch (IOException e) {
+        size = file.length();
+      } catch (NullPointerException e) {
+        // Not good. Can't read asset.
+        Log.e("Unable to read file " + filename);
+        continue;
+      }
+      fileTransferStatus.put(filename, true);
+      filesToUpload.add(file);
+      fileUploadSize.put(file, size);
+      fileUploadProgress.put(file, 0.0);
+    }
+    if (filesToUpload.size() == 0) {
+      return;
+    }
+
+    printUploadProgress();
+
+    // Now upload the files
+    Util.executeAsyncTask(new AsyncTask<Void, Void, Void>() {
+      @Override
+      protected Void doInBackground(Void... params) {
+        synchronized (uploadFileLock) {  // Don't overload app and server with many upload tasks
+          JSONObject result;
+          HttpURLConnection op = null;
+
+          try {
+            op = Util.uploadFilesOperation(
+                Constants.Params.FILE,
+                filesToUpload,
+                streams,
+                Constants.API_HOST_NAME,
+                Constants.API_SERVLET,
+                dict,
+                httpMethod,
+                Constants.API_SSL,
+                60);
+
+            if (op != null) {
+              result = Util.getJsonResponse(op);
+              int statusCode = op.getResponseCode();
+              if (statusCode != 200) {
+                throw new Exception("Leanplum: Error sending request: " + statusCode);
+              }
+              if (Request.this.response != null) {
+                Request.this.response.response(result);
+              }
+            } else {
+              if (error != null) {
+                error.error(new Exception("Leanplum: Unable to read file."));
+              }
+            }
+          } catch (JSONException e) {
+            Log.e("Unable to convert to JSON.", e);
+            if (error != null) {
+              error.error(e);
+            }
+          } catch (SocketTimeoutException e) {
+            Log.e("Timeout uploading files. Try again or limit the number of files " +
+                "to upload with parameters to syncResourcesAsync.");
+            if (error != null) {
+              error.error(e);
+            }
+          } catch (Exception e) {
+            Log.e("Unable to send file.", e);
+            if (error != null) {
+              error.error(e);
+            }
+          } finally {
+            if (op != null) {
+              op.disconnect();
+            }
+          }
+
+          for (File file : filesToUpload) {
+            fileUploadProgress.put(file, 1.0);
+          }
+          printUploadProgress();
+
+          return null;
+        }
+      }
+    });
+
+    // TODO: Upload progress
+  }
+
+  void downloadFile(final String path, final String url) {
+    if (Constants.isTestMode) {
+      return;
+    }
+    if (Boolean.TRUE.equals(fileTransferStatus.get(path))) {
+      return;
+    }
+    pendingDownloads++;
+    Log.i("Downloading resource " + path);
+    fileTransferStatus.put(path, true);
+    final Map<String, Object> dict = createArgsDictionary();
+    dict.put(Constants.Keys.FILENAME, path);
+    if (!attachApiKeys(dict)) {
+      return;
+    }
+
+    Util.executeAsyncTask(new AsyncTask<Void, Void, Void>() {
+      @Override
+      protected Void doInBackground(Void... params) {
+        try {
+          downloadHelper(Constants.API_HOST_NAME, Constants.API_SERVLET, path, url, dict);
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+        return null;
+      }
+    });
+    // TODO: Download progress
+  }
+
+  private void downloadHelper(String hostName, String servlet, final String path, final String url,
+      final Map<String, Object> dict) {
+    HttpURLConnection op = null;
+    URL originalURL = null;
+    try {
+      if (url == null) {
+        op = Util.operation(
+            hostName,
+            servlet,
+            dict,
+            httpMethod,
+            Constants.API_SSL,
+            Constants.NETWORK_TIMEOUT_SECONDS_FOR_DOWNLOADS);
+      } else {
+        op = Util.createHttpUrlConnection(url, httpMethod, url.startsWith("https://"),
+            Constants.NETWORK_TIMEOUT_SECONDS_FOR_DOWNLOADS);
+      }
+      originalURL = op.getURL();
+      op.connect();
+      int statusCode = op.getResponseCode();
+      if (statusCode != 200) {
+        throw new Exception("Leanplum: Error sending request to: " + hostName +
+            ", HTTP status code: " + statusCode);
+      }
+      Stack<String> dirs = new Stack<>();
+      String currentDir = path;
+      while ((currentDir = new File(currentDir).getParent()) != null) {
+        dirs.push(currentDir);
+      }
+      while (!dirs.isEmpty()) {
+        String directory = FileManager.fileRelativeToDocuments(dirs.pop());
+        boolean isCreated = new File(directory).mkdir();
+        if (!isCreated) {
+          Log.w("Failed to create directory: ", directory);
+        }
+      }
+
+      FileOutputStream out = new FileOutputStream(
+          new File(FileManager.fileRelativeToDocuments(path)));
+      Util.saveResponse(op, out);
+      pendingDownloads--;
+      if (Request.this.response != null) {
+        Request.this.response.response(null);
+      }
+      if (pendingDownloads == 0 && noPendingDownloadsBlock != null) {
+        noPendingDownloadsBlock.noPendingDownloads();
+      }
+    } catch (Exception e) {
+      if (e instanceof EOFException) {
+        if (op != null && !op.getURL().equals(originalURL)) {
+          downloadHelper(null, op.getURL().toString(), path, url, new HashMap<String, Object>());
+          return;
+        }
+      }
+      Log.e("Error downloading resource:" + path, e);
+      pendingDownloads--;
+      if (error != null) {
+        error.error(e);
+      }
+      if (pendingDownloads == 0 && noPendingDownloadsBlock != null) {
+        noPendingDownloadsBlock.noPendingDownloads();
+      }
+    } finally {
+      if (op != null) {
+        op.disconnect();
+      }
+    }
+  }
+
+  public static int numPendingDownloads() {
+    return pendingDownloads;
+  }
+
+  public static void onNoPendingDownloads(NoPendingDownloadsCallback block) {
+    noPendingDownloadsBlock = block;
+  }
+
+
+  public static int numResponses(JSONObject response) {
+    if (response == null) {
+      return 0;
+    }
+    try {
+      return response.getJSONArray("response").length();
+    } catch (JSONException e) {
+      Log.e("Could not parse JSON response.", e);
+      return 0;
+    }
+  }
+
+  public static JSONObject getResponseAt(JSONObject response, int index) {
+    try {
+      return response.getJSONArray("response").getJSONObject(index);
+    } catch (JSONException e) {
+      Log.e("Could not parse JSON response.", e);
+      return null;
+    }
+  }
+
+  public static JSONObject getLastResponse(JSONObject response) {
+    int numResponses = numResponses(response);
+    if (numResponses > 0) {
+      return getResponseAt(response, numResponses - 1);
+    } else {
+      return null;
+    }
+  }
+
+  public static boolean isResponseSuccess(JSONObject response) {
+    if (response == null) {
+      return false;
+    }
+    try {
+      return response.getBoolean("success");
+    } catch (JSONException e) {
+      Log.e("Could not parse JSON response.", e);
+      return false;
+    }
+  }
+
+  public static String getResponseError(JSONObject response) {
+    if (response == null) {
+      return null;
+    }
+    try {
+      JSONObject error = response.optJSONObject("error");
+      if (error == null) {
+        return null;
+      }
+      return error.getString("message");
+    } catch (JSONException e) {
+      Log.e("Could not parse JSON response.", e);
+      return null;
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/RequestFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import java.util.Map;
+
+public class RequestFactory {
+  public static RequestFactory defaultFactory;
+
+  public synchronized static RequestFactory getInstance() {
+    if (defaultFactory == null) {
+      defaultFactory = new RequestFactory();
+    }
+    return defaultFactory;
+  }
+
+  public Request createRequest(
+      String httpMethod, String apiMethod, Map<String, Object> params) {
+    return new Request(httpMethod, apiMethod, params);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/ResourceQualifiers.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.content.res.Configuration;
+import android.os.Build;
+import android.util.DisplayMetrics;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ResourceQualifiers {
+  public static abstract class QualifierFilter {
+    abstract Object getMatch(String str);
+
+    public abstract boolean isMatch(Object value, Configuration config, DisplayMetrics display);
+
+    public Map<String, Object> bestMatch(Map<String, Object> values, Configuration config, DisplayMetrics display) {
+      return values;
+    }
+  }
+
+  public enum Qualifier {
+    MCC(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.startsWith("mcc")) {
+          return Integer.getInteger(str.substring(3));
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.mcc == ((Integer) value);
+      }
+    }),
+    MNC(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.startsWith("mnc")) {
+          return Integer.getInteger(str.substring(3));
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.mnc == ((Integer) value);
+      }
+    }),
+    LANGUAGE(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.length() == 2) {
+          return str;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.locale.getLanguage().equals(value);
+      }
+    }),
+    REGION(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.startsWith("r") && str.length() == 3) {
+          return str.substring(1);
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.locale.getCountry().toLowerCase().equals(value);
+      }
+    }),
+    LAYOUT_DIRECTION(new QualifierFilter() {
+      // From http://developer.android.com/reference/android/content/res/Configuration.html#SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
+      public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x00000040;
+      public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x00000080;
+      public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0x000000c0;
+
+      @Override
+      public Object getMatch(String str) {
+        if ("ldrtl".equals(str)) {
+          return SCREENLAYOUT_LAYOUTDIR_RTL;
+        } else if ("ldltr".equals(str)) {
+          return SCREENLAYOUT_LAYOUTDIR_LTR;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return (config.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) == (Integer) value;
+      }
+    }),
+    SMALLEST_WIDTH(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.startsWith("sw") && str.endsWith("dp")) {
+          return Integer.getInteger(str.substring(2, str.length() - 2));
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        try {
+          Field field = config.getClass().getField("smallestScreenWidthDp");
+          int smallestWidthDp = (int) (Integer) field.get(config);
+          return smallestWidthDp >= (Integer) value;
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+        return false;
+      }
+
+      @Override
+      public Map<String, Object> bestMatch(Map<String, Object> values, Configuration config, DisplayMetrics display) {
+        Map<String, Object> result = new HashMap<>();
+        int max = Integer.MIN_VALUE;
+        for (Map.Entry<String, Object> entry : values.entrySet()) {
+          Integer intObj = (Integer) entry.getValue();
+          if (intObj > max) {
+            max = intObj;
+            result.clear();
+          }
+          if (intObj == max) {
+            result.put(entry.getKey(), intObj);
+          }
+        }
+        return result;
+      }
+    }),
+    AVAILABLE_WIDTH(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.startsWith("w") && str.endsWith("dp")) {
+          return Integer.getInteger(str.substring(1, str.length() - 2));
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        try {
+          Field field = config.getClass().getField("screenWidthDp");
+          int screenWidthDp = (int) (Integer) field.get(config);
+          return screenWidthDp >= (Integer) value;
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+        return false;
+      }
+
+      @Override
+      public Map<String, Object> bestMatch(Map<String, Object> values, Configuration config, DisplayMetrics display) {
+        Map<String, Object> result = new HashMap<>();
+        int max = Integer.MIN_VALUE;
+        for (Map.Entry<String, Object> entry : values.entrySet()) {
+          Integer intObj = (Integer) entry.getValue();
+          if (intObj > max) {
+            max = intObj;
+            result.clear();
+          }
+          if (intObj == max) {
+            result.put(entry.getKey(), intObj);
+          }
+        }
+        return result;
+      }
+    }),
+    AVAILABLE_HEIGHT(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.startsWith("h") && str.endsWith("dp")) {
+          return Integer.getInteger(str.substring(1, str.length() - 2));
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        try {
+          Field field = config.getClass().getField("screenHeightDp");
+          int screenHeightDp = (int) (Integer) field.get(config);
+          return screenHeightDp >= (Integer) value;
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+        return false;
+      }
+
+      @Override
+      public Map<String, Object> bestMatch(Map<String, Object> values, Configuration config, DisplayMetrics display) {
+        Map<String, Object> result = new HashMap<>();
+        int max = Integer.MIN_VALUE;
+        for (Map.Entry<String, Object> entry : values.entrySet()) {
+          Integer intObj = (Integer) entry.getValue();
+          if (intObj > max) {
+            max = intObj;
+            result.clear();
+          }
+          if (intObj == max) {
+            result.put(entry.getKey(), intObj);
+          }
+        }
+        return result;
+      }
+    }),
+    SCREEN_SIZE(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("small".equals(str)) {
+          return Configuration.SCREENLAYOUT_SIZE_SMALL;
+        } else if ("normal".equals(str)) {
+          return Configuration.SCREENLAYOUT_SIZE_NORMAL;
+        } else if ("large".equals(str)) {
+          return Configuration.SCREENLAYOUT_SIZE_LARGE;
+        } else if ("xlarge".equals(str)) {
+          return Configuration.SCREENLAYOUT_SIZE_XLARGE;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) <= (Integer) value;
+      }
+
+      @Override
+      public Map<String, Object> bestMatch(Map<String, Object> values, Configuration config, DisplayMetrics display) {
+        Map<String, Object> result = new HashMap<>();
+        int max = Integer.MIN_VALUE;
+        for (Map.Entry<String, Object> entry : values.entrySet()) {
+          Integer intObj = (Integer) entry.getValue();
+          if (intObj > max) {
+            max = intObj;
+            result.clear();
+          }
+          if (intObj == max) {
+            result.put(entry.getKey(), intObj);
+          }
+        }
+        return result;
+      }
+    }),
+    SCREEN_ASPECT(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("long".equals(str)) {
+          return Configuration.SCREENLAYOUT_LONG_YES;
+        } else if ("notlong".equals(str)) {
+          return Configuration.SCREENLAYOUT_LONG_NO;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) == (Integer) value;
+      }
+    }),
+    SCREEN_ORIENTATION(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("port".equals(str)) {
+          return Configuration.ORIENTATION_PORTRAIT;
+        } else if ("land".equals(str)) {
+          return Configuration.ORIENTATION_LANDSCAPE;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.orientation == (Integer) value;
+      }
+    }),
+    UI_MODE(new QualifierFilter() {
+      public static final int UI_MODE_TYPE_TELEVISION = 0x00000004;
+      public static final int UI_MODE_TYPE_APPLIANCE = 0x00000005;
+
+      @Override
+      public Object getMatch(String str) {
+        if ("car".equals(str)) {
+          return Configuration.UI_MODE_TYPE_CAR;
+        } else if ("desk".equals(str)) {
+          return Configuration.UI_MODE_TYPE_DESK;
+        } else if ("television".equals(str)) {
+          return UI_MODE_TYPE_TELEVISION;
+        } else if ("appliance".equals(str)) {
+          return UI_MODE_TYPE_APPLIANCE;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return (config.uiMode & Configuration.UI_MODE_TYPE_MASK) == (Integer) value;
+      }
+    }),
+    NIGHT_MODE(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("night".equals(str)) {
+          return Configuration.UI_MODE_NIGHT_YES;
+        } else if ("notnight".equals(str)) {
+          return Configuration.UI_MODE_NIGHT_NO;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) == (Integer) value;
+      }
+    }),
+    SCREEN_PIXEL_DENSITY(new QualifierFilter() {
+      public static final int DENSITY_TV = 0x000000d5;
+      public static final int DENSITY_XXHIGH = 0x000001e0;
+      public static final int DENSITY_NONE = 0;
+
+      @Override
+      public Object getMatch(String str) {
+        if ("ldpi".equals(str)) {
+          return DisplayMetrics.DENSITY_LOW;
+        } else if ("mdpi".equals(str)) {
+          return DisplayMetrics.DENSITY_MEDIUM;
+        } else if ("hdpi".equals(str)) {
+          return DisplayMetrics.DENSITY_HIGH;
+        } else if ("xhdpi".equals(str)) {
+          return DisplayMetrics.DENSITY_XHIGH;
+        } else if ("nodpi".equals(str)) {
+          return DENSITY_NONE;
+        } else if ("tvdpi".equals(str)) {
+          return DENSITY_TV;
+        } else if ("xxhigh".equals(str)) {
+          return DENSITY_XXHIGH;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return true;
+      }
+
+      @Override
+      public Map<String, Object> bestMatch(Map<String, Object> values, Configuration config, DisplayMetrics display) {
+        Map<String, Object> result = new HashMap<>();
+        int min = Integer.MAX_VALUE;
+
+        for (Map.Entry<String, Object> entry : values.entrySet()) {
+          Integer intObj = (Integer) entry.getValue();
+          if (intObj < min && intObj >= display.densityDpi) {
+            min = intObj;
+            result.clear();
+          }
+          if (intObj == min) {
+            result.put(entry.getKey(), intObj);
+          }
+        }
+        if (result.size() == 0) {
+          int max = Integer.MIN_VALUE;
+          for (String key : values.keySet()) {
+            Integer intObj = (Integer) values.get(key);
+            if (intObj > max) {
+              max = intObj;
+              result.clear();
+            }
+            if (intObj == max) {
+              result.put(key, intObj);
+            }
+          }
+        }
+        return result;
+      }
+    }),
+    TOUCHSCREEN_TYPE(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("notouch".equals(str)) {
+          return Configuration.TOUCHSCREEN_NOTOUCH;
+        } else if ("finger".equals(str)) {
+          return Configuration.TOUCHSCREEN_FINGER;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.touchscreen == (Integer) value;
+      }
+    }),
+    KEYBOARD_AVAILABILITY(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("keysexposed".equals(str)) {
+          return Configuration.KEYBOARDHIDDEN_NO;
+        } else if ("keyshidden".equals(str)) {
+          return Configuration.KEYBOARDHIDDEN_YES;
+        } else if ("keyssoft".equals(str)) {
+          return 0;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return (Integer) value == 0 || config.keyboardHidden == (Integer) value;
+      }
+    }),
+    PRIMARY_TEXT_INPUTMETHOD(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("nokeys".equals(str)) {
+          return Configuration.KEYBOARD_NOKEYS;
+        } else if ("qwerty".equals(str)) {
+          return Configuration.KEYBOARD_QWERTY;
+        } else if ("12key".equals(str)) {
+          return Configuration.KEYBOARD_12KEY;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.keyboard == (Integer) value;
+      }
+    }),
+    NAVIGATION_KEY_AVAILABILITY(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("navexposed".equals(str)) {
+          return Configuration.NAVIGATIONHIDDEN_NO;
+        } else if ("navhidden".equals(str)) {
+          return Configuration.NAVIGATIONHIDDEN_YES;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.navigationHidden == (Integer) value;
+      }
+    }),
+    PRIMARY_NON_TOUCH_NAVIGATION_METHOD(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if ("nonav".equals(str)) {
+          return Configuration.NAVIGATION_NONAV;
+        } else if ("dpad".equals(str)) {
+          return Configuration.NAVIGATION_DPAD;
+        } else if ("trackball".equals(str)) {
+          return Configuration.NAVIGATION_TRACKBALL;
+        } else if ("wheel".equals(str)) {
+          return Configuration.NAVIGATION_WHEEL;
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return config.navigation == (Integer) value;
+      }
+    }),
+    PLATFORM_VERSION(new QualifierFilter() {
+      @Override
+      public Object getMatch(String str) {
+        if (str.startsWith("v")) {
+          return Integer.getInteger(str.substring(1));
+        }
+        return null;
+      }
+
+      @Override
+      public boolean isMatch(Object value, Configuration config, DisplayMetrics display) {
+        return Build.VERSION.SDK_INT >= (Integer) value;
+      }
+    });
+
+    private QualifierFilter filter;
+
+    Qualifier(QualifierFilter filter) {
+      this.filter = filter;
+    }
+
+    public QualifierFilter getFilter() {
+      return filter;
+    }
+  }
+
+  public Map<Qualifier, Object> qualifiers = new HashMap<>();
+
+  public static ResourceQualifiers fromFolder(String folderName) {
+    ResourceQualifiers result = new ResourceQualifiers();
+    String[] nameParts = folderName.toLowerCase().split("-");
+    int qualifierIndex = 0;
+    for (String part : nameParts) {
+      boolean isMatch = false;
+      while (!isMatch && qualifierIndex < Qualifier.values().length) {
+        Qualifier qualifier = Qualifier.values()[qualifierIndex];
+        Object match = qualifier.getFilter().getMatch(part);
+        if (match != null) {
+          result.qualifiers.put(qualifier, match);
+          isMatch = true;
+        }
+        qualifierIndex++;
+      }
+    }
+    return result;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Socket.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.LeanplumEditorMode;
+import com.leanplum.callbacks.VariablesChangedCallback;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Leanplum socket class, that handles connections to the Leanplum remote socket.
+ *
+ * @author Andrew First, Ben Marten
+ */
+public class Socket {
+  private static final String TAG = "Leanplum";
+  private static final String EVENT_CONTENT_RESPONSE = "getContentResponse";
+  private static final String EVENT_UPDATE_VARS = "updateVars";
+  private static final String EVENT_GET_VIEW_HIERARCHY = "getViewHierarchy";
+  private static final String EVENT_PREVIEW_UPDATE_RULES = "previewUpdateRules";
+  private static final String EVENT_TRIGGER = "trigger";
+  private static final String EVENT_GET_VARIABLES = "getVariables";
+  private static final String EVENT_GET_ACTIONS = "getActions";
+  private static final String EVENT_REGISTER_DEVICE = "registerDevice";
+
+  private static Socket instance = new Socket();
+  private SocketIOClient sio;
+  private boolean authSent;
+  private boolean connected = false;
+  private boolean connecting = false;
+
+  public Socket() {
+    createSocketClient();
+  }
+
+  public static Socket getInstance() {
+    return instance;
+  }
+
+  private void createSocketClient() {
+    SocketIOClient.Handler socketIOClientHandler = new SocketIOClient.Handler() {
+      @Override
+      public void onError(Exception error) {
+        Log.e("Development socket error", error);
+      }
+
+      @Override
+      public void onDisconnect(int code, String reason) {
+        Log.i("Disconnected from development server");
+        connected = false;
+        connecting = false;
+        authSent = false;
+      }
+
+      @Override
+      public void onConnect() {
+        if (!authSent) {
+          Log.i("Connected to development server");
+          try {
+            Map<String, String> args = Util.newMap(
+                Constants.Params.APP_ID, Request.appId(),
+                Constants.Params.DEVICE_ID, Request.deviceId());
+            try {
+              sio.emit("auth", new JSONArray(Collections.singletonList(new JSONObject(args))));
+            } catch (JSONException e) {
+              e.printStackTrace();
+            }
+          } catch (Throwable t) {
+            Util.handleException(t);
+          }
+          authSent = true;
+          connected = true;
+          connecting = false;
+        }
+      }
+
+      @Override
+      public void on(String event, JSONArray arguments) {
+        try {
+          switch (event) {
+            case EVENT_UPDATE_VARS:
+              Leanplum.forceContentUpdate();
+              break;
+            case EVENT_TRIGGER:
+              handleTriggerEvent(arguments);
+              break;
+            case EVENT_GET_VIEW_HIERARCHY:
+              LeanplumUIEditorWrapper.getInstance().startUpdating();
+              LeanplumUIEditorWrapper.getInstance().sendUpdate();
+              break;
+            case EVENT_PREVIEW_UPDATE_RULES:
+              previewUpdateRules(arguments);
+              break;
+            case EVENT_GET_VARIABLES:
+              handleGetVariablesEvent();
+              break;
+            case EVENT_GET_ACTIONS:
+              handleGetActionsEvent();
+              break;
+            case EVENT_REGISTER_DEVICE:
+              handleRegisterDeviceEvent(arguments);
+              break;
+            default:
+              break;
+          }
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+    };
+
+    try {
+      sio = new SocketIOClient(new URI("http://" + Constants.SOCKET_HOST + ":" +
+          Constants.SOCKET_PORT), socketIOClientHandler);
+    } catch (URISyntaxException e) {
+      Log.e(e.getMessage());
+    }
+    connect();
+    Timer reconnectTimer = new Timer();
+    reconnectTimer.schedule(new TimerTask() {
+      @Override
+      public void run() {
+        try {
+          reconnect();
+        } catch (Throwable t) {
+          Util.handleException(t);
+        }
+      }
+    }, 0, 5000);
+  }
+
+  /**
+   * Connect to the remote socket.
+   */
+  private void connect() {
+    connecting = true;
+    sio.connect();
+  }
+
+  /**
+   * Disconnect from the remote socket.
+   */
+  private void reconnect() {
+    if (!connected && !connecting) {
+      connect();
+    }
+  }
+
+  /**
+   * Send a given event and data to the remote socket server.
+   *
+   * @param eventName The name of the event.
+   * @param data The data to be sent to the remote server.
+   */
+  public <T> void sendEvent(String eventName, Map<String, T> data) {
+    try {
+      Log.p("Sending event: " + eventName + " & data over socket:\n" + data);
+      sio.emit(eventName,
+          new JSONArray(Collections.singletonList(JsonConverter.mapToJsonObject(data))));
+    } catch (JSONException e) {
+      Log.e("Failed to create JSON data object: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Handles the "trigger" event received from server.
+   *
+   * @param arguments The arguments received from server.
+   */
+  void handleTriggerEvent(JSONArray arguments) {
+    // Trigger a custom action.
+    try {
+      JSONObject payload = arguments.getJSONObject(0);
+      JSONObject actionJson = payload.getJSONObject(Constants.Params.ACTION);
+      if (actionJson != null) {
+        String messageId = payload.getString(Constants.Params.MESSAGE_ID);
+        boolean isRooted = payload.getBoolean("isRooted");
+        String actionType = actionJson.getString(Constants.Values.ACTION_ARG);
+        Map<String, Object> defaultDefinition = CollectionUtil.uncheckedCast(
+            VarCache.actionDefinitions().get(actionType));
+        Map<String, Object> defaultArgs = null;
+        if (defaultDefinition != null) {
+          defaultArgs = CollectionUtil.uncheckedCast(defaultDefinition.get("values"));
+        }
+        Map<String, Object> action = JsonConverter.mapFromJson(actionJson);
+        action = CollectionUtil.uncheckedCast(VarCache.mergeHelper(defaultArgs, action));
+        ActionContext context = new ActionContext(actionType, action, messageId);
+        context.preventRealtimeUpdating();
+        ((BaseActionContext) context).setIsRooted(isRooted);
+        ((BaseActionContext) context).setIsPreview(true);
+        context.update();
+        LeanplumInternal.triggerAction(context);
+        ActionManager.getInstance().recordMessageImpression(messageId);
+      }
+    } catch (JSONException e) {
+      Log.e("Error getting action info", e);
+    }
+  }
+
+  /**
+   * Handles the "getVariables" event received from server.
+   */
+  public void handleGetVariablesEvent() {
+    boolean sentValues = VarCache.sendVariablesIfChanged();
+    VarCache.maybeUploadNewFiles();
+    sendEvent(EVENT_CONTENT_RESPONSE, Util.newMap("updated", sentValues));
+  }
+
+  /**
+   * Handles the "getActions" event received from server.
+   */
+  void handleGetActionsEvent() {
+    boolean sentValues = VarCache.sendActionsIfChanged();
+    VarCache.maybeUploadNewFiles();
+    sendEvent(EVENT_CONTENT_RESPONSE, Util.newMap("updated", sentValues));
+  }
+
+  /**
+   * Handles the "registerDevice" event received from server.
+   *
+   * @param arguments The arguments received from server.
+   */
+  void handleRegisterDeviceEvent(JSONArray arguments) {
+    LeanplumInternal.onHasStartedAndRegisteredAsDeveloper();
+    String emailArg = null;
+    try {
+      emailArg = arguments.getJSONObject(0).getString("email");
+    } catch (JSONException e) {
+      Log.v("Socket - No developer e-mail provided.");
+    }
+    final String email = (emailArg == null) ? "a Leanplum account" : emailArg;
+    OsHandler.getInstance().post(new Runnable() {
+      @Override
+      public void run() {
+        LeanplumActivityHelper.queueActionUponActive(new VariablesChangedCallback() {
+          @Override
+          public void variablesChanged() {
+            Activity activity = LeanplumActivityHelper.getCurrentActivity();
+            AlertDialog.Builder alert = new AlertDialog.Builder(activity);
+            alert.setTitle(TAG);
+            alert.setMessage("Your device is registered to " + email + ".");
+            alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+              @Override
+              public void onClick(DialogInterface dialog, int which) {
+              }
+            });
+            alert.show();
+          }
+        });
+      }
+    });
+  }
+
+  void previewUpdateRules(JSONArray arguments) {
+    JSONObject packetData;
+    try {
+      packetData = arguments.getJSONObject(0);
+    } catch (Exception e) {
+      Log.e("Error parsing data");
+      return;
+    }
+
+    if (!packetData.optBoolean("closed")) {
+      LeanplumUIEditorWrapper.getInstance().startUpdating();
+    } else {
+      LeanplumUIEditorWrapper.getInstance().stopUpdating();
+    }
+
+    LeanplumEditorMode mode;
+    int intMode = packetData.optInt("mode");
+    if (intMode >= LeanplumEditorMode.values().length) {
+      Log.p("Invalid editor mode in packet");
+      mode = LeanplumEditorMode.LP_EDITOR_MODE_INTERFACE;
+    } else {
+      mode = LeanplumEditorMode.values()[intMode];
+    }
+    LeanplumUIEditorWrapper.getInstance().setMode(mode);
+
+    JSONArray rules = packetData.optJSONArray("rules");
+    if (rules != null) {
+      List<Map<String, Object>> ruleDiffs = JsonConverter.listFromJson(rules);
+      VarCache.applyUpdateRuleDiffs(ruleDiffs);
+    }
+
+    LeanplumUIEditorWrapper.getInstance().sendUpdateDelayedDefault();
+  }
+
+  /**
+   * Returns whether the socket connection is established
+   *
+   * @return true if connected
+   */
+  public boolean isConnected() {
+    return connected;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/SocketIOClient.java
@@ -0,0 +1,264 @@
+// Copyright (c) 2009-2012 James Coglan
+// Copyright (c) 2012 Eric Butler 
+// Copyright (c) 2012 Koushik Dutta 
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the 'Software'), to deal in
+// the Software without restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished to do so,
+// subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// From https://github.com/koush/android-websockets
+
+package com.leanplum.internal;
+
+import android.net.http.AndroidHttpClient;
+import android.os.Looper;
+
+import com.leanplum.Leanplum;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.HashSet;
+
+class SocketIOClient {
+  interface Handler {
+    void onConnect();
+
+    void on(String event, JSONArray arguments);
+
+    void onDisconnect(int code, String reason);
+
+    void onError(Exception error);
+  }
+
+  private String mURL;
+  private Handler mHandler;
+  private String mSession;
+  private int mHeartbeat;
+  private WebSocketClient mClient;
+  private android.os.Handler mSendHandler;
+  private Looper mSendLooper;
+
+  public SocketIOClient(URI uri, Handler handler) {
+    // remove trailing "/" from URI, in case user provided e.g. http://test.com/
+    mURL = uri.toString().replaceAll("/$", "") + "/socket.io/1/";
+    mHandler = handler;
+  }
+
+  private static String userAgentString() {
+    String appName = (Leanplum.getContext() != null) ?
+        Util.getApplicationName(Leanplum.getContext()) + "/" + Util.getVersionName() : "websocket";
+    return appName + "(" + Request.appId() + "; " + Constants.CLIENT + "; "
+        + Constants.LEANPLUM_VERSION + "/" + Constants.LEANPLUM_PACKAGE_IDENTIFIER + ")";
+  }
+
+  private static String downloadUriAsString(final HttpUriRequest req)
+      throws IOException {
+    AndroidHttpClient client = AndroidHttpClient.newInstance(userAgentString());
+    try {
+      HttpResponse res = client.execute(req);
+      return readToEnd(res.getEntity().getContent());
+    } finally {
+      client.close();
+    }
+  }
+
+  private static byte[] readToEndAsArray(InputStream input) throws IOException {
+    DataInputStream dis = new DataInputStream(input);
+    byte[] stuff = new byte[1024];
+    ByteArrayOutputStream buff = new ByteArrayOutputStream();
+    int read;
+    while ((read = dis.read(stuff)) != -1) {
+      buff.write(stuff, 0, read);
+    }
+
+    return buff.toByteArray();
+  }
+
+  private static String readToEnd(InputStream input) throws IOException {
+    return new String(readToEndAsArray(input));
+  }
+
+  public void emit(String name, JSONArray args) throws JSONException {
+    final JSONObject event = new JSONObject();
+    event.put("name", name);
+    event.put("args", args);
+    // Log.d("Emitting event: " + event.toString());
+    mSendHandler.post(new Runnable() {
+      @Override
+      public void run() {
+        mClient.send(String.format("5:::%s", event.toString()));
+      }
+    });
+  }
+
+  private void connectSession() throws URISyntaxException {
+    mClient = new WebSocketClient(new URI(mURL + "websocket/" + mSession),
+        new WebSocketClient.Listener() {
+          @Override
+          public void onMessage(byte[] data) {
+            cleanup();
+            mHandler.onError(new Exception("Unexpected binary data"));
+          }
+
+          @Override
+          public void onMessage(String message) {
+            try {
+              // Log.d("Message: " + message);
+              String[] parts = message.split(":", 4);
+              int code = Integer.parseInt(parts[0]);
+              switch (code) {
+                case 1:
+                  onConnect();
+                  break;
+                case 2:
+                  // heartbeat
+                  mClient.send("2::");
+                  break;
+                case 3:
+                  // message
+                case 4:
+                  // json message
+                  throw new Exception("message type not supported");
+                case 5: {
+                  final String messageId = parts[1];
+                  final String dataString = parts[3];
+                  JSONObject data = new JSONObject(dataString);
+                  String event = data.getString("name");
+                  JSONArray args;
+                  try {
+                    args = data.getJSONArray("args");
+                  } catch (JSONException e) {
+                    args = new JSONArray();
+                  }
+                  if (!"".equals(messageId)) {
+                    mSendHandler.post(new Runnable() {
+                      @Override
+                      public void run() {
+                        mClient.send(String.format("6:::%s", messageId));
+                      }
+                    });
+                  }
+                  mHandler.on(event, args);
+                  break;
+                }
+                case 6:
+                  // ACK
+                  break;
+                case 7:
+                  // error
+                  throw new Exception(message);
+                case 8:
+                  // noop
+                  break;
+                default:
+                  throw new Exception("unknown code");
+              }
+            } catch (Exception ex) {
+              cleanup();
+              onError(ex);
+            }
+          }
+
+          @Override
+          public void onError(Exception error) {
+            cleanup();
+            mHandler.onError(error);
+          }
+
+          @Override
+          public void onDisconnect(int code, String reason) {
+            cleanup();
+            // attempt reconnect with same session?
+            mHandler.onDisconnect(code, reason);
+          }
+
+          @Override
+          public void onConnect() {
+            mSendHandler.postDelayed(new Runnable() {
+              @Override
+              public void run() {
+                mSendHandler.postDelayed(this, mHeartbeat);
+                mClient.send("2:::");
+              }
+            }, mHeartbeat);
+            mHandler.onConnect();
+          }
+        }, null);
+    mClient.connect();
+  }
+
+  public void disconnect() throws IOException {
+    cleanup();
+  }
+
+  private void cleanup() {
+    if (mClient != null) {
+      mClient.disconnect();
+      mClient = null;
+    }
+
+    if (mSendLooper != null) {
+      mSendLooper.quit();
+    }
+    mSendLooper = null;
+    mSendHandler = null;
+  }
+
+  public void connect() {
+    if (mClient != null)
+      return;
+    new Thread() {
+      public void run() {
+        HttpPost post = new HttpPost(mURL);
+        try {
+          String line = downloadUriAsString(post);
+          String[] parts = line.split(":");
+          mSession = parts[0];
+          String heartbeat = parts[1];
+          if (!"".equals(heartbeat))
+            mHeartbeat = Integer.parseInt(heartbeat) / 2 * 1000;
+          String transportsLine = parts[3];
+          String[] transports = transportsLine.split(",");
+          HashSet<String> set = new HashSet<>(Arrays.asList(transports));
+          if (!set.contains("websocket"))
+            throw new Exception("websocket not supported");
+
+          Looper.prepare();
+          mSendLooper = Looper.myLooper();
+          mSendHandler = new android.os.Handler();
+
+          connectSession();
+
+          Looper.loop();
+        } catch (Exception e) {
+          mHandler.onError(e);
+        }
+      }
+    }.start();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/Util.java
@@ -0,0 +1,972 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.provider.Settings.Secure;
+import android.support.annotation.RequiresPermission;
+import android.text.TextUtils;
+import android.util.TypedValue;
+
+import com.google.android.gms.ads.identifier.AdvertisingIdClient;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.LeanplumDeviceIdMode;
+import com.leanplum.LeanplumException;
+import com.leanplum.internal.Constants.Methods;
+import com.leanplum.internal.Constants.Params;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.UnsupportedCharsetException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Leanplum utilities.
+ *
+ * @author Andrew First
+ */
+public class Util {
+  private static final Executor asyncExecutor = Executors.newCachedThreadPool();
+
+  private static final String ACCESS_WIFI_STATE_PERMISSION = "android.permission.ACCESS_WIFI_STATE";
+
+  private static String appName = null;
+  private static String versionName = null;
+
+  private static boolean hasPlayServicesCalled = false;
+  private static boolean hasPlayServices = false;
+
+  public static class DeviceIdInfo {
+    public final String id;
+    public boolean limitAdTracking;
+
+    public DeviceIdInfo(String id) {
+      this.id = id;
+    }
+
+    public DeviceIdInfo(String id, boolean limitAdTracking) {
+      this.id = id;
+      this.limitAdTracking = limitAdTracking;
+    }
+  }
+
+  /**
+   * Gets MD5 hash of given string.
+   *
+   * @param string String for which want to have MD5 hash.
+   * @return String with MD5 hash of given string.
+   */
+  private static String md5(String string) throws Exception {
+    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
+    messageDigest.update(string.getBytes(Charset.forName("UTF-8")));
+    byte digest[] = messageDigest.digest();
+
+    StringBuilder result = new StringBuilder();
+    for (byte dig : digest) {
+      result.append(String.format("%02x", dig));
+    }
+    return result.toString();
+  }
+
+  /**
+   * Gets SHA-256 hash of given string.
+   */
+  public static String sha256(String string) throws NoSuchAlgorithmException {
+    MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
+    messageDigest.update(string.getBytes(Charset.forName("UTF-8")));
+    byte digest[] = messageDigest.digest();
+
+    StringBuilder result = new StringBuilder();
+    for (byte dig : digest) {
+      result.append(String.format("%02x", dig));
+    }
+    return result.toString();
+  }
+
+  private static String checkDeviceId(String deviceIdMethod, String deviceId) {
+    if (deviceId != null) {
+      if (!isValidDeviceId(deviceId)) {
+        Log.e("Invalid device id generated (" + deviceIdMethod + "): " + deviceId);
+        return null;
+      }
+    }
+    return deviceId;
+  }
+
+  @RequiresPermission(ACCESS_WIFI_STATE_PERMISSION)
+  private static String getWifiMacAddressHash(Context context) {
+    String logPrefix = "Skipping wifi device id; ";
+    if (context.checkCallingOrSelfPermission(ACCESS_WIFI_STATE_PERMISSION) !=
+        PackageManager.PERMISSION_GRANTED) {
+      Log.v(logPrefix + "no wifi state permissions.");
+      return null;
+    }
+    try {
+      WifiManager manager = (WifiManager) context.getApplicationContext()
+          .getSystemService(Context.WIFI_SERVICE);
+      WifiInfo wifiInfo = manager.getConnectionInfo();
+      if (wifiInfo == null) {
+        Log.i(logPrefix + "null WifiInfo.");
+        return null;
+      }
+      @SuppressLint("HardwareIds")
+      String macAddress = wifiInfo.getMacAddress();
+      if (macAddress == null || macAddress.isEmpty()) {
+        Log.i(logPrefix + "no mac address returned.");
+        return null;
+      }
+      if (Constants.INVALID_MAC_ADDRESS.equals(macAddress)) {
+        // Note(ed): this is the expected case for Marshmallow and later, as they return
+        // INVALID_MAC_ADDRESS; we intend to fall back to the Android id for Marshmallow devices.
+        Log.v(logPrefix + "Marshmallow and later returns a fake MAC address.");
+        return null;
+      }
+      @SuppressLint("HardwareIds")
+      String deviceId = md5(wifiInfo.getMacAddress());
+      Log.v("Using wifi device id: " + deviceId);
+      return checkDeviceId("mac address", deviceId);
+    } catch (Exception e) {
+      Log.w("Error getting wifi MAC address.");
+    }
+    return null;
+  }
+
+  /**
+   * Retrieves the advertising ID. Requires Google Play Services. Note: This method must not run on
+   * the main thread.
+   */
+  private static DeviceIdInfo getAdvertisingId(Context caller) throws Exception {
+    try {
+      AdvertisingIdClient.Info info = AdvertisingIdClient.getAdvertisingIdInfo(caller);
+      if (info != null) {
+        String advertisingId = info.getId();
+        String deviceId = checkDeviceId("advertising id", advertisingId);
+        if (deviceId != null) {
+          boolean limitedTracking = info.isLimitAdTrackingEnabled();
+          return new DeviceIdInfo(deviceId, limitedTracking);
+        }
+      }
+    } catch (Throwable t) {
+      Log.e("Error getting advertising ID. Google Play Services are not available: ", t);
+    }
+    return null;
+  }
+
+  private static String getAndroidId(Context context) {
+    @SuppressLint("HardwareIds")
+    String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
+    if (androidId == null || androidId.isEmpty()) {
+      Log.i("Skipping Android device id; no id returned.");
+      return null;
+    }
+    if (Constants.INVALID_ANDROID_ID.equals(androidId)) {
+      Log.v("Skipping Android device id; got invalid " + "device id: " + androidId);
+      return null;
+    }
+    Log.v("Using Android device id: " + androidId);
+    return checkDeviceId("android id", androidId);
+  }
+
+  /**
+   * Final fallback device id -- generate a random device id.
+   */
+  private static String generateRandomDeviceId() {
+    // Mark random IDs to be able to identify them.
+    String randomId = UUID.randomUUID().toString() + "-LP";
+    Log.v("Using generated device id: " + randomId);
+    return randomId;
+  }
+
+  private static boolean isValidForCharset(String id, String charsetName) {
+    CharsetEncoder encoder = null;
+    try {
+      Charset charset = Charset.forName(charsetName);
+      encoder = charset.newEncoder();
+    } catch (UnsupportedCharsetException e) {
+      Log.w("Unsupported charset: " + charsetName);
+    }
+    if (encoder != null && !encoder.canEncode(id)) {
+      Log.v("Invalid id (contains invalid characters): " + id);
+      return false;
+    }
+    return true;
+  }
+
+  public static boolean isValidUserId(String userId) {
+    String logPrefix = "Invalid user id ";
+    if (userId == null || userId.isEmpty()) {
+      Log.v(logPrefix + "(sentinel): " + userId);
+      return false;
+    }
+    if (userId.length() > Constants.MAX_USER_ID_LENGTH) {
+      Log.v(logPrefix + "(too long): " + userId);
+      return false;
+    }
+    if (userId.contains("\n")) {
+      Log.v(logPrefix + "(contains newline): " + userId);
+      return false;
+    }
+    if (userId.contains("\"") || userId.contains("\'")) {
+      Log.v(logPrefix + "(contains quotes): " + userId);
+      return false;
+    }
+    return isValidForCharset(userId, "UTF-8");
+  }
+
+  public static boolean isValidDeviceId(String deviceId) {
+    String logPrefix = "Invalid device id ";
+    if (deviceId == null || deviceId.isEmpty() ||
+        Constants.INVALID_ANDROID_ID.equals(deviceId) ||
+        Constants.INVALID_MAC_ADDRESS_HASH.equals(deviceId) ||
+        Constants.OLD_INVALID_MAC_ADDRESS_HASH.equals(deviceId)) {
+      Log.v(logPrefix + "(sentinel): " + deviceId);
+      return false;
+    }
+    if (deviceId.length() > Constants.MAX_DEVICE_ID_LENGTH) {
+      Log.v(logPrefix + "(too long): " + deviceId);
+      return false;
+    }
+    if (deviceId.contains("[")) {
+      Log.v(logPrefix + "(contains brackets): " + deviceId);
+      return false;
+    }
+    if (deviceId.contains("\n")) {
+      Log.v(logPrefix + "(contains newline): " + deviceId);
+      return false;
+    }
+    if (deviceId.contains(",")) {
+      Log.v(logPrefix + "(contains comma): " + deviceId);
+      return false;
+    }
+    if (deviceId.contains("\"") || deviceId.contains("\'")) {
+      Log.v(logPrefix + "(contains quotes): " + deviceId);
+      return false;
+    }
+    return isValidForCharset(deviceId, "US-ASCII");
+  }
+
+  @RequiresPermission(ACCESS_WIFI_STATE_PERMISSION)
+  public static DeviceIdInfo getDeviceId(LeanplumDeviceIdMode mode) {
+    Context context = Leanplum.getContext();
+
+    if (mode.equals(LeanplumDeviceIdMode.ADVERTISING_ID)) {
+      try {
+        DeviceIdInfo info = getAdvertisingId(context);
+        if (info != null) {
+          return info;
+        }
+      } catch (Exception e) {
+        Log.e("Error getting advertising ID", e);
+      }
+    }
+
+    if (isSimulator() || mode.equals(LeanplumDeviceIdMode.ANDROID_ID)) {
+      String androidId = getAndroidId(context);
+      if (androidId != null) {
+        return new DeviceIdInfo(getAndroidId(context));
+      }
+    }
+
+    String macAddressHash = getWifiMacAddressHash(context);
+    if (macAddressHash != null) {
+      return new DeviceIdInfo(macAddressHash);
+    }
+
+    String androidId = getAndroidId(context);
+    if (androidId != null) {
+      return new DeviceIdInfo(androidId);
+    }
+
+    return new DeviceIdInfo(generateRandomDeviceId());
+  }
+
+  public static String getVersionName() {
+    if (versionName != null) {
+      return versionName;
+    }
+    Context context = Leanplum.getContext();
+    try {
+      versionName = LeanplumManifestHelper.getAppVersionName();
+      // If we didn't get application version name from AndroidManifest.xml - will try to get it
+      // from PackageInfo.
+      if (TextUtils.isEmpty(versionName)) {
+        PackageInfo pInfo = context.getPackageManager().getPackageInfo(
+            context.getPackageName(), 0);
+        versionName = pInfo.versionName;
+      }
+    } catch (Exception e) {
+      Log.w("Could not extract versionName from Manifest or PackageInfo.");
+    }
+    return versionName;
+  }
+
+  public static String getDeviceModel() {
+    if (isSimulator()) {
+      return "Android Emulator";
+    }
+    String manufacturer = Build.MANUFACTURER;
+    String model = Build.MODEL;
+    if (model.startsWith(manufacturer)) {
+      return capitalize(model);
+    } else {
+      return capitalize(manufacturer) + " " + model;
+    }
+  }
+
+  public static String getApplicationName(Context context) {
+    if (appName != null) {
+      return appName;
+    }
+    int stringId = context.getApplicationInfo().labelRes;
+    if (stringId == 0) {
+      appName = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString();
+    } else {
+      appName = context.getString(stringId);
+    }
+    return appName;
+  }
+
+  private static String capitalize(String s) {
+    if (s == null || s.length() == 0) {
+      return "";
+    }
+    char first = s.charAt(0);
+    if (Character.isUpperCase(first)) {
+      return s;
+    } else {
+      return Character.toUpperCase(first) + s.substring(1);
+    }
+  }
+
+  @SuppressWarnings("SameReturnValue")
+  public static String getSystemName() {
+    return "Android OS";
+  }
+
+  @SuppressWarnings("SameReturnValue")
+  public static String getSystemVersion() {
+    return Build.VERSION.RELEASE;
+  }
+
+  public static boolean isSimulator() {
+    String model = android.os.Build.MODEL.toLowerCase(Locale.getDefault());
+    return model.contains("google_sdk")
+        || model.contains("emulator")
+        || model.contains("sdk");
+  }
+
+  public static String getDeviceName() {
+    if (isSimulator()) {
+      return "Android Emulator";
+    }
+    return getDeviceModel();
+  }
+
+  public static String getLocale() {
+    String language = Locale.getDefault().getLanguage();
+    if ("".equals(language)) {
+      language = "xx";
+    }
+    String country = Locale.getDefault().getCountry();
+    if ("".equals(country)) {
+      country = "XX";
+    }
+    return language + "_" + country;
+  }
+
+  /**
+   * Builds a query from Map containing parameters.
+   *
+   * @param params Params used to build a query.
+   * @return Query string or empty string in case params are null.
+   */
+  private static String getQuery(Map<String, Object> params) {
+    if (params == null) {
+      return "";
+    }
+    Uri.Builder builder = new Uri.Builder();
+    for (Map.Entry<String, Object> pair : params.entrySet()) {
+      if (pair.getValue() == null) {
+        Log.w("Request parameter for key: " + pair.getKey() + " is null.");
+        continue;
+      }
+      builder.appendQueryParameter(pair.getKey(), pair.getValue().toString());
+    }
+    return builder.build().getEncodedQuery();
+  }
+
+  public static HttpURLConnection operation(
+      String hostName,
+      String path,
+      Map<String, Object> params,
+      String httpMethod,
+      boolean ssl,
+      int timeoutSeconds) throws IOException {
+    if ("GET".equals(httpMethod)) {
+      path = attachGetParameters(path, params);
+    }
+    HttpURLConnection urlConnection = createHttpUrlConnection(hostName, path,
+        httpMethod, ssl, timeoutSeconds);
+
+    if (!"GET".equals(httpMethod)) {
+      attachPostParameters(params, urlConnection);
+    }
+
+    if (Constants.enableVerboseLoggingInDevelopmentMode
+        && Constants.isDevelopmentModeEnabled) {
+      Log.d("Sending request at path " + path + " with parameters " + params);
+    }
+    return urlConnection;
+  }
+
+  /**
+   * Converts and attaches GET parameters to specified path.
+   *
+   * @param path Path on which to attach parameters.
+   * @param params Params to convert and attach.
+   * @return Path with attached parameters.
+   */
+  private static String attachGetParameters(String path, Map<String, Object> params) {
+    if (params == null) {
+      return path;
+    }
+    Uri.Builder builder = Uri.parse(path).buildUpon();
+    for (Map.Entry<String, Object> pair : params.entrySet()) {
+      if (pair.getValue() == null) {
+        continue;
+      }
+      builder.appendQueryParameter(pair.getKey(), pair.getValue().toString());
+    }
+    return builder.build().toString();
+  }
+
+  /**
+   * Converts and writes POST parameters directly to an option http connection.
+   *
+   * @param params Params to post.
+   * @param urlConnection URL connection on which to write parameters.
+   * @throws IOException Throws in case it fails.
+   */
+  private static void attachPostParameters(Map<String, Object> params,
+      HttpURLConnection urlConnection) throws IOException {
+    OutputStream os = urlConnection.getOutputStream();
+    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
+    String query = getQuery(params);
+    writer.write(query);
+    writer.close();
+    os.close();
+  }
+
+  public static HttpURLConnection createHttpUrlConnection(String hostName,
+      String path, String httpMethod, boolean ssl, int timeoutSeconds)
+      throws IOException {
+    String fullPath;
+    if (path.startsWith("http")) {
+      fullPath = path;
+    } else {
+      fullPath = (ssl ? "https://" : "http://") + hostName + "/" + path;
+    }
+    return createHttpUrlConnection(fullPath, httpMethod, ssl, timeoutSeconds);
+  }
+
+  static HttpURLConnection createHttpUrlConnection(
+      String fullPath, String httpMethod, boolean ssl, int timeoutSeconds)
+      throws IOException {
+    URL url = new URL(fullPath);
+    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+    if (ssl) {
+      SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
+      ((HttpsURLConnection) urlConnection).setSSLSocketFactory(socketFactory);
+    }
+    urlConnection.setReadTimeout(timeoutSeconds * 1000);
+    urlConnection.setConnectTimeout(timeoutSeconds * 1000);
+    urlConnection.setRequestMethod(httpMethod);
+    urlConnection.setDoOutput(!"GET".equals(httpMethod));
+    urlConnection.setDoInput(true);
+    urlConnection.setUseCaches(false);
+    urlConnection.setInstanceFollowRedirects(true);
+    Context context = Leanplum.getContext();
+    urlConnection.setRequestProperty("User-Agent",
+        getApplicationName(context) + "/" + getVersionName() + "/" + Request.appId() + "/" +
+            Constants.CLIENT + "/" + Constants.LEANPLUM_VERSION + "/" + getSystemName() + "/" +
+            getSystemVersion() + "/" + Constants.LEANPLUM_PACKAGE_IDENTIFIER);
+    return urlConnection;
+  }
+
+  /**
+   * Writes the filesToUpload to a new HttpURLConnection using the multipart form data format.
+   *
+   * @return the connection that the files were uploaded using
+   */
+  public static HttpURLConnection uploadFilesOperation(
+      String key,
+      List<File> filesToUpload,
+      List<InputStream> streams,
+      String hostName,
+      String path,
+      Map<String, Object> params,
+      String httpMethod,
+      boolean ssl,
+      int timeoutSeconds) throws IOException {
+
+    HttpURLConnection urlConnection = createHttpUrlConnection(hostName, path,
+        httpMethod, ssl, timeoutSeconds);
+
+    final String BOUNDARY = "==================================leanplum";
+    final String LINE_END = "\r\n";
+    final String TWO_HYPHENS = "--";
+    final String CONTENT_TYPE = "Content-Type: application/octet-stream";
+
+    // Make a connection to the server
+    urlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
+    urlConnection.setRequestProperty("Connection", "Keep-Alive");
+
+    DataOutputStream outputStream = new DataOutputStream(urlConnection.getOutputStream());
+
+    // Create the header for the request with the parameters
+    for (Map.Entry<String, Object> entry : params.entrySet()) {
+      String paramData = TWO_HYPHENS + BOUNDARY + LINE_END
+          + "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINE_END
+          + LINE_END
+          + entry.getValue() + LINE_END;
+      outputStream.writeBytes(paramData);
+    }
+
+    // Main file writing loop
+    for (int i = 0; i < filesToUpload.size(); i++) {
+      File fileToUpload = filesToUpload.get(i);
+      String contentDisposition = String.format(Locale.getDefault(), "Content-Disposition: " +
+              "form-data; name=\"%s%d\";filename=\"%s\"",
+          key, i, fileToUpload.getName());
+
+      // Create the header for the file
+      String fileHeader = TWO_HYPHENS + BOUNDARY + LINE_END
+          + contentDisposition + LINE_END
+          + CONTENT_TYPE + LINE_END
+          + LINE_END;
+      outputStream.writeBytes(fileHeader);
+
+      // Read in the actual file
+      InputStream is = (i < streams.size()) ? streams.get(i) : new FileInputStream(fileToUpload);
+      byte[] buffer = new byte[4096];
+      int bytesRead;
+      try {
+        while ((bytesRead = is.read(buffer)) != -1) {
+          outputStream.write(buffer, 0, bytesRead);
+        }
+      } catch (NullPointerException e) {
+        Log.e("Unable to read file while uploading " + filesToUpload.get(i));
+        return null;
+      } finally {
+        if (is != null) {
+          try {
+            is.close();
+          } catch (IOException e) {
+            Log.w("Failed to close InputStream: " + e);
+          }
+        }
+      }
+
+      // End the output for this file
+      outputStream.writeBytes(LINE_END);
+    }
+
+    // End the output for the request
+    String endOfRequest = TWO_HYPHENS + BOUNDARY + TWO_HYPHENS + LINE_END;
+    outputStream.writeBytes(endOfRequest);
+
+    outputStream.flush();
+    outputStream.close();
+    return urlConnection;
+  }
+
+  public static void saveResponse(URLConnection op, OutputStream outputStream) throws IOException {
+    InputStream is = op.getInputStream();
+    byte[] buffer = new byte[4096];
+    int bytesRead;
+    while ((bytesRead = is.read(buffer)) != -1) {
+      outputStream.write(buffer, 0, bytesRead);
+    }
+    outputStream.close();
+  }
+
+  private static String getResponse(HttpURLConnection op) throws IOException {
+    InputStream inputStream;
+    if (op.getResponseCode() < 400) {
+      inputStream = op.getInputStream();
+    } else {
+      inputStream = op.getErrorStream();
+    }
+    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+    StringBuilder builder = new StringBuilder();
+    for (String line; (line = reader.readLine()) != null; ) {
+      builder.append(line).append("\n");
+    }
+
+    try {
+      inputStream.close();
+      reader.close();
+    } catch (Exception ignored) {
+    }
+
+    return builder.toString();
+  }
+
+  public static JSONObject getJsonResponse(HttpURLConnection op)
+      throws JSONException, IOException {
+    String response = getResponse(op);
+    if (Constants.enableVerboseLoggingInDevelopmentMode
+        && Constants.isDevelopmentModeEnabled) {
+      Log.d("Received response " + response);
+    }
+    JSONTokener tokener = new JSONTokener(response);
+    return new JSONObject(tokener);
+  }
+
+  /**
+   * Check whether the device has a network connection. WARNING: Does not check for available
+   * internet connection! use isOnline()
+   *
+   * @return Whether a network connection is available or not.
+   */
+  public static boolean isConnected() {
+    try {
+      Context context = Leanplum.getContext();
+      ConnectivityManager manager = (ConnectivityManager) context.getSystemService(
+          Context.CONNECTIVITY_SERVICE);
+      if (manager == null) {
+        return false;
+      }
+      NetworkInfo netInfo = manager.getActiveNetworkInfo();
+      return !(netInfo == null || !netInfo.isConnectedOrConnecting());
+    } catch (Exception e) {
+      Log.e("Error getting connectivity info", e);
+      return false;
+    }
+  }
+
+  public static <T> T multiIndex(Map<?, ?> map, Object... indices) {
+    if (map == null) {
+      return null;
+    }
+    Object current = map;
+    for (Object index : indices) {
+      if (!((Map<?, ?>) current).containsKey(index)) {
+        return null;
+      }
+      current = ((Map<?, ?>) current).get(index);
+    }
+    return CollectionUtil.uncheckedCast(current);
+  }
+
+  public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> task, T... params) {
+    if (Build.VERSION.SDK_INT >= 11) {
+      task.executeOnExecutor(asyncExecutor, params);
+    } else {
+      task.execute(params);
+    }
+  }
+
+  /**
+   * Check the device to make sure it has the Google Play Services APK. If it doesn't, display a
+   * dialog that allows users to download the APK from the Google Play Store or enable it in the
+   * device's system settings.
+   */
+  public static boolean hasPlayServices() {
+    if (hasPlayServicesCalled) {
+      return hasPlayServices;
+    }
+    Context context = Leanplum.getContext();
+    PackageManager packageManager = context.getPackageManager();
+    PackageInfo packageInfo;
+    try {
+      packageInfo = packageManager.getPackageInfo("com.google.android.gms",
+          PackageManager.GET_SIGNATURES);
+    } catch (PackageManager.NameNotFoundException e) {
+      hasPlayServicesCalled = true;
+      hasPlayServices = false;
+      return false;
+    }
+    if (packageInfo.versionCode < 4242000) {
+      Log.i("Google Play services version is too old: " + packageInfo.versionCode);
+      hasPlayServicesCalled = true;
+      hasPlayServices = false;
+      return false;
+    }
+    ApplicationInfo info;
+    try {
+      info = packageManager.getApplicationInfo("com.google.android.gms", 0);
+    } catch (PackageManager.NameNotFoundException e) {
+      hasPlayServicesCalled = true;
+      hasPlayServices = false;
+      return false;
+    }
+    hasPlayServicesCalled = true;
+    hasPlayServices = info.enabled;
+    return info.enabled;
+  }
+
+  public static boolean isInBackground() {
+    return (LeanplumActivityHelper.getCurrentActivity() == null ||
+        LeanplumActivityHelper.isActivityPaused());
+  }
+
+  /**
+   * Include install time and last app update time in start API params the first time that the app
+   * runs with Leanplum.
+   */
+  public static void initializePreLeanplumInstall(Map<String, Object> params) {
+    Context context = Leanplum.getContext();
+    SharedPreferences preferences = context.getSharedPreferences("__leanplum__",
+        Context.MODE_PRIVATE);
+    if (preferences.getBoolean(Constants.Keys.INSTALL_TIME_INITIALIZED, false)) {
+      return;
+    }
+
+    PackageManager packageManager = context.getPackageManager();
+    String packageName = context.getPackageName();
+    setInstallTime(params, packageManager, packageName);
+    setUpdateTime(params, packageManager, packageName);
+
+    SharedPreferences.Editor editor = preferences.edit();
+    editor.putBoolean(Constants.Keys.INSTALL_TIME_INITIALIZED, true);
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  /**
+   * Set install time from package manager and update time from apk file modification time.
+   */
+  private static void setInstallTime(Map<String, Object> params, PackageManager packageManager,
+      String packageName) {
+    try {
+      PackageInfo info = packageManager.getPackageInfo(packageName, 0);
+      params.put(Params.INSTALL_DATE, "" + (info.firstInstallTime / 1000.0));
+    } catch (NameNotFoundException e) {
+      Log.w("Failed to find package info: " + e);
+    }
+  }
+
+  /**
+   * Set update time from apk file modification time.
+   */
+  private static void setUpdateTime(Map<String, Object> params, PackageManager packageManager,
+      String packageName) {
+    try {
+      ApplicationInfo info = packageManager.getApplicationInfo(packageName, 0);
+      File apkFile = new File(info.sourceDir);
+      if (apkFile.exists()) {
+        params.put(Constants.Params.UPDATE_DATE, "" + (apkFile.lastModified() / 1000.0));
+      }
+    } catch (Throwable t) {
+      Log.w("Failed to find package info: " + t);
+    }
+  }
+
+  /**
+   * Handles uncaught exceptions in the SDK.
+   */
+  public static void handleException(Throwable t) {
+    if (t instanceof OutOfMemoryError) {
+      if (Constants.isDevelopmentModeEnabled) {
+        throw (OutOfMemoryError) t;
+      }
+      return;
+    }
+
+    // Propagate Leanplum generated exceptions.
+    if (t instanceof LeanplumException) {
+      if (Constants.isDevelopmentModeEnabled) {
+        throw (LeanplumException) t;
+      }
+      return;
+    }
+
+    Log.e("INTERNAL ERROR", t);
+
+    String versionName;
+    try {
+      versionName = getVersionName();
+    } catch (Throwable t2) {
+      versionName = "(Unknown)";
+    }
+
+    try {
+      Map<String, Object> params = new HashMap<>();
+      params.put(Params.TYPE, Constants.Values.SDK_ERROR);
+
+      String message = t.getMessage();
+      if (message != null) {
+        message = t.toString() + " (" + message + ')';
+      } else {
+        message = t.toString();
+      }
+      params.put(Params.MESSAGE, message);
+
+      StringWriter stringWriter = new StringWriter();
+      PrintWriter writer = new PrintWriter(stringWriter);
+      t.printStackTrace(writer);
+      params.put("stackTrace", stringWriter.toString());
+
+      params.put(Params.VERSION_NAME, versionName);
+      Request.post(Methods.LOG, params).send();
+    } catch (Throwable t2) {
+      Log.e("Unable to send error report.", t2);
+    }
+  }
+
+  /**
+   * Constructs a {@link HashMap} with the given keys and values.
+   */
+  public static <K, V> Map<K, V> newMap(K firstKey, V firstValue, Object... otherValues) {
+    if (otherValues.length % 2 == 1) {
+      throw new IllegalArgumentException("Must supply an even number of values.");
+    }
+
+    Map<K, V> map = new HashMap<>();
+    map.put(firstKey, firstValue);
+    for (int i = 0; i < otherValues.length; i += 2) {
+      K otherKey = CollectionUtil.uncheckedCast(otherValues[i]);
+      V otherValue = CollectionUtil.uncheckedCast(otherValues[i + 1]);
+      map.put(otherKey, otherValue);
+    }
+    return map;
+  }
+
+  /**
+   * Generates a Resource name from resourceId located in res/ folder.
+   *
+   * @param resourceId id of the resource, must be greater then 0.
+   * @return resourceName in format folder/file.extension.
+   */
+  public static String generateResourceNameFromId(int resourceId) {
+    try {
+      if (resourceId <= 0) {
+        Log.w("Provided resource id is invalid.");
+        return null;
+      }
+      Resources resources = Leanplum.getContext().getResources();
+      // Get entryName from resourceId, which represents a file name in res/ directory.
+      String entryName = resources.getResourceEntryName(resourceId);
+      // Get typeName from resourceId, which represents a folder where file is located in
+      // res/ directory.
+      String typeName = resources.getResourceTypeName(resourceId);
+
+      // By using TypedValue we can get full path of a file with extension.
+      TypedValue value = new TypedValue();
+      resources.getValue(resourceId, value, true);
+
+      // Regex matching to find real file extension, "image.img.png" will produce "png".
+      String[] fullFileName = value.string.toString().split("\\.(?=[^\\.]+$)");
+      String extension = "";
+      // If extension is found, we will append dot before it.
+      if (fullFileName.length == 2) {
+        extension = "." + fullFileName[1];
+      }
+
+      // Return full resource name in format: drawable/image.png
+      return typeName + "/" + entryName + extension;
+    } catch (Exception e) {
+      Log.w("Failed to generate resource name from provided resource id: ", e);
+      Util.handleException(e);
+    }
+    return null;
+  }
+
+  /**
+   * Generates resource Id based on Resource name.
+   *
+   * @param resourceName name of the resource including folder and file extension.
+   * @return id of the resource if found, 0 otherwise.
+   */
+  public static int generateIdFromResourceName(String resourceName) {
+    // Split resource name to extract folder and file name.
+    String[] parts = resourceName.split("/");
+    if (parts.length == 2) {
+      Resources resources = Leanplum.getContext().getResources();
+      // Type name represents folder where file is contained.
+      String typeName = parts[0];
+      String fileName = parts[1];
+      String entryName = fileName;
+      // Since fileName contains extension we have to remove it,
+      // to be able to get resource id.
+      String[] fileParts = fileName.split("\\.(?=[^\\.]+$)");
+      if (fileParts.length == 2) {
+        entryName = fileParts[0];
+      }
+      // Get identifier for a file in specified directory
+      if (!TextUtils.isEmpty(typeName) && !TextUtils.isEmpty(entryName)) {
+        return resources.getIdentifier(entryName, typeName, Leanplum.getContext().getPackageName());
+      }
+    }
+    Log.w("Could not extract resource id from provided resource name: ", resourceName);
+    return 0;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/VarCache.java
@@ -0,0 +1,899 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.leanplum.ActionContext;
+import com.leanplum.CacheUpdateBlock;
+import com.leanplum.Leanplum;
+import com.leanplum.LocationManager;
+import com.leanplum.Var;
+import com.leanplum.internal.FileManager.HashResults;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.InputStream;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Variable cache.
+ *
+ * @author Andrew First.
+ */
+public class VarCache {
+  private static final Map<String, Var<?>> vars = new ConcurrentHashMap<>();
+  private static final Map<String, Object> fileAttributes = new HashMap<>();
+  private static final Map<String, InputStream> fileStreams = new HashMap<>();
+
+  /**
+   * The default values set by the client. This is not thread-safe so traversals should be
+   * synchronized.
+   */
+  public static final Map<String, Object> valuesFromClient = new HashMap<>();
+
+  private static final Map<String, String> defaultKinds = new HashMap<>();
+  private static final Map<String, Object> actionDefinitions = new HashMap<>();
+  private static final String LEANPLUM = "__leanplum__";
+  private static Map<String, Object> diffs = new HashMap<>();
+  private static Map<String, Object> regions = new HashMap<>();
+  private static Map<String, Object> messageDiffs = new HashMap<>();
+  private static List<Map<String, Object>> updateRuleDiffs;
+  private static List<Map<String, Object>> eventRuleDiffs;
+  private static Map<String, Object> devModeValuesFromServer;
+  private static Map<String, Object> devModeFileAttributesFromServer;
+  private static Map<String, Object> devModeActionDefinitionsFromServer;
+  private static List<Map<String, Object>> variants = new ArrayList<>();
+  private static CacheUpdateBlock updateBlock;
+  private static CacheUpdateBlock interfaceUpdateBlock;
+  private static CacheUpdateBlock eventsUpdateBlock;
+  private static boolean hasReceivedDiffs = false;
+  private static Map<String, Object> messages = new HashMap<>();
+  private static Object merged;
+  private static boolean silent;
+  private static int contentVersion;
+  private static Map<String, Object> userAttributes;
+
+  private static final String NAME_COMPONENT_REGEX = "(?:[^\\.\\[.(\\\\]+|\\\\.)+";
+  private static final Pattern NAME_COMPONENT_PATTERN = Pattern.compile(NAME_COMPONENT_REGEX);
+
+  public static String[] getNameComponents(String name) {
+    Matcher matcher = NAME_COMPONENT_PATTERN.matcher(name);
+    List<String> components = new ArrayList<>();
+    while (matcher.find()) {
+      components.add(name.substring(matcher.start(), matcher.end()));
+    }
+    return components.toArray(new String[0]);
+  }
+
+  private static Object traverse(Object collection, Object key, boolean autoInsert) {
+    if (collection == null) {
+      return null;
+    }
+    if (collection instanceof Map) {
+      Map<Object, Object> castedCollection = CollectionUtil.uncheckedCast(collection);
+      Object result = castedCollection.get(key);
+      if (autoInsert && result == null && key instanceof String) {
+        result = new HashMap<String, Object>();
+        castedCollection.put(key, result);
+      }
+      return result;
+    } else if (collection instanceof List) {
+      List<Object> castedList = CollectionUtil.uncheckedCast(collection);
+      Object result = castedList.get((Integer) key);
+      if (autoInsert && result == null) {
+        result = new HashMap<String, Object>();
+        castedList.set((Integer) key, result);
+      }
+      return result;
+    }
+    return null;
+  }
+
+  public static boolean registerFile(
+      String stringValue, String defaultValue,
+      InputStream defaultStream, boolean isResource, String resourceHash, int resourceSize) {
+    if (Constants.isDevelopmentModeEnabled) {
+      if (!Constants.isNoop()) {
+        if (defaultStream == null) {
+          return false;
+        }
+        Map<String, Object> variationAttributes = new HashMap<>();
+        Map<String, Object> attributes = new HashMap<>();
+        if (isResource) {
+          attributes.put(Constants.Keys.HASH, resourceHash);
+          attributes.put(Constants.Keys.SIZE, resourceSize);
+        } else {
+          if (Constants.hashFilesToDetermineModifications && Util.isSimulator()) {
+            HashResults result = FileManager.fileMD5HashCreateWithPath(defaultStream);
+            if (result != null) {
+              attributes.put(Constants.Keys.HASH, result.hash);
+              attributes.put(Constants.Keys.SIZE, result.size);
+            }
+          } else {
+            int size = FileManager.getFileSize(
+                FileManager.fileValue(stringValue, defaultValue, null));
+            attributes.put(Constants.Keys.SIZE, size);
+          }
+        }
+        variationAttributes.put("", attributes);
+        fileAttributes.put(stringValue, variationAttributes);
+        fileStreams.put(stringValue, defaultStream);
+        maybeUploadNewFiles();
+      }
+      return true;
+    }
+    return false;
+  }
+
+  private static void updateValues(String name, String[] nameComponents, Object value, String kind,
+      Map<String, Object> values, Map<String, String> kinds) {
+    Object valuesPtr = values;
+    if (nameComponents != null && nameComponents.length > 0) {
+      for (int i = 0; i < nameComponents.length - 1; i++) {
+        valuesPtr = traverse(valuesPtr, nameComponents[i], true);
+      }
+      if (valuesPtr instanceof Map) {
+        Map<String, Object> map = CollectionUtil.uncheckedCast(valuesPtr);
+        map.put(nameComponents[nameComponents.length - 1], value);
+      }
+    }
+    if (kinds != null) {
+      kinds.put(name, kind);
+    }
+  }
+
+  public static void registerVariable(Var<?> var) {
+    vars.put(var.name(), var);
+    synchronized (valuesFromClient) {
+      updateValues(
+          var.name(), var.nameComponents(), var.defaultValue(),
+          var.kind(), valuesFromClient, defaultKinds);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> Var<T> getVariable(String name) {
+    return (Var<T>) vars.get(name);
+  }
+
+  private static void computeMergedDictionary() {
+    synchronized (valuesFromClient) {
+      merged = mergeHelper(valuesFromClient, diffs);
+    }
+  }
+
+  public static Object mergeHelper(Object vars, Object diff) {
+    if (diff == null) {
+      return vars;
+    }
+    if (diff instanceof Number
+        || diff instanceof Boolean
+        || diff instanceof String
+        || diff instanceof Character
+        || vars instanceof Number
+        || vars instanceof Boolean
+        || vars instanceof String
+        || vars instanceof Character) {
+      return diff;
+    }
+
+    Iterable<?> diffKeys = (diff instanceof Map) ? ((Map<?, ?>) diff).keySet() : (Iterable<?>) diff;
+    Iterable<?> varsKeys = (vars instanceof Map) ? ((Map<?, ?>) vars).keySet() : (Iterable<?>) vars;
+    Map<?, ?> diffMap = (diff instanceof Map) ? ((Map<?, ?>) diff) : null;
+    Map<?, ?> varsMap = (vars instanceof Map) ? ((Map<?, ?>) vars) : null;
+
+    // Infer that the diffs is an array if the vars value doesn't exist to tell us the type.
+    boolean isArray = false;
+    if (vars == null) {
+      if (diff instanceof Map && ((Map<?, ?>) diff).size() > 0) {
+        isArray = true;
+        for (Object var : diffKeys) {
+          if (!(var instanceof String)) {
+            isArray = false;
+            break;
+          }
+          String str = ((String) var);
+          if (str.length() < 3 || str.charAt(0) != '[' || str.charAt(str.length() - 1) != ']') {
+            isArray = false;
+            break;
+          }
+          String varSubscript = str.substring(1, str.length() - 1);
+          if (!("" + Integer.getInteger(varSubscript)).equals(varSubscript)) {
+            isArray = false;
+            break;
+          }
+        }
+      }
+    }
+
+    // Merge arrays.
+    if (vars instanceof List || isArray) {
+      ArrayList<Object> merged = new ArrayList<>();
+      for (Object var : varsKeys) {
+        merged.add(var);
+      }
+      for (Object varSubscript : diffKeys) {
+        String strSubscript = (String) varSubscript;
+        int subscript = Integer.parseInt(strSubscript.substring(1, strSubscript.length() - 1));
+        Object var = diffMap != null ? diffMap.get(strSubscript) : null;
+        while (subscript >= merged.size()) {
+          merged.add(null);
+        }
+        merged.set(subscript, mergeHelper(merged.get(subscript), var));
+      }
+      return merged;
+    }
+
+    // Merge dictionaries.
+    if (vars instanceof Map || diff instanceof Map) {
+      HashMap<Object, Object> merged = new HashMap<>();
+      if (varsKeys != null) {
+        for (Object var : varsKeys) {
+          if (diffMap != null && varsMap != null) {
+            Object diffVar = diffMap.get(var);
+            Object value = varsMap.get(var);
+            if (diffVar == null && value != null) {
+              merged.put(var, value);
+            }
+          }
+        }
+      }
+      for (Object var : diffKeys) {
+        Object diffsValue = diffMap != null ? diffMap.get(var) : null;
+        Object varsValue = varsMap != null ? varsMap.get(var) : null;
+        Object mergedValues = mergeHelper(varsValue, diffsValue);
+        merged.put(var, mergedValues);
+      }
+      return merged;
+    }
+    return null;
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> T getMergedValueFromComponentArray(Object[] components, Object values) {
+    Object mergedPtr = values;
+    for (Object component : components) {
+      mergedPtr = traverse(mergedPtr, component, false);
+    }
+    return (T) mergedPtr;
+  }
+
+  public static <T> T getMergedValueFromComponentArray(Object[] components) {
+    return getMergedValueFromComponentArray(components,
+        merged != null ? merged : valuesFromClient);
+  }
+
+  public static Map<String, Object> getDiffs() {
+    return diffs;
+  }
+
+  public static Map<String, Object> getMessageDiffs() {
+    return messageDiffs;
+  }
+
+  public static List<Map<String, Object>> getUpdateRuleDiffs() {
+    return updateRuleDiffs;
+  }
+
+  public static List<Map<String, Object>> getEventRuleDiffs() {
+    return eventRuleDiffs;
+  }
+
+  public static Map<String, Object> regions() {
+    return regions;
+  }
+
+  public static boolean hasReceivedDiffs() {
+    return hasReceivedDiffs;
+  }
+
+  public static void loadDiffs() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(LEANPLUM, Context.MODE_PRIVATE);
+    if (Request.token() == null) {
+      applyVariableDiffs(
+          new HashMap<String, Object>(),
+          new HashMap<String, Object>(),
+          new ArrayList<Map<String, Object>>(),
+          new ArrayList<Map<String, Object>>(),
+          new HashMap<String, Object>(),
+          new ArrayList<Map<String, Object>>());
+      return;
+    }
+    try {
+      // Crypt functions return input text if there was a problem.
+      AESCrypt aesContext = new AESCrypt(Request.appId(), Request.token());
+      String variables = aesContext.decodePreference(
+          defaults, Constants.Defaults.VARIABLES_KEY, "{}");
+      String messages = aesContext.decodePreference(
+          defaults, Constants.Defaults.MESSAGES_KEY, "{}");
+      String updateRules = aesContext.decodePreference(
+          defaults, Constants.Defaults.UPDATE_RULES_KEY, "[]");
+      String eventRules = aesContext.decodePreference(
+          defaults, Constants.Defaults.EVENT_RULES_KEY, "[]");
+      String regions = aesContext.decodePreference(defaults, Constants.Defaults.REGIONS_KEY, "{}");
+      String variants = aesContext.decodePreference(defaults, Constants.Keys.VARIANTS, "[]");
+      applyVariableDiffs(
+          JsonConverter.fromJson(variables),
+          JsonConverter.fromJson(messages),
+          JsonConverter.<Map<String, Object>>listFromJson(new JSONArray(updateRules)),
+          JsonConverter.<Map<String, Object>>listFromJson(new JSONArray(eventRules)),
+          JsonConverter.fromJson(regions),
+          JsonConverter.<Map<String, Object>>listFromJson(new JSONArray(variants)));
+      String deviceId = aesContext.decodePreference(defaults, Constants.Params.DEVICE_ID, null);
+      if (deviceId != null) {
+        if (Util.isValidDeviceId(deviceId)) {
+          Request.setDeviceId(deviceId);
+        } else {
+          Log.w("Invalid stored device id found: \"" + deviceId + "\"; discarding.");
+        }
+      }
+      String userId = aesContext.decodePreference(defaults, Constants.Params.USER_ID, null);
+      if (userId != null) {
+        if (Util.isValidUserId(userId)) {
+          Request.setUserId(userId);
+        } else {
+          Log.w("Invalid stored user id found: \"" + userId + "\"; discarding.");
+        }
+      }
+      String loggingEnabled = aesContext.decodePreference(defaults, Constants.Keys.LOGGING_ENABLED,
+          "false");
+      if (Boolean.parseBoolean(loggingEnabled)) {
+        Constants.loggingEnabled = true;
+      }
+    } catch (Exception e) {
+      Log.e("Could not load variable diffs.\n" + Log.getStackTraceString(e));
+    }
+    userAttributes();
+  }
+
+  public static void saveDiffs() {
+    if (Constants.isNoop()) {
+      return;
+    }
+    if (Request.token() == null) {
+      return;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(LEANPLUM, Context.MODE_PRIVATE);
+    SharedPreferences.Editor editor = defaults.edit();
+
+    // Crypt functions return input text if there was a problem.
+    AESCrypt aesContext = new AESCrypt(Request.appId(), Request.token());
+    String variablesCipher = aesContext.encrypt(JsonConverter.toJson(diffs));
+    editor.putString(Constants.Defaults.VARIABLES_KEY, variablesCipher);
+
+    String messagesCipher = aesContext.encrypt(JsonConverter.toJson(messages));
+    editor.putString(Constants.Defaults.MESSAGES_KEY, messagesCipher);
+
+    try {
+      String updateRulesCipher = aesContext.encrypt(
+          JsonConverter.listToJsonArray(updateRuleDiffs).toString());
+      editor.putString(Constants.Defaults.UPDATE_RULES_KEY, updateRulesCipher);
+    } catch (JSONException e) {
+      Log.e("Error converting updateRuleDiffs to JSON", e);
+    }
+
+    try {
+      String eventRulesCipher = aesContext.encrypt(
+          JsonConverter.listToJsonArray(eventRuleDiffs).toString());
+      editor.putString(Constants.Defaults.EVENT_RULES_KEY, eventRulesCipher);
+    } catch (JSONException e) {
+      Log.e("Error converting eventRuleDiffs to JSON", e);
+    }
+
+    String regionsCipher = aesContext.encrypt(JsonConverter.toJson(regions));
+    editor.putString(Constants.Defaults.REGIONS_KEY, regionsCipher);
+
+    try {
+      String variantsJson = JsonConverter.listToJsonArray(variants).toString();
+      editor.putString(Constants.Keys.VARIANTS, aesContext.encrypt(variantsJson));
+    } catch (JSONException e1) {
+      Log.e("Error converting " + variants + " to JSON.\n" + Log.getStackTraceString(e1));
+    }
+    editor.putString(Constants.Params.DEVICE_ID, aesContext.encrypt(Request.deviceId()));
+    editor.putString(Constants.Params.USER_ID, aesContext.encrypt(Request.userId()));
+    editor.putString(Constants.Keys.LOGGING_ENABLED,
+        aesContext.encrypt(String.valueOf(Constants.loggingEnabled)));
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  /**
+   * Convert a resId to a resPath.
+   */
+  static int getResIdFromPath(String resPath) {
+    int resId = 0;
+    try {
+      String path = resPath.replace("res/", "");
+      path = path.substring(0, path.lastIndexOf('.'));  // remove file extension
+      String name = path.substring(path.lastIndexOf('/') + 1);
+      String type = path.substring(0, path.lastIndexOf('/'));
+      type = type.replace('/', '.');
+      Context context = Leanplum.getContext();
+      resId = context.getResources().getIdentifier(name, type, context.getPackageName());
+    } catch (Exception e) {
+      // Fall back to 0 on any exception
+    }
+    return resId;
+  }
+
+  /**
+   * Update file variables stream info with override info, so that override files don't require
+   * downloads if they're already available.
+   */
+  private static void fileVariableFinish() {
+    for (String name : new HashMap<>(vars).keySet()) {
+      Var<?> var = vars.get(name);
+      String overrideFile = var.stringValue;
+      if (var.isResource && (var.kind().equals(Constants.Kinds.FILE)) && overrideFile != null &&
+          !var.defaultValue().equals(overrideFile)) {
+        Map<String, Object> variationAttributes = CollectionUtil.uncheckedCast(fileAttributes.get
+            (overrideFile));
+        InputStream stream = fileStreams.get(overrideFile);
+        if (variationAttributes != null && stream != null) {
+          var.setOverrideResId(getResIdFromPath(var.stringValue()));
+        }
+      }
+    }
+  }
+
+  public static void applyVariableDiffs(
+      Map<String, Object> diffs,
+      Map<String, Object> messages,
+      List<Map<String, Object>> updateRules,
+      List<Map<String, Object>> eventRules,
+      Map<String, Object> regions,
+      List<Map<String, Object>> variants) {
+    if (diffs != null) {
+      VarCache.diffs = diffs;
+      computeMergedDictionary();
+
+      // Update variables with new values.
+      // Have to copy the dictionary because a dictionary variable may add a new sub-variable,
+      // modifying the variable dictionary.
+      for (String name : new HashMap<>(vars).keySet()) {
+        vars.get(name).update();
+      }
+      fileVariableFinish();
+    }
+
+    if (messages != null) {
+      // Store messages.
+      messageDiffs = messages;
+      Map<String, Object> newMessages = new HashMap<>();
+      for (Map.Entry<String, Object> entry : messages.entrySet()) {
+        Map<String, Object> messageConfig = CollectionUtil.uncheckedCast(entry.getValue());
+        Map<String, Object> newConfig = new HashMap<>(messageConfig);
+        Map<String, Object> actionArgs = CollectionUtil.uncheckedCast(messageConfig.get(Constants
+            .Keys.VARS));
+        Map<String, Object> defaultArgs = Util.multiIndex(actionDefinitions,
+            newConfig.get(Constants.Params.ACTION), "values");
+        Map<String, Object> vars = CollectionUtil.uncheckedCast(mergeHelper(defaultArgs,
+            actionArgs));
+        newMessages.put(entry.getKey(), newConfig);
+        newConfig.put(Constants.Keys.VARS, vars);
+      }
+
+      VarCache.messages = newMessages;
+      for (Map.Entry<String, Object> entry : VarCache.messages.entrySet()) {
+        String name = entry.getKey();
+        Map<String, Object> messageConfig = CollectionUtil.uncheckedCast(VarCache.messages.get
+            (name));
+        if (messageConfig.get("action") != null) {
+          Map<String, Object> actionArgs =
+              CollectionUtil.uncheckedCast(messageConfig.get(Constants.Keys.VARS));
+          new ActionContext(
+              messageConfig.get("action").toString(), actionArgs, name).update();
+        }
+      }
+    }
+
+    if (regions != null) {
+      VarCache.regions = regions;
+    }
+
+    if (messages != null || regions != null) {
+      Set<String> foregroundRegionNames = new HashSet<>();
+      Set<String> backgroundRegionNames = new HashSet<>();
+      ActionManager.getForegroundandBackgroundRegionNames(foregroundRegionNames,
+          backgroundRegionNames);
+      LocationManager locationManager = ActionManager.getLocationManager();
+      if (locationManager != null) {
+        locationManager.setRegionsData(regions, foregroundRegionNames, backgroundRegionNames);
+      }
+    }
+
+    boolean interfaceUpdated = false;
+    if (updateRules != null) {
+      interfaceUpdated = !(updateRules.equals(updateRuleDiffs));
+      updateRuleDiffs = new ArrayList<>(updateRules);
+      VarCache.downloadUpdateRulesImages();
+    }
+
+    boolean eventsUpdated = false;
+    if (eventRules != null) {
+      eventsUpdated = !(eventRules.equals(eventRuleDiffs));
+      eventRuleDiffs = new ArrayList<>(eventRules);
+    }
+
+    if (variants != null) {
+      VarCache.variants = variants;
+    }
+
+    contentVersion++;
+
+    if (!silent) {
+      saveDiffs();
+      triggerHasReceivedDiffs();
+
+      if (interfaceUpdated && interfaceUpdateBlock != null) {
+        interfaceUpdateBlock.updateCache();
+      }
+
+      if (eventsUpdated && eventsUpdateBlock != null) {
+        eventsUpdateBlock.updateCache();
+      }
+    }
+  }
+
+  static void applyUpdateRuleDiffs(List<Map<String, Object>> updateRuleDiffs) {
+    VarCache.updateRuleDiffs = updateRuleDiffs;
+    VarCache.downloadUpdateRulesImages();
+    if (interfaceUpdateBlock != null) {
+      interfaceUpdateBlock.updateCache();
+    }
+    VarCache.saveDiffs();
+  }
+
+  private static void downloadUpdateRulesImages() {
+    for (Map value : VarCache.updateRuleDiffs) {
+      List changes = (List) value.get("changes");
+      for (Object change : changes) {
+        Map<String, String> castedChange = CollectionUtil.uncheckedCast(change);
+        String key = castedChange.get("key");
+        if (key != null && key.contains("image")) {
+          String name = castedChange.get("value");
+          FileManager.maybeDownloadFile(true, name, null, null, null);
+        }
+      }
+    }
+  }
+
+  public static int contentVersion() {
+    return contentVersion;
+  }
+
+  @SuppressWarnings("SameParameterValue")
+  private static boolean areActionDefinitionsEqual(
+      Map<String, Object> a, Map<String, Object> b) {
+    if ((a == null || b == null) || (a.size() != b.size())) {
+      return false;
+    }
+    for (Map.Entry<String, Object> entry : a.entrySet()) {
+      Map<String, Object> aItem = CollectionUtil.uncheckedCast(entry.getValue());
+      Map<String, Object> bItem = CollectionUtil.uncheckedCast(b.get(entry.getKey()));
+      if (bItem == null || aItem == null) {
+        return false;
+      }
+
+      Object aKind = aItem.get("kind");
+      Object aValues = aItem.get("values");
+      Object aKinds = aItem.get("kinds");
+      Object aOptions = aItem.get("options");
+      if (aKind != null && !aKind.equals(bItem.get("kind")) ||
+          aValues != null && !aValues.equals(bItem.get("values")) ||
+          aKinds != null && !aKinds.equals(bItem.get("kinds")) ||
+          (aOptions == null) != (bItem.get("options") == null) ||
+          aOptions != null && aOptions.equals(bItem.get("options"))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  private static void triggerHasReceivedDiffs() {
+    hasReceivedDiffs = true;
+    if (updateBlock != null) {
+      updateBlock.updateCache();
+    }
+  }
+
+  static boolean sendVariablesIfChanged() {
+    return sendContentIfChanged(true, false);
+  }
+
+  static boolean sendActionsIfChanged() {
+    return sendContentIfChanged(false, true);
+  }
+
+  private static boolean sendContentIfChanged(boolean variables, boolean actions) {
+    boolean changed = false;
+    if (variables && devModeValuesFromServer != null
+        && !valuesFromClient.equals(devModeValuesFromServer)) {
+      changed = true;
+    }
+    if (actions && !areActionDefinitionsEqual(
+        actionDefinitions, devModeActionDefinitionsFromServer)) {
+      changed = true;
+    }
+
+    if (changed) {
+      HashMap<String, Object> params = new HashMap<>();
+      if (variables) {
+        params.put(Constants.Params.VARS, JsonConverter.toJson(valuesFromClient));
+        params.put(Constants.Params.KINDS, JsonConverter.toJson(defaultKinds));
+      }
+      if (actions) {
+        params.put(Constants.Params.ACTION_DEFINITIONS, JsonConverter.toJson(actionDefinitions));
+      }
+      params.put(Constants.Params.FILE_ATTRIBUTES, JsonConverter.toJson(fileAttributes));
+      Request.post(Constants.Methods.SET_VARS, params).sendIfConnected();
+    }
+
+    return changed;
+  }
+
+  static void maybeUploadNewFiles() {
+    // First check to make sure we have all the data we need
+    if (Constants.isNoop()
+        || devModeFileAttributesFromServer == null
+        || !Leanplum.hasStartedAndRegisteredAsDeveloper()
+        || !Constants.enableFileUploadingInDevelopmentMode) {
+      return;
+    }
+
+    List<String> filenames = new ArrayList<>();
+    List<JSONObject> fileData = new ArrayList<>();
+    List<InputStream> streams = new ArrayList<>();
+    int totalSize = 0;
+    for (Map.Entry<String, Object> entry : fileAttributes.entrySet()) {
+      String name = entry.getKey();
+      Map<String, Object> variationAttributes = CollectionUtil.uncheckedCast(entry.getValue());
+      Map<String, Object> serverVariationAttributes =
+          CollectionUtil.uncheckedCast(devModeFileAttributesFromServer.get(name));
+      Map<String, Object> localAttributes = CollectionUtil.uncheckedCast(variationAttributes.get
+          (""));
+      Map<String, Object> serverAttributes = CollectionUtil.uncheckedCast(
+          (serverVariationAttributes != null ? serverVariationAttributes.get("") : null));
+      if (FileManager.isNewerLocally(localAttributes, serverAttributes)) {
+        Log.v("Will upload file " + name + ". Local attributes: " +
+            localAttributes + "; server attributes: " + serverAttributes);
+
+        String hash = (String) localAttributes.get(Constants.Keys.HASH);
+        if (hash == null) {
+          hash = "";
+        }
+
+        String variationPath = FileManager.fileRelativeToAppBundle(name);
+
+        // Upload in batch if we can't put any more files in
+        if ((totalSize > Constants.Files.MAX_UPLOAD_BATCH_SIZES && filenames.size() > 0)
+            || filenames.size() >= Constants.Files.MAX_UPLOAD_BATCH_FILES) {
+          Map<String, Object> params = new HashMap<>();
+          params.put(Constants.Params.DATA, fileData.toString());
+
+          Request.post(Constants.Methods.UPLOAD_FILE, params).sendFilesNow(filenames,
+              streams);
+
+          filenames = new ArrayList<>();
+          fileData = new ArrayList<>();
+          streams = new ArrayList<>();
+          totalSize = 0;
+        }
+
+        // Add the current file to the lists and update size
+        Object size = localAttributes.get(Constants.Keys.SIZE);
+        totalSize += (Integer) size;
+        filenames.add(variationPath);
+        JSONObject fileDatum = new JSONObject();
+        try {
+          fileDatum.put(Constants.Keys.HASH, hash);
+          fileDatum.put(Constants.Keys.SIZE, localAttributes.get(Constants.Keys.SIZE) + "");
+          fileDatum.put(Constants.Keys.FILENAME, name);
+          fileData.add(fileDatum);
+        } catch (JSONException e) {
+          // HASH, SIZE, or FILENAME are null, which they never should be (they're constants).
+          Log.e("Unable to upload files.\n" + Log.getStackTraceString(e));
+          fileData.add(new JSONObject());
+        }
+        streams.add(fileStreams.get(name));
+      }
+    }
+
+    if (filenames.size() > 0) {
+      Map<String, Object> params = new HashMap<>();
+      params.put(Constants.Params.DATA, fileData.toString());
+      Request.post(Constants.Methods.UPLOAD_FILE, params).sendFilesNow(filenames, streams);
+    }
+  }
+
+  /**
+   * Sets whether values should be saved and callbacks triggered when the variable values get
+   * updated.
+   */
+  public static void setSilent(boolean silent) {
+    VarCache.silent = silent;
+  }
+
+  public static boolean silent() {
+    return silent;
+  }
+
+  public static void setDevModeValuesFromServer(Map<String, Object> values,
+      Map<String, Object> fileAttributes, Map<String, Object> actionDefinitions) {
+    devModeValuesFromServer = values;
+    devModeActionDefinitionsFromServer = actionDefinitions;
+    devModeFileAttributesFromServer = fileAttributes;
+  }
+
+  public static void onUpdate(CacheUpdateBlock block) {
+    updateBlock = block;
+  }
+
+  public static void onInterfaceUpdate(CacheUpdateBlock block) {
+    interfaceUpdateBlock = block;
+  }
+
+  public static void onEventsUpdate(CacheUpdateBlock block) {
+    eventsUpdateBlock = block;
+  }
+
+  public static List<Map<String, Object>> variants() {
+    return variants;
+  }
+
+  public static Map<String, Object> actionDefinitions() {
+    return actionDefinitions;
+  }
+
+  public static Map<String, Object> messages() {
+    return messages;
+  }
+
+  public static void registerActionDefinition(
+      String name, int kind, List<ActionArg<?>> args,
+      Map<String, Object> options) {
+    Map<String, Object> values = new HashMap<>();
+    Map<String, String> kinds = new HashMap<>();
+    List<String> order = new ArrayList<>();
+    for (ActionArg<?> arg : args) {
+      updateValues(arg.name(), getNameComponents(arg.name()),
+          arg.defaultValue(), arg.kind(), values, kinds);
+      order.add(arg.name());
+    }
+    Map<String, Object> definition = new HashMap<>();
+    definition.put("kind", kind);
+    definition.put("values", values);
+    definition.put("kinds", kinds);
+    definition.put("order", order);
+    definition.put("options", options);
+    actionDefinitions.put(name, definition);
+  }
+
+  public static <T> String kindFromValue(T defaultValue) {
+    String kind = null;
+    if (defaultValue instanceof Integer
+        || defaultValue instanceof Long
+        || defaultValue instanceof Short
+        || defaultValue instanceof Character
+        || defaultValue instanceof Byte
+        || defaultValue instanceof BigInteger) {
+      kind = Constants.Kinds.INT;
+    } else if (defaultValue instanceof Float
+        || defaultValue instanceof Double
+        || defaultValue instanceof BigDecimal) {
+      kind = Constants.Kinds.FLOAT;
+    } else if (defaultValue instanceof String) {
+      kind = Constants.Kinds.STRING;
+    } else if (defaultValue instanceof List
+        || defaultValue instanceof Array) {
+      kind = Constants.Kinds.ARRAY;
+    } else if (defaultValue instanceof Map) {
+      kind = Constants.Kinds.DICTIONARY;
+    } else if (defaultValue instanceof Boolean) {
+      kind = Constants.Kinds.BOOLEAN;
+    }
+    return kind;
+  }
+
+  static Map<String, Object> userAttributes() {
+    if (userAttributes == null) {
+      Context context = Leanplum.getContext();
+      SharedPreferences defaults = context.getSharedPreferences(LEANPLUM, Context.MODE_PRIVATE);
+      AESCrypt aesContext = new AESCrypt(Request.appId(), Request.token());
+      try {
+        userAttributes = JsonConverter.fromJson(
+            aesContext.decodePreference(defaults, Constants.Defaults.ATTRIBUTES_KEY, "{}"));
+      } catch (Exception e) {
+        Log.e("Could not load user attributes.\n" + Log.getStackTraceString(e));
+        userAttributes = new HashMap<>();
+      }
+    }
+    return userAttributes;
+  }
+
+  public static void saveUserAttributes() {
+    if (Constants.isNoop() || Request.appId() == null || userAttributes == null) {
+      return;
+    }
+    Context context = Leanplum.getContext();
+    SharedPreferences defaults = context.getSharedPreferences(LEANPLUM, Context.MODE_PRIVATE);
+    SharedPreferences.Editor editor = defaults.edit();
+    // Crypt functions return input text if there was a problem.
+    String plaintext = JsonConverter.toJson(userAttributes);
+    AESCrypt aesContext = new AESCrypt(Request.appId(), Request.token());
+    editor.putString(Constants.Defaults.ATTRIBUTES_KEY, aesContext.encrypt(plaintext));
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+
+  /**
+   * Resets the VarCache to stock state.
+   */
+  public static void reset() {
+    vars.clear();
+    fileAttributes.clear();
+    fileStreams.clear();
+    valuesFromClient.clear();
+    defaultKinds.clear();
+    actionDefinitions.clear();
+    diffs.clear();
+    messageDiffs.clear();
+    regions.clear();
+    devModeValuesFromServer = null;
+    devModeFileAttributesFromServer = null;
+    devModeActionDefinitionsFromServer = null;
+    variants.clear();
+    updateBlock = null;
+    hasReceivedDiffs = false;
+    messages = null;
+    merged = null;
+    silent = false;
+    contentVersion = 0;
+    userAttributes = null;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/internal/WebSocketClient.java
@@ -0,0 +1,289 @@
+// Copyright (c) 2009-2012 James Coglan
+// Copyright (c) 2012 Eric Butler 
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the 'Software'), to deal in
+// the Software without restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished to do so,
+// subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Source: https://github.com/codebutler/android-websockets/blob/master/src/main/java/com/codebutler/android_websockets/WebSocketClient.java
+
+package com.leanplum.internal;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.text.TextUtils;
+import android.util.Base64;
+
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.StatusLine;
+import org.apache.http.client.HttpResponseException;
+import org.apache.http.message.BasicLineParser;
+import org.apache.http.message.BasicNameValuePair;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+class WebSocketClient {
+  private static final String TAG = "WebSocketClient";
+
+  private URI mURI;
+  private Listener mListener;
+  private java.net.Socket mSocket;
+  private Thread mThread;
+  private HandlerThread mHandlerThread;
+  private Handler mHandler;
+  private List<BasicNameValuePair> mExtraHeaders;
+  private HybiParser mParser;
+
+  private final Object mSendLock = new Object();
+
+  private static TrustManager[] sTrustManagers;
+
+  public static void setTrustManagers(TrustManager[] tm) {
+    sTrustManagers = tm;
+  }
+
+  public WebSocketClient(URI uri, Listener listener, List<BasicNameValuePair> extraHeaders) {
+    mURI = uri;
+    mListener = listener;
+    mExtraHeaders = extraHeaders;
+    mParser = new HybiParser(this);
+
+    mHandlerThread = new HandlerThread("websocket-thread");
+    mHandlerThread.start();
+    mHandler = new Handler(mHandlerThread.getLooper());
+  }
+
+  public Listener getListener() {
+    return mListener;
+  }
+
+  public void connect() {
+    if (mThread != null && mThread.isAlive()) {
+      return;
+    }
+
+    mThread = new Thread(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          int port = (mURI.getPort() != -1) ? mURI.getPort() : (mURI.getScheme().equals("wss") ? 443 : 80);
+
+          String path = TextUtils.isEmpty(mURI.getPath()) ? "/" : mURI.getPath();
+          if (!TextUtils.isEmpty(mURI.getQuery())) {
+            path += "?" + mURI.getQuery();
+          }
+
+          String originScheme = mURI.getScheme().equals("wss") ? "https" : "http";
+          URI origin = null;
+          try {
+            origin = new URI(originScheme, "//" + mURI.getHost(), null);
+          } catch (URISyntaxException e) {
+            Util.handleException(e);
+          }
+
+          SocketFactory factory;
+          try {
+            factory = mURI.getScheme().equals("wss") ? getSSLSocketFactory() : SocketFactory.getDefault();
+          } catch (GeneralSecurityException e) {
+            Util.handleException(e);
+            return;
+          }
+          try {
+            mSocket = factory.createSocket(mURI.getHost(), port);
+          } catch (IOException e) {
+            Util.handleException(e);
+          }
+
+          PrintWriter out = new PrintWriter(mSocket.getOutputStream());
+          out.print("GET " + path + " HTTP/1.1\r\n");
+          out.print("Upgrade: websocket\r\n");
+          out.print("Connection: Upgrade\r\n");
+          out.print("Host: " + mURI.getHost() + "\r\n");
+          out.print("Origin: " + (origin != null ? origin.toString() : "unknown") + "\r\n");
+          out.print("Sec-WebSocket-Key: " + createSecret() + "\r\n");
+          out.print("Sec-WebSocket-Version: 13\r\n");
+          if (mExtraHeaders != null) {
+            for (NameValuePair pair : mExtraHeaders) {
+              out.print(String.format("%s: %s\r\n", pair.getName(), pair.getValue()));
+            }
+          }
+          out.print("\r\n");
+          out.flush();
+
+          HybiParser.HappyDataInputStream stream = new HybiParser.HappyDataInputStream(mSocket.getInputStream());
+
+          // Read HTTP response status line.
+
+          StatusLine statusLine = parseStatusLine(readLine(stream));
+
+          if (statusLine == null) {
+            throw new HttpException("Received no reply from server.");
+          } else if (statusLine.getStatusCode() != HttpStatus.SC_SWITCHING_PROTOCOLS) {
+            throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
+          }
+
+          // Read HTTP response headers.
+          String line;
+          while (!TextUtils.isEmpty(line = readLine(stream))) {
+            Header header = parseHeader(line);
+            if (header.getName().equals("Sec-WebSocket-Accept")) {
+              // FIXME: Verify the response...
+            }
+          }
+
+          mListener.onConnect();
+
+          // Now decode websocket frames.
+          mParser.start(stream);
+
+        } catch (EOFException ex) {
+          Log.d("WebSocket EOF!", ex);
+          mListener.onDisconnect(0, "EOF");
+
+        } catch (SSLException ex) {
+          // Connection reset by peer
+          Log.d("Websocket SSL error!", ex);
+          mListener.onDisconnect(0, "SSL");
+
+        } catch (Exception e) {
+          mListener.onError(e);
+        }
+      }
+    });
+    mThread.start();
+  }
+
+  public void disconnect() {
+    if (mSocket != null) {
+      mHandler.post(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            if (mSocket != null) {
+              mSocket.close();
+              mSocket = null;
+            }
+          } catch (IOException e) {
+            Log.d("Error while disconnecting", e);
+            mListener.onError(e);
+          }
+        }
+      });
+    }
+  }
+
+  public void send(String data) {
+    sendFrame(mParser.frame(data));
+  }
+
+  public void send(byte[] data) {
+    sendFrame(mParser.frame(data));
+  }
+
+  private StatusLine parseStatusLine(String line) {
+    if (TextUtils.isEmpty(line)) {
+      return null;
+    }
+    return BasicLineParser.parseStatusLine(line, new BasicLineParser());
+  }
+
+  private Header parseHeader(String line) {
+    return BasicLineParser.parseHeader(line, new BasicLineParser());
+  }
+
+  // Can't use BufferedReader because it buffers past the HTTP data.
+  private String readLine(HybiParser.HappyDataInputStream reader) throws IOException {
+    int readChar = reader.read();
+    if (readChar == -1) {
+      return null;
+    }
+    StringBuilder string = new StringBuilder("");
+    while (readChar != '\n') {
+      if (readChar != '\r') {
+        string.append((char) readChar);
+      }
+
+      readChar = reader.read();
+      if (readChar == -1) {
+        return null;
+      }
+    }
+    return string.toString();
+  }
+
+  private String createSecret() {
+    byte[] nonce = new byte[16];
+    for (int i = 0; i < 16; i++) {
+      nonce[i] = (byte) (Math.random() * 256);
+    }
+    return Base64.encodeToString(nonce, Base64.DEFAULT).trim();
+  }
+
+  void sendFrame(final byte[] frame) {
+    mHandler.post(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          synchronized (mSendLock) {
+            if (mSocket != null) {
+              OutputStream outputStream = mSocket.getOutputStream();
+              outputStream.write(frame);
+              outputStream.flush();
+            }
+          }
+        } catch (IOException e) {
+          mListener.onError(e);
+        }
+      }
+    });
+  }
+
+  interface Listener {
+    void onConnect();
+
+    void onMessage(String message);
+
+    void onMessage(byte[] data);
+
+    void onDisconnect(int code, String reason);
+
+    void onError(Exception error);
+  }
+
+  private SSLSocketFactory getSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException {
+    SSLContext context = SSLContext.getInstance("TLS");
+    context.init(null, sTrustManagers, null);
+    return context.getSocketFactory();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/Alert.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.PostponableAction;
+import com.leanplum.messagetemplates.MessageTemplates.Args;
+import com.leanplum.messagetemplates.MessageTemplates.Values;
+
+import static com.leanplum.messagetemplates.MessageTemplates.getApplicationName;
+
+/**
+ * Registers a Leanplum action that displays a system alert dialog.
+ *
+ * @author Andrew First
+ */
+public class Alert {
+  private static final String NAME = "Alert";
+
+  public static void register(Context currentContext) {
+    Leanplum.defineAction(
+        NAME,
+        Leanplum.ACTION_KIND_MESSAGE | Leanplum.ACTION_KIND_ACTION,
+        new ActionArgs().with(Args.TITLE, getApplicationName(currentContext))
+            .with(Args.MESSAGE, Values.ALERT_MESSAGE)
+            .with(Args.DISMISS_TEXT, Values.OK_TEXT)
+            .withAction(Args.DISMISS_ACTION, null), new ActionCallback() {
+
+          @Override
+          public boolean onResponse(final ActionContext context) {
+            LeanplumActivityHelper.queueActionUponActive(new PostponableAction() {
+              @Override
+              public void run() {
+                Activity activity = LeanplumActivityHelper.getCurrentActivity();
+                if (activity == null) {
+                  return;
+                }
+                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
+                    activity);
+                alertDialogBuilder
+                    .setTitle(context.stringNamed(Args.TITLE))
+                    .setMessage(context.stringNamed(Args.MESSAGE))
+                    .setCancelable(false)
+                    .setPositiveButton(context.stringNamed(Args.DISMISS_TEXT),
+                        new DialogInterface.OnClickListener() {
+                          public void onClick(DialogInterface dialog, int id) {
+                            context.runActionNamed(Args.DISMISS_ACTION);
+                          }
+                        });
+                AlertDialog alertDialog = alertDialogBuilder.create();
+                if (!activity.isFinishing()) {
+                  alertDialog.show();
+                }
+              }
+            });
+            return true;
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/BaseMessageDialog.java
@@ -0,0 +1,615 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Typeface;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RoundRectShape;
+import android.graphics.drawable.shapes.Shape;
+import android.os.Build;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.utils.BitmapUtil;
+import com.leanplum.utils.SizeUtil;
+import com.leanplum.views.BackgroundImageView;
+import com.leanplum.views.CloseButton;
+
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Map;
+
+/**
+ * Base dialog used to display the Center Popup, Interstitial, Web Interstitial, HTML template.
+ *
+ * @author Martin Yanakiev, Anna Orlova
+ */
+public class BaseMessageDialog extends Dialog {
+  protected RelativeLayout dialogView;
+  protected BaseMessageOptions options;
+  protected WebInterstitialOptions webOptions;
+  protected HTMLOptions htmlOptions;
+  protected Activity activity;
+  protected WebView webView;
+
+  private boolean isWeb = false;
+  private boolean isHtml = false;
+  private boolean isClosing = false;
+
+  protected BaseMessageDialog(Activity activity, boolean fullscreen, BaseMessageOptions options,
+      WebInterstitialOptions webOptions, HTMLOptions htmlOptions) {
+    super(activity, getTheme(activity));
+
+    SizeUtil.init(activity);
+    this.activity = activity;
+    this.options = options;
+    this.webOptions = webOptions;
+    this.htmlOptions = htmlOptions;
+    if (webOptions != null) {
+      isWeb = true;
+    }
+    if (htmlOptions != null) {
+      isHtml = true;
+    }
+    dialogView = new RelativeLayout(activity);
+    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    dialogView.setBackgroundColor(Color.TRANSPARENT);
+    dialogView.setLayoutParams(layoutParams);
+
+    RelativeLayout view = createContainerView(activity, fullscreen);
+    view.setId(108);
+    dialogView.addView(view, view.getLayoutParams());
+
+    if ((!isWeb || (webOptions != null && webOptions.hasDismissButton())) && !isHtml) {
+      CloseButton closeButton = createCloseButton(activity, fullscreen, view);
+      dialogView.addView(closeButton, closeButton.getLayoutParams());
+    }
+
+    setContentView(dialogView, dialogView.getLayoutParams());
+
+    dialogView.setAnimation(createFadeInAnimation());
+
+    if (!fullscreen) {
+      Window window = getWindow();
+      if (window == null) {
+        return;
+      }
+      if (!isHtml) {
+        window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        if (Build.VERSION.SDK_INT >= 14) {
+          window.setDimAmount(0.7f);
+        }
+      } else {
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
+            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+        if (htmlOptions != null &&
+            MessageTemplates.Args.HTML_ALIGN_BOTTOM.equals(htmlOptions.getHtmlAlign())) {
+          dialogView.setGravity(Gravity.BOTTOM);
+        }
+      }
+    }
+  }
+
+  @Override
+  public void onWindowFocusChanged(boolean hasFocus) {
+    try {
+      if (webView != null && Build.VERSION.SDK_INT >= 11) {
+        if (hasFocus) {
+          webView.onResume();
+        } else {
+          webView.onPause();
+        }
+      }
+    } catch (Throwable ignore) {
+    }
+    super.onWindowFocusChanged(hasFocus);
+  }
+
+  private Animation createFadeInAnimation() {
+    Animation fadeIn = new AlphaAnimation(0, 1);
+    fadeIn.setInterpolator(new DecelerateInterpolator());
+    fadeIn.setDuration(350);
+    return fadeIn;
+  }
+
+  private Animation createFadeOutAnimation() {
+    Animation fadeOut = new AlphaAnimation(1, 0);
+    fadeOut.setInterpolator(new AccelerateInterpolator());
+    fadeOut.setDuration(350);
+    return fadeOut;
+  }
+
+  @Override
+  public void cancel() {
+    if (isClosing) {
+      return;
+    }
+    isClosing = true;
+    Animation animation = createFadeOutAnimation();
+    animation.setAnimationListener(new Animation.AnimationListener() {
+      @Override
+      public void onAnimationStart(Animation animation) {
+      }
+
+      @Override
+      public void onAnimationRepeat(Animation animation) {
+      }
+
+      @Override
+      public void onAnimationEnd(Animation animation) {
+        BaseMessageDialog.super.cancel();
+        Handler handler = new Handler();
+        handler.postDelayed(new Runnable() {
+          @Override
+          public void run() {
+            if (isHtml && webView != null) {
+              webView.stopLoading();
+              webView.loadUrl("");
+              if (dialogView != null) {
+                dialogView.removeAllViews();
+              }
+              webView.removeAllViews();
+              webView.destroy();
+            }
+          }
+        }, 10);
+      }
+    });
+    dialogView.startAnimation(animation);
+  }
+
+  private CloseButton createCloseButton(Activity context, boolean fullscreen, View parent) {
+    CloseButton closeButton = new CloseButton(context);
+    closeButton.setId(103);
+    RelativeLayout.LayoutParams closeLayout = new RelativeLayout.LayoutParams(
+        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    if (fullscreen) {
+      closeLayout.addRule(RelativeLayout.ALIGN_PARENT_TOP, dialogView.getId());
+      closeLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, dialogView.getId());
+      closeLayout.setMargins(0, SizeUtil.dp5, SizeUtil.dp5, 0);
+    } else {
+      closeLayout.addRule(RelativeLayout.ALIGN_TOP, parent.getId());
+      closeLayout.addRule(RelativeLayout.ALIGN_RIGHT, parent.getId());
+      closeLayout.setMargins(0, -SizeUtil.dp7, -SizeUtil.dp7, 0);
+    }
+    closeButton.setLayoutParams(closeLayout);
+    closeButton.setOnClickListener(new View.OnClickListener() {
+      @Override
+      public void onClick(View arg0) {
+        cancel();
+      }
+    });
+    return closeButton;
+  }
+
+  @SuppressWarnings("deprecation")
+  private RelativeLayout createContainerView(Activity context, boolean fullscreen) {
+    RelativeLayout view = new RelativeLayout(context);
+
+    // Positions the dialog.
+    RelativeLayout.LayoutParams layoutParams;
+    if (fullscreen) {
+      layoutParams = new RelativeLayout.LayoutParams(
+          LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    } else if (isHtml) {
+      int height = SizeUtil.dpToPx(context, htmlOptions.getHtmlHeight());
+      layoutParams = new RelativeLayout.LayoutParams(
+          LayoutParams.MATCH_PARENT, height);
+    } else {
+
+      // Make sure the dialog fits on screen.
+      Display display = context.getWindowManager().getDefaultDisplay();
+      Point size = new Point();
+      if (Build.VERSION.SDK_INT >= 13) {
+        display.getSize(size);
+      } else {
+        size = new Point(display.getHeight(), display.getHeight());
+      }
+
+      int width = SizeUtil.dpToPx(context, ((CenterPopupOptions) options).getWidth());
+      int height = SizeUtil.dpToPx(context, ((CenterPopupOptions) options).getHeight());
+
+      int maxWidth = size.x - SizeUtil.dp20;
+      int maxHeight = size.y - SizeUtil.dp20;
+      double aspectRatio = width / (double) height;
+      if (width > maxWidth && (int) (width / aspectRatio) < maxHeight) {
+        width = maxWidth;
+        height = (int) (width / aspectRatio);
+      }
+      if (height > maxHeight && (int) (height * aspectRatio) < maxWidth) {
+        height = maxHeight;
+        width = (int) (height * aspectRatio);
+      }
+
+      layoutParams = new RelativeLayout.LayoutParams(width, height);
+      layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+    }
+
+    view.setLayoutParams(layoutParams);
+
+    ShapeDrawable footerBackground = new ShapeDrawable();
+    footerBackground.setShape(createRoundRect(fullscreen ? 0 : SizeUtil.dp20));
+    footerBackground.getPaint().setColor(0x00000000);
+    if (Build.VERSION.SDK_INT >= 16) {
+      view.setBackground(footerBackground);
+    } else {
+      view.setBackgroundDrawable(footerBackground);
+    }
+
+    if (!isWeb && !isHtml) {
+      ImageView image = createBackgroundImageView(context, fullscreen);
+      view.addView(image, image.getLayoutParams());
+
+      View title = createTitleView(context);
+      title.setId(104);
+      view.addView(title, title.getLayoutParams());
+
+      View button = createAcceptButton(context);
+      button.setId(105);
+      view.addView(button, button.getLayoutParams());
+
+      View message = createMessageView(context);
+      ((RelativeLayout.LayoutParams) message.getLayoutParams())
+          .addRule(RelativeLayout.BELOW, title.getId());
+      ((RelativeLayout.LayoutParams) message.getLayoutParams())
+          .addRule(RelativeLayout.ABOVE, button.getId());
+      view.addView(message, message.getLayoutParams());
+    } else if (isWeb) {
+      WebView webView = createWebView(context);
+      view.addView(webView, webView.getLayoutParams());
+    } else {
+      webView = createHtml(context);
+      view.addView(webView, webView.getLayoutParams());
+    }
+
+    return view;
+  }
+
+  private Shape createRoundRect(int cornerRadius) {
+    int c = cornerRadius;
+    float[] outerRadii = new float[] {c, c, c, c, c, c, c, c};
+    return new RoundRectShape(outerRadii, null, null);
+  }
+
+  @SuppressWarnings("deprecation")
+  private ImageView createBackgroundImageView(Context context, boolean fullscreen) {
+    BackgroundImageView view = new BackgroundImageView(context, fullscreen);
+    view.setScaleType(ImageView.ScaleType.CENTER_CROP);
+    int cornerRadius;
+    if (!fullscreen) {
+      cornerRadius = SizeUtil.dp20;
+    } else {
+      cornerRadius = 0;
+    }
+    view.setImageBitmap(options.getBackgroundImage());
+    ShapeDrawable footerBackground = new ShapeDrawable();
+    footerBackground.setShape(createRoundRect(cornerRadius));
+    footerBackground.getPaint().setColor(options.getBackgroundColor());
+    if (Build.VERSION.SDK_INT >= 16) {
+      view.setBackground(footerBackground);
+    } else {
+      view.setBackgroundDrawable(footerBackground);
+    }
+    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    view.setLayoutParams(layoutParams);
+    return view;
+  }
+
+  private RelativeLayout createTitleView(Context context) {
+    RelativeLayout view = new RelativeLayout(context);
+    view.setLayoutParams(new LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+
+    TextView title = new TextView(context);
+    title.setPadding(0, SizeUtil.dp5, 0, SizeUtil.dp5);
+    title.setGravity(Gravity.CENTER);
+    title.setText(options.getTitle());
+    title.setTextColor(options.getTitleColor());
+    title.setTextSize(TypedValue.COMPLEX_UNIT_SP, SizeUtil.textSize0);
+    title.setTypeface(null, Typeface.BOLD);
+    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
+    layoutParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
+    title.setLayoutParams(layoutParams);
+
+    view.addView(title, title.getLayoutParams());
+    return view;
+  }
+
+  private TextView createMessageView(Context context) {
+    TextView view = new TextView(context);
+    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    view.setLayoutParams(layoutParams);
+    view.setGravity(Gravity.CENTER);
+    view.setText(options.getMessageText());
+    view.setTextColor(options.getMessageColor());
+    view.setTextSize(TypedValue.COMPLEX_UNIT_SP, SizeUtil.textSize0_1);
+    return view;
+  }
+
+  private WebView createWebView(Context context) {
+    WebView view = new WebView(context);
+    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    view.setLayoutParams(layoutParams);
+    view.setWebViewClient(new WebViewClient() {
+      @SuppressWarnings("deprecation")
+      @Override
+      public boolean shouldOverrideUrlLoading(WebView wView, String url) {
+        if (url.contains(webOptions.getCloseUrl())) {
+          cancel();
+          String[] urlComponents = url.split("\\?");
+          if (urlComponents.length > 1) {
+            String queryString = urlComponents[1];
+            String[] parameters = queryString.split("&");
+            for (String parameter : parameters) {
+              String[] parameterComponents = parameter.split("=");
+              if (parameterComponents.length > 1 && parameterComponents[0].equals("result")) {
+                Leanplum.track(parameterComponents[1]);
+              }
+            }
+          }
+          return true;
+        }
+        return false;
+      }
+    });
+    view.loadUrl(webOptions.getUrl());
+    return view;
+  }
+
+  /**
+   * Create WebView with HTML template.
+   *
+   * @param context Current context.
+   * @return WebVew WebVew with HTML template.
+   */
+  @SuppressLint("SetJavaScriptEnabled")
+  private WebView createHtml(Context context) {
+    dialogView.setVisibility(View.GONE);
+    final WebView webView = new WebView(context);
+    webView.setBackgroundColor(Color.TRANSPARENT);
+    webView.setVerticalScrollBarEnabled(false);
+    webView.setHorizontalScrollBarEnabled(false);
+    webView.setOnTouchListener(new View.OnTouchListener() {
+      public boolean onTouch(View v, MotionEvent event) {
+        return (event.getAction() == MotionEvent.ACTION_MOVE);
+      }
+    });
+    webView.canGoBack();
+    // Disable long click.
+    webView.setLongClickable(false);
+    webView.setHapticFeedbackEnabled(false);
+    webView.setOnLongClickListener(new View.OnLongClickListener() {
+      @Override
+      public boolean onLongClick(View v) {
+        return true;
+      }
+    });
+
+    WebSettings webViewSettings = webView.getSettings();
+    if (Build.VERSION.SDK_INT >= 17) {
+      webViewSettings.setMediaPlaybackRequiresUserGesture(false);
+    }
+    webViewSettings.setAppCacheEnabled(true);
+    webViewSettings.getSaveFormData();
+    webViewSettings.setAllowFileAccess(true);
+    webViewSettings.setJavaScriptEnabled(true);
+    webViewSettings.setDomStorageEnabled(true);
+    webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true);
+    webViewSettings.setLoadWithOverviewMode(true);
+    webViewSettings.setLoadsImagesAutomatically(true);
+
+    if (Build.VERSION.SDK_INT >= 16) {
+      webViewSettings.setAllowFileAccessFromFileURLs(true);
+      webViewSettings.setAllowUniversalAccessFromFileURLs(true);
+    }
+    if (Build.VERSION.SDK_INT >= 11) {
+      webViewSettings.setBuiltInZoomControls(false);
+      webViewSettings.setDisplayZoomControls(false);
+    }
+    webViewSettings.setSupportZoom(false);
+
+    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    webView.setLayoutParams(layoutParams);
+    final Dialog currentDialog = this;
+    webView.setWebChromeClient(new WebChromeClient());
+    webView.setWebViewClient(new WebViewClient() {
+      @SuppressWarnings("deprecation")
+      @Override
+      public boolean shouldOverrideUrlLoading(WebView wView, String url) {
+        // Open URL event.
+        if (url.contains(htmlOptions.getOpenUrl())) {
+          dialogView.setVisibility(View.VISIBLE);
+          if (activity != null && !activity.isFinishing()) {
+            currentDialog.show();
+          }
+          return true;
+        }
+
+        // Close URL event.
+        if (url.contains(htmlOptions.getCloseUrl())) {
+          cancel();
+          String queryComponentsFromUrl = queryComponentsFromUrl(url, "result");
+          if (!TextUtils.isEmpty(queryComponentsFromUrl)) {
+            Leanplum.track(queryComponentsFromUrl);
+          }
+          return true;
+        }
+
+        // Track URL event.
+        if (url.contains(htmlOptions.getTrackUrl())) {
+          String eventName = queryComponentsFromUrl(url, "event");
+          if (!TextUtils.isEmpty(eventName)) {
+            Double value = Double.parseDouble(queryComponentsFromUrl(url, "value"));
+            String info = queryComponentsFromUrl(url, "info");
+            Map<String, Object> paramsMap = null;
+
+            try {
+              paramsMap = ActionContext.mapFromJson(new JSONObject(queryComponentsFromUrl(url,
+                  "parameters")));
+            } catch (Exception ignored) {
+            }
+
+            if (queryComponentsFromUrl(url, "isMessageEvent").equals("true")) {
+              ActionContext actionContext = htmlOptions.getActionContext();
+              actionContext.trackMessageEvent(eventName, value, info, paramsMap);
+            } else {
+              Leanplum.track(eventName, value, info, paramsMap);
+            }
+          }
+          return true;
+        }
+
+        // Action URL or track action URL event.
+        if (url.contains(htmlOptions.getActionUrl()) ||
+            url.contains(htmlOptions.getTrackActionUrl())) {
+          cancel();
+          String queryComponentsFromUrl = queryComponentsFromUrl(url, "action");
+          try {
+            queryComponentsFromUrl = URLDecoder.decode(queryComponentsFromUrl, "UTF-8");
+          } catch (UnsupportedEncodingException ignored) {
+          }
+
+          ActionContext actionContext = htmlOptions.getActionContext();
+          if (!TextUtils.isEmpty(queryComponentsFromUrl) && actionContext != null) {
+            if (url.contains(htmlOptions.getActionUrl())) {
+              actionContext.runActionNamed(queryComponentsFromUrl);
+            } else {
+              actionContext.runTrackedActionNamed(queryComponentsFromUrl);
+            }
+          }
+          return true;
+        }
+
+        return false;
+      }
+    });
+    String html = htmlOptions.getHtmlTemplate();
+
+    webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null);
+
+    return webView;
+  }
+
+  /**
+   * Get query components from URL.
+   *
+   * @param url URL string.
+   * @param components Name of components.
+   * @return String String with query components.
+   */
+  private String queryComponentsFromUrl(String url, String components) {
+    String componentsFromUrl = "";
+    String[] urlComponents = url.split("\\?");
+    if (urlComponents.length > 1) {
+      String queryString = urlComponents[1];
+      String[] parameters = queryString.split("&");
+      for (String parameter : parameters) {
+        String[] parameterComponents = parameter.split("=");
+        if (parameterComponents.length > 1 && parameterComponents[0].equals(components)) {
+          componentsFromUrl = parameterComponents[1];
+        }
+      }
+    }
+    try {
+      componentsFromUrl = URLDecoder.decode(componentsFromUrl, "UTF-8");
+    } catch (Exception ignored) {
+    }
+    return componentsFromUrl;
+  }
+
+  private TextView createAcceptButton(Context context) {
+    TextView view = new TextView(context);
+    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
+    layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
+    layoutParams.setMargins(0, 0, 0, SizeUtil.dp5);
+
+    view.setPadding(SizeUtil.dp20, SizeUtil.dp5, SizeUtil.dp20, SizeUtil.dp5);
+    view.setLayoutParams(layoutParams);
+    view.setText(options.getAcceptButtonText());
+    view.setTextColor(options.getAcceptButtonTextColor());
+    view.setTypeface(null, Typeface.BOLD);
+
+    BitmapUtil.stateBackgroundDarkerByPercentage(view,
+        options.getAcceptButtonBackgroundColor(), 30);
+
+    view.setTextSize(TypedValue.COMPLEX_UNIT_SP, SizeUtil.textSize0_1);
+    view.setOnClickListener(new View.OnClickListener() {
+      @Override
+      public void onClick(View arg0) {
+        if (!isClosing) {
+          options.accept();
+          cancel();
+        }
+      }
+    });
+    return view;
+  }
+
+  private static int getTheme(Activity activity) {
+    boolean full = (activity.getWindow().getAttributes().flags &
+        WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN;
+    if (full) {
+      return android.R.style.Theme_Translucent_NoTitleBar_Fullscreen;
+    } else {
+      return android.R.style.Theme_Translucent_NoTitleBar;
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/BaseMessageOptions.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.util.Log;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+import com.leanplum.messagetemplates.MessageTemplates.Args;
+import com.leanplum.utils.BitmapUtil;
+
+import java.io.InputStream;
+
+/**
+ * Options used by Center Popup and Interstitial.
+ *
+ * @author Martin Yanakiev
+ */
+abstract class BaseMessageOptions {
+  private ActionContext context;
+  private String title;
+  private int titleColor;
+  private String messageText;
+  private int messageColor;
+  private Bitmap backgroundImage;
+  private int backgroundColor;
+  private String acceptButtonText;
+  private int acceptButtonBackgroundColor;
+  private int acceptButtonTextColor;
+
+  protected BaseMessageOptions(ActionContext context) {
+    this.context = context;
+    setTitle(context.stringNamed(Args.TITLE_TEXT));
+    setTitleColor(context.numberNamed(Args.TITLE_COLOR).intValue());
+    setMessageText(context.stringNamed(Args.MESSAGE_TEXT));
+    setMessageColor(context.numberNamed(Args.MESSAGE_COLOR).intValue());
+    InputStream imageStream = context.streamNamed(Args.BACKGROUND_IMAGE);
+    if (imageStream != null) {
+      try {
+        setBackgroundImage(BitmapFactory.decodeStream(imageStream));
+      } catch (Exception e) {
+        Log.e("Leanplum", "Error loading background image", e);
+      }
+    }
+    setBackgroundColor(context.numberNamed(Args.BACKGROUND_COLOR).intValue());
+    setAcceptButtonText(context.stringNamed(Args.ACCEPT_BUTTON_TEXT));
+    setAcceptButtonBackgroundColor(context.numberNamed(
+        Args.ACCEPT_BUTTON_BACKGROUND_COLOR).intValue());
+    setAcceptButtonTextColor(context.numberNamed(
+        Args.ACCEPT_BUTTON_TEXT_COLOR).intValue());
+  }
+
+  public int getBackgroundColor() {
+    return backgroundColor;
+  }
+
+  private void setBackgroundColor(int backgroundColor) {
+    this.backgroundColor = backgroundColor;
+  }
+
+  public String getAcceptButtonText() {
+    return acceptButtonText;
+  }
+
+  private void setAcceptButtonText(String acceptButtonText) {
+    this.acceptButtonText = acceptButtonText;
+  }
+
+  public String getTitle() {
+    return title;
+  }
+
+  private void setTitle(String title) {
+    this.title = title;
+  }
+
+  public int getTitleColor() {
+    return titleColor;
+  }
+
+  private void setTitleColor(int titleColor) {
+    this.titleColor = titleColor;
+  }
+
+  public String getMessageText() {
+    return messageText;
+  }
+
+  private void setMessageText(String messageText) {
+    this.messageText = messageText;
+  }
+
+  public int getMessageColor() {
+    return messageColor;
+  }
+
+  private void setMessageColor(int messageColor) {
+    this.messageColor = messageColor;
+  }
+
+  public Bitmap getBackgroundImage() {
+    return backgroundImage;
+  }
+
+  public Bitmap getBackgroundImageRounded(int pixels) {
+    return BitmapUtil.getRoundedCornerBitmap(backgroundImage, pixels);
+  }
+
+  private void setBackgroundImage(Bitmap backgroundImage) {
+    this.backgroundImage = backgroundImage;
+  }
+
+  public int getAcceptButtonBackgroundColor() {
+    return acceptButtonBackgroundColor;
+  }
+
+  private void setAcceptButtonBackgroundColor(int color) {
+    this.acceptButtonBackgroundColor = color;
+  }
+
+  public int getAcceptButtonTextColor() {
+    return acceptButtonTextColor;
+  }
+
+  private void setAcceptButtonTextColor(int color) {
+    this.acceptButtonTextColor = color;
+  }
+
+  public void accept() {
+    context.runTrackedActionNamed(Args.ACCEPT_ACTION);
+  }
+
+  public static ActionArgs toArgs(Context currentContext) {
+    return new ActionArgs()
+        .with(Args.TITLE_TEXT,
+            MessageTemplates.getApplicationName(currentContext))
+        .withColor(Args.TITLE_COLOR, Color.BLACK)
+        .with(Args.MESSAGE_TEXT, MessageTemplates.Values.POPUP_MESSAGE)
+        .withColor(Args.MESSAGE_COLOR, Color.BLACK)
+        .withFile(Args.BACKGROUND_IMAGE, null)
+        .withColor(Args.BACKGROUND_COLOR, Color.WHITE)
+        .with(Args.ACCEPT_BUTTON_TEXT, MessageTemplates.Values.OK_TEXT)
+        .withColor(Args.ACCEPT_BUTTON_BACKGROUND_COLOR, Color.WHITE)
+        .withColor(Args.ACCEPT_BUTTON_TEXT_COLOR, Color.argb(255, 0, 122, 255))
+        .withAction(Args.ACCEPT_ACTION, null);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/CenterPopup.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.app.Activity;
+import android.content.Context;
+
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.PostponableAction;
+import com.leanplum.callbacks.VariablesChangedCallback;
+
+/**
+ * Registers a Leanplum action that displays a custom center popup dialog.
+ *
+ * @author Andrew First
+ */
+public class CenterPopup extends BaseMessageDialog {
+  private static final String NAME = "Center Popup";
+
+  public CenterPopup(Activity activity, CenterPopupOptions options) {
+    super(activity, false, options, null, null);
+    this.options = options;
+  }
+
+  public static void register(Context currentContext) {
+    Leanplum.defineAction(NAME, Leanplum.ACTION_KIND_MESSAGE | Leanplum.ACTION_KIND_ACTION,
+        CenterPopupOptions.toArgs(currentContext), new ActionCallback() {
+          @Override
+          public boolean onResponse(final ActionContext context) {
+            Leanplum.addOnceVariablesChangedAndNoDownloadsPendingHandler(
+                new VariablesChangedCallback() {
+                  @Override
+                  public void variablesChanged() {
+                    LeanplumActivityHelper.queueActionUponActive(new PostponableAction() {
+                      @Override
+                      public void run() {
+                        Activity activity = LeanplumActivityHelper.getCurrentActivity();
+                        if (activity == null) {
+                          return;
+                        }
+                        CenterPopup popup = new CenterPopup(activity,
+                            new CenterPopupOptions(context));
+                        if (!activity.isFinishing()) {
+                          popup.show();
+                        }
+                      }
+                    });
+                  }
+                });
+            return true;
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/CenterPopupOptions.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.content.Context;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+import com.leanplum.messagetemplates.MessageTemplates.Args;
+
+/**
+ * Options used by {@link CenterPopup}.
+ *
+ * @author Martin Yanakiev
+ */
+public class CenterPopupOptions extends BaseMessageOptions {
+  private int width;
+  private int height;
+
+  public CenterPopupOptions(ActionContext context) {
+    super(context);
+    setWidth(context.numberNamed(Args.LAYOUT_WIDTH).intValue());
+    setHeight(context.numberNamed(Args.LAYOUT_HEIGHT).intValue());
+  }
+
+  public int getWidth() {
+    return width;
+  }
+
+  private void setWidth(int width) {
+    this.width = width;
+  }
+
+  public int getHeight() {
+    return height;
+  }
+
+  private void setHeight(int height) {
+    this.height = height;
+  }
+
+  public static ActionArgs toArgs(Context currentContext) {
+    return BaseMessageOptions.toArgs(currentContext)
+        .with(Args.LAYOUT_WIDTH, MessageTemplates.Values.CENTER_POPUP_WIDTH)
+        .with(Args.LAYOUT_HEIGHT, MessageTemplates.Values.CENTER_POPUP_HEIGHT);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/Confirm.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.PostponableAction;
+import com.leanplum.messagetemplates.MessageTemplates.Args;
+import com.leanplum.messagetemplates.MessageTemplates.Values;
+
+import static com.leanplum.messagetemplates.MessageTemplates.getApplicationName;
+
+/**
+ * Registers a Leanplum action that displays a system confirm dialog.
+ *
+ * @author Andrew First
+ */
+class Confirm {
+  private static final String NAME = "Confirm";
+
+  public static void register(Context currentContext) {
+    Leanplum.defineAction(
+        NAME,
+        Leanplum.ACTION_KIND_MESSAGE | Leanplum.ACTION_KIND_ACTION,
+        new ActionArgs().with(Args.TITLE, getApplicationName(currentContext))
+            .with(Args.MESSAGE, Values.CONFIRM_MESSAGE)
+            .with(Args.ACCEPT_TEXT, Values.YES_TEXT)
+            .with(Args.CANCEL_TEXT, Values.NO_TEXT)
+            .withAction(Args.ACCEPT_ACTION, null)
+            .withAction(Args.CANCEL_ACTION, null), new ActionCallback() {
+
+          @Override
+          public boolean onResponse(final ActionContext context) {
+            LeanplumActivityHelper.queueActionUponActive(new PostponableAction() {
+              @Override
+              public void run() {
+                Activity activity = LeanplumActivityHelper.getCurrentActivity();
+                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
+                    activity);
+                alertDialogBuilder
+                    .setTitle(context.stringNamed(Args.TITLE))
+                    .setMessage(context.stringNamed(Args.MESSAGE))
+                    .setCancelable(false)
+                    .setPositiveButton(context.stringNamed(Args.ACCEPT_TEXT),
+                        new DialogInterface.OnClickListener() {
+                          public void onClick(DialogInterface dialog, int id) {
+                            context.runTrackedActionNamed(Args.ACCEPT_ACTION);
+                          }
+                        })
+                    .setNegativeButton(context.stringNamed(Args.CANCEL_TEXT),
+                        new DialogInterface.OnClickListener() {
+                          public void onClick(DialogInterface dialog, int id) {
+                            context.runActionNamed(Args.CANCEL_ACTION);
+                          }
+                        });
+                AlertDialog alertDialog = alertDialogBuilder.create();
+                if (activity != null && !activity.isFinishing()) {
+                  alertDialog.show();
+                }
+              }
+            });
+            return true;
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/HTMLOptions.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+
+import org.json.JSONException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Map;
+
+/**
+ * Options used by {@link HTMLTemplate}.
+ *
+ * @author Anna Orlova
+ */
+class HTMLOptions {
+  private String closeUrl;
+  private String openUrl;
+  private String trackUrl;
+  private String actionUrl;
+  private String trackActionUrl;
+  private String htmlTemplate;
+  private ActionContext actionContext;
+  private String htmlAlign;
+  private int htmlHeight;
+
+  HTMLOptions(ActionContext context) {
+    this.setActionContext(context);
+    this.setHtmlTemplate(getTemplate(context));
+    this.setCloseUrl(context.stringNamed(MessageTemplates.Args.CLOSE_URL));
+    this.setOpenUrl(context.stringNamed(MessageTemplates.Args.OPEN_URL));
+    this.setTrackUrl(context.stringNamed(MessageTemplates.Args.TRACK_URL));
+    this.setActionUrl(context.stringNamed(MessageTemplates.Args.ACTION_URL));
+    this.setTrackActionUrl(context.stringNamed(MessageTemplates.Args.TRACK_ACTION_URL));
+    this.setHtmlAlign(context.stringNamed(MessageTemplates.Args.HTML_ALIGN));
+    this.setHtmlHeight(context.numberNamed(MessageTemplates.Args.HTML_HEIGHT).intValue());
+  }
+
+  /**
+   * Read data from file as String.
+   *
+   * @param context ActionContext.
+   * @param name Name of file.
+   * @return String String with data of file.
+   */
+  @SuppressWarnings("SameParameterValue")
+  private static String readFileAsString(ActionContext context, String name) {
+    if (context == null || TextUtils.isEmpty(name)) {
+      return null;
+    }
+
+    String str;
+    InputStream inputStream = context.streamNamed(name);
+    StringBuilder buf = new StringBuilder();
+    BufferedReader reader = null;
+
+    try {
+      reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+      while ((str = reader.readLine()) != null) {
+        buf.append(str).append("\n");
+      }
+      reader.close();
+    } catch (IOException e) {
+      Log.e("Leanplum", "Fail to get HTML template.");
+    } finally {
+      try {
+        if (inputStream != null) {
+          inputStream.close();
+        }
+        if (reader != null) {
+          reader.close();
+        }
+      } catch (Exception e) {
+        Log.w("Leanplum", "Failed to close InputStream or BufferedReader: " + e);
+      }
+    }
+    return buf.toString();
+  }
+
+  /**
+   * Replace all keys with __file__ prefix to keys without __file__ prefix and replace value of
+   * those keys with local path to file.
+   *
+   * @param map Map with arguments from ActionContext.
+   * @param htmlTemplateName Name of file with HTML template.
+   * @return Map Map with updated arguments.
+   */
+  private static Map<String, Object> replaceFileToLocalPath(Map<String, Object> map,
+      String htmlTemplateName) {
+    if (map == null) {
+      return null;
+    }
+    String[] keyArray = map.keySet().toArray(new String[map.keySet().size()]);
+    for (String key : keyArray) {
+      if (map.get(key) instanceof Map) {
+        @SuppressWarnings("unchecked")
+        Map<String, Object> mapValue = (Map<String, Object>) map.get(key);
+        replaceFileToLocalPath(mapValue, htmlTemplateName);
+      } else if (key.contains(MessageTemplates.Values.FILE_PREFIX) &&
+          !key.equals(htmlTemplateName)) {
+        String filePath = ActionContext.filePath((String) map.get(key));
+        if (filePath == null) {
+          continue;
+        }
+        File f = new File(filePath);
+        String localPath = "file://" + f.getAbsolutePath();
+        if (localPath.contains(Leanplum.getContext().getPackageName())) {
+          map.put(key.replace(MessageTemplates.Values.FILE_PREFIX, ""),
+              localPath.replace(" ", "%20"));
+        }
+        map.remove(key);
+      }
+    }
+    return map;
+  }
+
+  /**
+   * Get HTML template file.
+   *
+   * @param context ActionContext.
+   * @return String String with data of HTML template file.
+   */
+  private static String getTemplate(ActionContext context) {
+    if (context == null) {
+      return null;
+    }
+
+    String htmlTemplate = readFileAsString(context, MessageTemplates.Values.HTML_TEMPLATE_PREFIX);
+    Map<String, Object> htmlArgs = replaceFileToLocalPath(context.getArgs(),
+        MessageTemplates.Values.HTML_TEMPLATE_PREFIX);
+    if (htmlArgs == null || TextUtils.isEmpty(htmlTemplate)) {
+      return null;
+    }
+
+    htmlArgs.put("messageId", context.getMessageId());
+    if (context.getContextualValues() != null && context.getContextualValues().arguments != null) {
+      htmlArgs.put("displayEvent", context.getContextualValues().arguments);
+    }
+
+    String htmlString = "";
+    try {
+      htmlString = (htmlTemplate.replace("##Vars##",
+          ActionContext.mapToJsonObject(htmlArgs).toString()));
+    } catch (JSONException e) {
+      Log.e("Leanplum", "Cannot convert map of arguments to JSON object.");
+    }
+    return htmlString.replace("\\/", "/");
+  }
+
+  /**
+   * @return boolean True if it's full screen template.
+   */
+  boolean isFullScreen() {
+    return htmlHeight == 0;
+  }
+
+  int getHtmlHeight() {
+    return htmlHeight;
+  }
+
+  private void setHtmlHeight(int htmlHeight) {
+    this.htmlHeight = htmlHeight;
+  }
+
+  String getHtmlAlign() {
+    return htmlAlign;
+  }
+
+  private void setHtmlAlign(String htmlAlign) {
+    this.htmlAlign = htmlAlign;
+  }
+
+  ActionContext getActionContext() {
+    return actionContext;
+  }
+
+  private void setActionContext(ActionContext actionContext) {
+    //noinspection AccessStaticViaInstance
+    this.actionContext = actionContext;
+  }
+
+  String getHtmlTemplate() {
+    return htmlTemplate;
+  }
+
+  private void setHtmlTemplate(String htmlTemplate) {
+    this.htmlTemplate = htmlTemplate;
+  }
+
+  String getTrackActionUrl() {
+    return trackActionUrl;
+  }
+
+  private void setTrackActionUrl(String trackActionUrl) {
+    this.trackActionUrl = trackActionUrl;
+  }
+
+  String getTrackUrl() {
+    return trackUrl;
+  }
+
+  private void setTrackUrl(String trackUrl) {
+    this.trackUrl = trackUrl;
+  }
+
+  String getOpenUrl() {
+    return openUrl;
+  }
+
+  private void setOpenUrl(String openUrl) {
+    this.openUrl = openUrl;
+  }
+
+  String getActionUrl() {
+    return actionUrl;
+  }
+
+  private void setActionUrl(String actionUrl) {
+    this.actionUrl = actionUrl;
+  }
+
+  String getCloseUrl() {
+    return closeUrl;
+  }
+
+  private void setCloseUrl(String closeUrl) {
+    this.closeUrl = closeUrl;
+  }
+
+  public static ActionArgs toArgs() {
+    return new ActionArgs()
+        .with(MessageTemplates.Args.CLOSE_URL, MessageTemplates.Values.DEFAULT_CLOSE_URL)
+        .with(MessageTemplates.Args.OPEN_URL, MessageTemplates.Values.DEFAULT_OPEN_URL)
+        .with(MessageTemplates.Args.ACTION_URL, MessageTemplates.Values.DEFAULT_ACTION_URL)
+        .with(MessageTemplates.Args.TRACK_ACTION_URL,
+            MessageTemplates.Values.DEFAULT_TRACK_ACTION_URL)
+        .with(MessageTemplates.Args.TRACK_URL, MessageTemplates.Values.DEFAULT_TRACK_URL)
+        .with(MessageTemplates.Args.HTML_ALIGN, MessageTemplates.Values.DEFAULT_HTML_ALING)
+        .with(MessageTemplates.Args.HTML_HEIGHT, MessageTemplates.Values.DEFAULT_HTML_HEIGHT);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/HTMLTemplate.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.app.Activity;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.PostponableAction;
+import com.leanplum.callbacks.VariablesChangedCallback;
+
+/**
+ * Registers a Leanplum action that displays a HTML message.
+ *
+ * @author Anna Orlova
+ */
+@SuppressWarnings("WeakerAccess")
+public class HTMLTemplate extends BaseMessageDialog {
+  private static final String NAME = "HTML";
+
+  public HTMLTemplate(Activity activity, HTMLOptions htmlOptions) {
+    super(activity, htmlOptions.isFullScreen(), null, null, htmlOptions);
+    this.htmlOptions = htmlOptions;
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
+    if (!htmlOptions.isFullScreen()) {
+      if (htmlOptions.getHtmlAlign().equals(MessageTemplates.Args.HTML_ALIGN_TOP) && ev.getY()
+          > htmlOptions.getHtmlHeight() ||
+          htmlOptions.getHtmlAlign().equals(MessageTemplates.Args.HTML_ALIGN_BOTTOM) && ev.getY()
+              < dialogView.getHeight() - htmlOptions.getHtmlHeight()) {
+        activity.dispatchTouchEvent(ev);
+      }
+    }
+    return super.dispatchTouchEvent(ev);
+  }
+
+  public static void register() {
+    Leanplum.defineAction(NAME, Leanplum.ACTION_KIND_MESSAGE | Leanplum.ACTION_KIND_ACTION,
+        HTMLOptions.toArgs(), new ActionCallback() {
+          @Override
+          public boolean onResponse(final ActionContext context) {
+            Leanplum.addOnceVariablesChangedAndNoDownloadsPendingHandler(
+                new VariablesChangedCallback() {
+                  @Override
+                  public void variablesChanged() {
+                    LeanplumActivityHelper.queueActionUponActive(
+                        new PostponableAction() {
+                          @Override
+                          public void run() {
+                            try {
+                              HTMLOptions htmlOptions = new HTMLOptions(context);
+                              if (htmlOptions.getHtmlTemplate() == null) {
+                                return;
+                              }
+                              final Activity activity = LeanplumActivityHelper.getCurrentActivity();
+                              if (activity != null && !activity.isFinishing()) {
+                                new HTMLTemplate(activity, htmlOptions);
+                              }
+                            } catch (Throwable t) {
+                              Log.e("Leanplum", "Fail on show HTML In-App message.", t);
+                            }
+                          }
+                        });
+                  }
+                });
+            return true;
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/Interstitial.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.app.Activity;
+import android.content.Context;
+
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.PostponableAction;
+import com.leanplum.callbacks.VariablesChangedCallback;
+
+/**
+ * Registers a Leanplum action that displays a fullscreen interstitial.
+ *
+ * @author Andrew First
+ */
+public class Interstitial extends BaseMessageDialog {
+  private static final String NAME = "Interstitial";
+
+  public Interstitial(Activity activity, InterstitialOptions options) {
+    super(activity, true, options, null, null);
+    this.options = options;
+  }
+
+  public static void register(Context currentContext) {
+    Leanplum.defineAction(NAME, Leanplum.ACTION_KIND_MESSAGE | Leanplum.ACTION_KIND_ACTION,
+        InterstitialOptions.toArgs(currentContext),
+        new ActionCallback() {
+          @Override
+          public boolean onResponse(final ActionContext context) {
+            Leanplum.addOnceVariablesChangedAndNoDownloadsPendingHandler(
+                new VariablesChangedCallback() {
+                  @Override
+                  public void variablesChanged() {
+                    LeanplumActivityHelper.queueActionUponActive(
+                        new PostponableAction() {
+                          @Override
+                          public void run() {
+                            Activity activity = LeanplumActivityHelper.getCurrentActivity();
+                            if (activity == null) {
+                              return;
+                            }
+                            Interstitial interstitial = new Interstitial(activity,
+                                new InterstitialOptions(context));
+                            if (!activity.isFinishing()) {
+                              interstitial.show();
+                            }
+                          }
+                        });
+                  }
+                });
+            return true;
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/InterstitialOptions.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.content.Context;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+
+/**
+ * Options used by {@link Interstitial}.
+ *
+ * @author Martin Yanakiev
+ */
+public class InterstitialOptions extends BaseMessageOptions {
+  public InterstitialOptions(ActionContext context) {
+    super(context);
+    // Set specific properties for interstitial popup.
+  }
+
+  public static ActionArgs toArgs(Context currentContext) {
+    return BaseMessageOptions.toArgs(currentContext)
+        .with(MessageTemplates.Args.MESSAGE_TEXT, MessageTemplates.Values.INTERSTITIAL_MESSAGE);
+    // Add specific args for interstitial popup.
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/MessageTemplates.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.content.Context;
+
+/**
+ * Registers all of the built-in message templates.
+ *
+ * @author Andrew First
+ */
+public class MessageTemplates {
+  static class Args {
+    // Open URL
+    static final String URL = "URL";
+
+    // Alert/confirm arguments.
+    static final String TITLE = "Title";
+    static final String MESSAGE = "Message";
+    static final String ACCEPT_TEXT = "Accept text";
+    static final String CANCEL_TEXT = "Cancel text";
+    static final String DISMISS_TEXT = "Dismiss text";
+    static final String ACCEPT_ACTION = "Accept action";
+    static final String CANCEL_ACTION = "Cancel action";
+    static final String DISMISS_ACTION = "Dismiss action";
+
+    // Center popup/interstitial arguments.
+    static final String TITLE_TEXT = "Title.Text";
+    static final String TITLE_COLOR = "Title.Color";
+    static final String MESSAGE_TEXT = "Message.Text";
+    static final String MESSAGE_COLOR = "Message.Color";
+    static final String ACCEPT_BUTTON_TEXT = "Accept button.Text";
+    static final String ACCEPT_BUTTON_BACKGROUND_COLOR = "Accept button.Background color";
+    static final String ACCEPT_BUTTON_TEXT_COLOR = "Accept button.Text color";
+    static final String BACKGROUND_IMAGE = "Background image";
+    static final String BACKGROUND_COLOR = "Background color";
+    static final String LAYOUT_WIDTH = "Layout.Width";
+    static final String LAYOUT_HEIGHT = "Layout.Height";
+    static final String HTML_HEIGHT = "HTML Height";
+    static final String HTML_ALIGN = "HTML Align";
+    static final String HTML_ALIGN_TOP = "Top";
+    static final String HTML_ALIGN_BOTTOM = "Bottom";
+
+    // Web interstitial arguments.
+    static final String CLOSE_URL = "Close URL";
+    static final String HAS_DISMISS_BUTTON = "Has dismiss button";
+
+    // HTML Template arguments.
+    static final String OPEN_URL = "Open URL";
+    static final String TRACK_URL = "Track URL";
+    static final String ACTION_URL = "Action URL";
+    static final String TRACK_ACTION_URL = "Track Action URL";
+  }
+
+  static class Values {
+    static final String ALERT_MESSAGE = "Alert message goes here.";
+    static final String CONFIRM_MESSAGE = "Confirmation message goes here.";
+    static final String POPUP_MESSAGE = "Popup message goes here.";
+    static final String INTERSTITIAL_MESSAGE = "Interstitial message goes here.";
+    static final String OK_TEXT = "OK";
+    static final String YES_TEXT = "Yes";
+    static final String NO_TEXT = "No";
+    static final int CENTER_POPUP_WIDTH = 300;
+    static final int CENTER_POPUP_HEIGHT = 250;
+    static final int DEFAULT_HTML_HEIGHT = 0;
+    static final String DEFAULT_HTML_ALING = Args.HTML_ALIGN_TOP;
+
+    // Open URL.
+    static final String DEFAULT_URL = "http://www.example.com";
+
+    // Web interstitial values.
+    static final String DEFAULT_CLOSE_URL = "http://leanplum:close";
+    static final boolean DEFAULT_HAS_DISMISS_BUTTON = true;
+
+    // HTML Template values.
+    public static final String FILE_PREFIX = "__file__";
+    public static final String HTML_TEMPLATE_PREFIX = "__file__Template";
+    static final String DEFAULT_OPEN_URL = "http://leanplum:loadFinished";
+    static final String DEFAULT_TRACK_URL = "http://leanplum:track";
+    static final String DEFAULT_ACTION_URL = "http://leanplum:runAction";
+    static final String DEFAULT_TRACK_ACTION_URL = "http://leanplum:runTrackedAction";
+
+  }
+
+  private static boolean registered = false;
+
+  static String getApplicationName(Context context) {
+    int stringId = context.getApplicationInfo().labelRes;
+    if (stringId == 0) {
+      return context.getApplicationInfo().loadLabel(context.getPackageManager()).toString();
+    }
+    return context.getString(stringId);
+  }
+
+  public synchronized static void register(Context currentContext) {
+    if (registered) {
+      return;
+    }
+    registered = true;
+    OpenURL.register();
+    Alert.register(currentContext);
+    Confirm.register(currentContext);
+    CenterPopup.register(currentContext);
+    Interstitial.register(currentContext);
+    WebInterstitial.register();
+    HTMLTemplate.register();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/OpenURL.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.PostponableAction;
+import com.leanplum.messagetemplates.MessageTemplates.Args;
+import com.leanplum.messagetemplates.MessageTemplates.Values;
+
+import java.util.List;
+
+/**
+ * Registers a Leanplum action that opens a particular URL. If the URL cannot be handled by the
+ * system URL handler, you can add your own action responder using {@link Leanplum#onAction} that
+ * handles the URL how you want.
+ *
+ * @author Andrew First
+ */
+class OpenURL {
+  private static final String NAME = "Open URL";
+
+  public static void register() {
+    Leanplum.defineAction(NAME, Leanplum.ACTION_KIND_ACTION,
+        new ActionArgs().with(Args.URL, Values.DEFAULT_URL), new ActionCallback() {
+          @Override
+          public boolean onResponse(ActionContext context) {
+            String url = context.stringNamed(Args.URL);
+            final Intent uriIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+            // Calling startActivity() from outside of an Activity context requires the
+            // FLAG_ACTIVITY_NEW_TASK flag.
+            if (!(Leanplum.getContext() instanceof Activity)) {
+              uriIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            }
+            try {
+              if (Leanplum.getContext() != null) {
+                LeanplumActivityHelper.queueActionUponActive(
+                    new PostponableAction() {
+                      @Override
+                      public void run() {
+                        Context context = Leanplum.getContext();
+                        if (context == null) {
+                          return;
+                        }
+                        List<ResolveInfo> resolveInfoList = context.getPackageManager().
+                            queryIntentActivities(uriIntent, 0);
+                        // If url can be handled by current app - set package name to intent, so url
+                        // will be open by current app. Skip chooser dialog.
+                        if (resolveInfoList != null && resolveInfoList.size() != 0) {
+                          for (ResolveInfo resolveInfo : resolveInfoList) {
+                            if (resolveInfo != null && resolveInfo.activityInfo != null &&
+                                resolveInfo.activityInfo.name != null) {
+                              if (resolveInfo.activityInfo.name.contains(
+                                  context.getPackageName())) {
+                                uriIntent.setPackage(resolveInfo.activityInfo.packageName);
+                              }
+                            }
+                          }
+                          try {
+                            // Even if we have valid destination, startActivity can crash if
+                            // activity we are trying to open is not exported in manifest.
+                            context.startActivity(uriIntent);
+                          } catch (ActivityNotFoundException e) {
+                            Log.e("Leanplum", "Activity you are trying to start doesn't exist or " +
+                                "isn't exported in manifest: " + e);
+                          }
+                        }
+                      }
+                    });
+                return true;
+              } else {
+                return false;
+              }
+            } catch (ActivityNotFoundException e) {
+              Log.e("Leanplum", "Unable to handle URL " + url);
+              return false;
+            }
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/WebInterstitial.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.app.Activity;
+import android.content.Context;
+
+import com.leanplum.ActionContext;
+import com.leanplum.Leanplum;
+import com.leanplum.LeanplumActivityHelper;
+import com.leanplum.callbacks.ActionCallback;
+import com.leanplum.callbacks.PostponableAction;
+
+/**
+ * Registers a Leanplum action that displays a fullscreen Web Interstitial.
+ *
+ * @author Atanas Dobrev
+ */
+public class WebInterstitial extends BaseMessageDialog {
+  private static final String NAME = "Web Interstitial";
+
+  public WebInterstitial(Activity activity, WebInterstitialOptions options) {
+    super(activity, true, null, options, null);
+    this.webOptions = options;
+  }
+
+  /**
+   * Deprecated: Use {@link WebInterstitial#register()}.
+   */
+  @Deprecated
+  @SuppressWarnings("unused")
+  public static void register(Context currentContext) {
+    register();
+  }
+
+  public static void register() {
+    Leanplum.defineAction(NAME, Leanplum.ACTION_KIND_MESSAGE | Leanplum.ACTION_KIND_ACTION,
+        WebInterstitialOptions.toArgs(), new ActionCallback() {
+          @Override
+          public boolean onResponse(final ActionContext context) {
+            LeanplumActivityHelper.queueActionUponActive(new PostponableAction() {
+              @Override
+              public void run() {
+                Activity activity = LeanplumActivityHelper.getCurrentActivity();
+                if (activity == null) {
+                  return;
+                }
+                WebInterstitial webInterstitial = new WebInterstitial(activity,
+                    new WebInterstitialOptions(context));
+                if (!activity.isFinishing()) {
+                  webInterstitial.show();
+                }
+              }
+            });
+            return true;
+          }
+        });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/messagetemplates/WebInterstitialOptions.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.messagetemplates;
+
+import android.content.Context;
+
+import com.leanplum.ActionArgs;
+import com.leanplum.ActionContext;
+import com.leanplum.messagetemplates.MessageTemplates.Args;
+import com.leanplum.messagetemplates.MessageTemplates.Values;
+
+/**
+ * Options used by {@link WebInterstitial}.
+ *
+ * @author Atanas Dobrev
+ */
+@SuppressWarnings("WeakerAccess")
+public class WebInterstitialOptions {
+  private String url;
+  private String closeUrl;
+  private boolean hasDismissButton;
+
+  protected WebInterstitialOptions(ActionContext context) {
+    this.setUrl(context.stringNamed(Args.URL));
+    this.setHasDismissButton(context.booleanNamed(Args.HAS_DISMISS_BUTTON));
+    this.setCloseUrl(context.stringNamed(Args.CLOSE_URL));
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  private void setUrl(String url) {
+    this.url = url;
+  }
+
+  public boolean hasDismissButton() {
+    return hasDismissButton;
+  }
+
+  private void setHasDismissButton(boolean hasDismissButton) {
+    this.hasDismissButton = hasDismissButton;
+  }
+
+  public String getCloseUrl() {
+    return closeUrl;
+  }
+
+  private void setCloseUrl(String closeUrl) {
+    this.closeUrl = closeUrl;
+  }
+
+  /**
+   * Deprecated: Use {@link WebInterstitialOptions#toArgs()}.
+   */
+  @Deprecated
+  @SuppressWarnings("unused")
+  public static ActionArgs toArgs(Context currentContext) {
+    return toArgs();
+  }
+
+  public static ActionArgs toArgs() {
+    return new ActionArgs()
+        .with(Args.URL, Values.DEFAULT_URL)
+        .with(Args.CLOSE_URL, Values.DEFAULT_CLOSE_URL)
+        .with(Args.HAS_DISMISS_BUTTON, Values.DEFAULT_HAS_DISMISS_BUTTON);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/utils/BitmapUtil.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.utils;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.graphics.drawable.shapes.RoundRectShape;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.leanplum.internal.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * Bitmap manipulation utilities.
+ *
+ * @author Martin Yanakiev, Anna Orlova
+ */
+public class BitmapUtil {
+  // Layout_height for imageView is 192dp
+  // https://android.googlesource.com/platform/frameworks/base
+  // /+/6387d2f6dae27ba6e8481883325adad96d3010f4/core/res/res/layout
+  // /notification_template_big_picture.xml
+  private static final int BIG_PICTURE_MAX_HEIGHT_DP = 192;
+
+  public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
+    if (bitmap == null) {
+      return null;
+    }
+
+    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
+        Config.ARGB_8888);
+    android.graphics.Canvas canvas = new android.graphics.Canvas(output);
+
+    final int color = 0xff000000;
+    final android.graphics.Paint paint = new android.graphics.Paint();
+    final android.graphics.Rect rect = new android.graphics.Rect(0, 0,
+        bitmap.getWidth(), bitmap.getHeight());
+    final android.graphics.RectF rectF = new android.graphics.RectF(rect);
+
+    paint.setAntiAlias(true);
+    canvas.drawARGB(0, 0, 0, 0);
+    paint.setColor(color);
+    canvas.drawRoundRect(rectF, pixels, pixels, paint);
+
+    paint.setXfermode(new android.graphics.PorterDuffXfermode(Mode.SRC_IN));
+    canvas.drawBitmap(bitmap, rect, rect, paint);
+
+    return output;
+  }
+
+  public static void stateBackgroundDarkerByPercentage(View v,
+      int normalStateColor, int percentage) {
+    int darker = getDarker(normalStateColor, percentage);
+    stateBackground(v, normalStateColor, darker);
+  }
+
+  public static int getDarker(int color, int percentage) {
+    if (percentage < 0 || percentage > 100)
+      percentage = 0;
+    double d = ((100 - percentage) / (double) 100);
+    int a = (color >> 24) & 0xFF;
+    int r = (int) (((color >> 16) & 0xFF) * d) & 0xFF;
+    int g = (int) (((color >> 8) & 0xFF) * d) & 0xFF;
+    int b = (int) ((color & 0xFF) * d) & 0xFF;
+    a = a << 24;
+    r = r << 16;
+    g = g << 8;
+    return a | r | g | b;
+  }
+
+  public static void stateBackground(View v, int normalStateColor,
+      int pressedStateColor) {
+    if (Build.VERSION.SDK_INT >= 16) {
+      v.setBackground(getBackground(normalStateColor, pressedStateColor));
+    } else {
+      v.setBackgroundColor(normalStateColor);
+    }
+  }
+
+  private static Drawable getBackground(int normalStateColor,
+      int pressedStateColor) {
+    StateListDrawable background = new StateListDrawable();
+    int c = SizeUtil.dp10;
+    float[] r = new float[] {c, c, c, c, c, c, c, c};
+    RoundRectShape rr = new RoundRectShape(r, null, null);
+    ShapeDrawable cd = new ShapeDrawable();
+    cd.setShape(rr);
+    cd.getPaint().setColor(pressedStateColor);
+    background.addState(new int[] {android.R.attr.state_pressed,
+        android.R.attr.state_focused}, cd);
+    background.addState(new int[] {-android.R.attr.state_pressed,
+        android.R.attr.state_focused}, cd);
+    background.addState(new int[] {android.R.attr.state_pressed,
+        -android.R.attr.state_focused}, cd);
+    ShapeDrawable cd1 = new ShapeDrawable();
+    cd1.setShape(rr);
+    cd1.getPaint().setColor(normalStateColor);
+    background.addState(new int[] {-android.R.attr.state_pressed,
+        -android.R.attr.state_focused}, cd1);
+    return background;
+  }
+
+  /**
+   * Method to calculate a sample size value that is a power of two based on a target width and
+   * height. From official Android documentation:
+   * https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
+   *
+   * @param reqWidth The requested width of the image.
+   * @param reqHeight The requested height of the image.
+   * @return The calculated inSampleSize - power of two.
+   */
+  private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
+      int reqHeight) {
+    // Raw height and width of image.
+    final int height = options.outHeight;
+    final int width = options.outWidth;
+    int inSampleSize = 1;
+
+    if (height > reqHeight || width > reqWidth) {
+      final int halfHeight = height / 2;
+      final int halfWidth = width / 2;
+
+      // Calculate the largest inSampleSize value that is a power of 2 and keeps both
+      // height and width larger than the requested height and width.
+      while ((halfHeight / inSampleSize) >= reqHeight
+          && (halfWidth / inSampleSize) >= reqWidth) {
+        inSampleSize *= 2;
+      }
+    }
+
+    return inSampleSize;
+  }
+
+  /**
+   * Download a scaled bitmap.
+   *
+   * @param imageUrl The string of URL image.
+   * @param width The requested width of the image.
+   * @param height The requested height of the image.
+   * @return The scaled bitmap downloaded form URL.
+   */
+  private static Bitmap getBitmapFromUrl(String imageUrl, int width, int height) {
+    InputStream input = null;
+    try {
+      input = new URL(imageUrl).openStream();
+
+      // First decode with inJustDecodeBounds=true to check dimensions.
+      final BitmapFactory.Options options = new BitmapFactory.Options();
+      options.inJustDecodeBounds = true;
+      BitmapFactory.decodeStream(input, null, options);
+
+      closeStream(input);
+
+      input = new URL(imageUrl).openStream();
+      options.inSampleSize = calculateInSampleSize(options, width, height);
+      // Decode bitmap with inSampleSize set.
+      options.inJustDecodeBounds = false;
+      return BitmapFactory.decodeStream(input, null, options);
+    } catch (IOException e) {
+      Log.e(String.format("IOException in image download for URL: %s.", imageUrl), e);
+      return null;
+    } finally {
+      closeStream(input);
+    }
+  }
+
+  /**
+   * Create a scaled bitmap.
+   *
+   * @param context The application context.
+   * @param imageUrl The string of URL image.
+   * @return The scaled bitmap.
+   */
+  public static Bitmap getScaledBitmap(Context context, String imageUrl) {
+    // Processing an image depending on the current screen size to avoid central crop if the image
+    // ratio is more than 2:1. Google aspect ~2:1 - page 78
+    // http://commondatastorage.googleapis.com/io2012/presentations/live%20to%20website/105.pdf
+    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+    DisplayMetrics displayMetrics = new DisplayMetrics();
+    windowManager.getDefaultDisplay().getMetrics(displayMetrics);
+
+    int pixelsHeight = Math.round(displayMetrics.density * BIG_PICTURE_MAX_HEIGHT_DP + 0.5f);
+    int pixelsWidth = Math.min(2 * pixelsHeight, displayMetrics.widthPixels);
+
+    Bitmap bitmap = getBitmapFromUrl(imageUrl, pixelsWidth, pixelsHeight);
+    try {
+      bitmap = Bitmap.createScaledBitmap(bitmap, pixelsWidth, pixelsHeight, true);
+    } catch (Exception e) {
+      Log.e("Failed on scale image " + imageUrl + " to (" + pixelsWidth + ", " + pixelsHeight + ")",
+          e);
+    }
+
+    return bitmap;
+  }
+
+  /**
+   * Method to close InputStream.
+   *
+   * @param inputStream The InputStream which must be closed.
+   */
+  private static void closeStream(InputStream inputStream) {
+    try {
+      if (inputStream != null) {
+        inputStream.close();
+      }
+    } catch (IOException e) {
+      Log.e("IOException during closing of image download stream.", e);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/utils/SharedPreferencesUtil.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+/**
+ * Shared preferences manipulation utilities.
+ *
+ * @author Anna Orlova
+ */
+public class SharedPreferencesUtil {
+  public static final String DEFAULT_STRING_VALUE = "";
+
+  /**
+   * Gets string value for key from shared preferences.
+   *
+   * @param context Application context.
+   * @param sharedPreferenceName Shared preference name.
+   * @param key Key of preference.
+   * @return String Value for key, if here no value - return DEFAULT_STRING_VALUE.
+   */
+  public static String getString(Context context, String sharedPreferenceName, String key) {
+    final SharedPreferences sharedPreferences = getPreferences(context, sharedPreferenceName);
+    return sharedPreferences.getString(key, DEFAULT_STRING_VALUE);
+  }
+
+  /**
+   * Get application shared preferences with sharedPreferenceName name.
+   *
+   * @param context Application context.
+   * @param sharedPreferenceName Shared preference name.
+   * @return Application's {@code SharedPreferences}.
+   */
+  private static SharedPreferences getPreferences(Context context, String sharedPreferenceName) {
+    return context.getSharedPreferences(sharedPreferenceName, Context.MODE_PRIVATE);
+  }
+
+  /**
+   * Sets string value for provided key to shared preference with sharedPreferenceName name.
+   *
+   * @param context application context.
+   * @param sharedPreferenceName shared preference name.
+   * @param key key of preference.
+   * @param value value of preference.
+   */
+  public static void setString(Context context, String sharedPreferenceName, String key,
+      String value) {
+    final SharedPreferences sharedPreferences = getPreferences(context, sharedPreferenceName);
+    SharedPreferences.Editor editor = sharedPreferences.edit();
+    editor.putString(key, value);
+    try {
+      editor.apply();
+    } catch (NoSuchMethodError e) {
+      editor.commit();
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/utils/SizeUtil.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+/**
+ * Utilities for converting between different size units.
+ *
+ * @author Martin Yanakiev
+ */
+public class SizeUtil {
+  public static int dp2;
+  public static int dp30;
+  public static int dp5;
+  public static int dp20;
+  public static int dp18;
+  public static int dp16;
+  public static int dp14;
+  public static int dp10;
+  public static int dp7;
+  public static int dp100;
+  public static int dp200;
+  public static int dp250;
+  public static int dp50;
+
+  public static final int textSize0_2 = 16;
+  public static final int textSize0_1 = 18;
+  public static final int textSize0 = 20;
+  public static final int textSize1 = 22;
+  public static final int textSize2 = 24;
+
+  private static boolean hasInited = false;
+
+  public static void init(Context context) {
+    if (hasInited) {
+      return;
+    }
+    hasInited = true;
+    dp30 = dpToPx(context, 30);
+    dp5 = dpToPx(context, 5);
+    dp20 = dpToPx(context, 20);
+    dp10 = dpToPx(context, 10);
+    dp7 = dpToPx(context, 7);
+    dp18 = dpToPx(context, 18);
+    dp16 = dpToPx(context, 16);
+    dp14 = dpToPx(context, 14);
+    dp100 = dpToPx(context, 100);
+    dp200 = dpToPx(context, 200);
+    dp250 = dpToPx(context, 250);
+    dp2 = dpToPx(context, 2);
+    dp50 = dpToPx(context, 50);
+  }
+
+  public static int dpToPx(Context context, int dp) {
+    init(context);
+    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    return Math.round(dp
+        * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
+  }
+
+  public static int pxToDp(Context context, int px) {
+    init(context);
+    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    return Math.round(px
+        / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
+  }
+
+  public static int spToPx(Context context, int sp) {
+    init(context);
+    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    return (int) (sp * displayMetrics.scaledDensity);
+  }
+
+  public static int pxToSp(Context context, int px) {
+    init(context);
+    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    return (int) (px / displayMetrics.scaledDensity);
+  }
+
+  public static int getStatusBarHeight(Activity activity) {
+    init(activity);
+    boolean full = (activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN;
+    if (full) {
+      return 0;
+    }
+    int result = 0;
+    int resourceId = activity.getResources().getIdentifier("status_bar_height",
+        "dimen", "android");
+    if (resourceId > 0) {
+      result = activity.getResources().getDimensionPixelSize(resourceId);
+    }
+    return result;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/views/BackgroundImageView.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.PorterDuff.Mode;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout.LayoutParams;
+
+import com.leanplum.utils.BitmapUtil;
+import com.leanplum.utils.SizeUtil;
+
+/**
+ * The image background on a Center Popup or Interstitial dialog.
+ *
+ * @author Martin Yanakiev
+ */
+public class BackgroundImageView extends ImageView {
+  private Paint paint = new Paint();
+  private boolean fullscreen;
+  private Matrix emptyMatrix = new Matrix();
+  private boolean loadedBitmap;
+
+  public BackgroundImageView(Context context, AttributeSet attrs, int defStyle) {
+    super(context, attrs, defStyle);
+    init();
+  }
+
+  public BackgroundImageView(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    init();
+  }
+
+  public BackgroundImageView(Context context, boolean fullscreen) {
+    super(context);
+    init();
+    this.fullscreen = fullscreen;
+  }
+
+  private void init() {
+    paint.setColor(0xFF00FF00);
+    paint.setStrokeWidth(2);
+    paint.setStyle(Style.FILL_AND_STROKE);
+  }
+
+  @Override
+  protected void onDraw(Canvas canvas) {
+    super.onDraw(canvas);
+    if (fullscreen) {
+      return;
+    }
+    if (loadedBitmap) {
+      loadedBitmap = false;
+      return;
+    }
+    Bitmap bitmap = loadBitmapFromView(this);
+    canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
+    bitmap = BitmapUtil.getRoundedCornerBitmap(bitmap, SizeUtil.dp20);
+    canvas.drawBitmap(bitmap, emptyMatrix, paint);
+  }
+
+  public Bitmap loadBitmapFromView(View view) {
+    if (view.getMeasuredHeight() <= 0) {
+      view.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    }
+    Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
+        Bitmap.Config.ARGB_8888);
+    Canvas canvas = new Canvas(bitmap);
+    view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
+    loadedBitmap = true;
+    view.draw(canvas);
+    return bitmap;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/AndroidSDK/src/com/leanplum/views/CloseButton.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.views;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.leanplum.utils.SizeUtil;
+
+/**
+ * The close button on a Center Popup or Interstitial dialog.
+ *
+ * @author Martin Yanakiev
+ */
+public class CloseButton extends View {
+  private Paint circlePaint = new Paint();
+  private Paint circlePressedPaint = new Paint();
+  private Paint linePaint = new Paint();
+  private float size;
+  private float x1;
+  private float y1;
+  private float x2;
+  private float y2;
+  private boolean isPressed = false;
+
+  public CloseButton(Context context) {
+    super(context);
+    initLabelView();
+  }
+
+  public CloseButton(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    initLabelView();
+  }
+
+  private void initLabelView() {
+    circlePaint.setAntiAlias(true);
+    circlePaint.setColor(0xFFDDDDDD);
+    circlePaint.setStrokeWidth(2);
+    circlePaint.setStyle(Style.FILL_AND_STROKE);
+    circlePressedPaint.setAntiAlias(true);
+    circlePressedPaint.setColor(0xFF999999);
+    circlePressedPaint.setStrokeWidth(2);
+    circlePressedPaint.setStyle(Style.FILL_AND_STROKE);
+    linePaint.setAntiAlias(true);
+    linePaint.setColor(0xFF000000);
+    linePaint.setStrokeWidth(3);
+    linePaint.setStyle(Style.FILL_AND_STROKE);
+    size = SizeUtil.dp30;
+    x1 = size * (2 / (float) 6);
+    x2 = size * (4 / (float) 6);
+    y1 = size * (2 / (float) 6);
+    y2 = size * (4 / (float) 6);
+  }
+
+  @Override
+  public boolean performClick() {
+    return super.performClick();
+  }
+
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    if (event.getAction() == MotionEvent.ACTION_DOWN) {
+      isPressed = true;
+      invalidate();
+      return true;
+    } else if (event.getAction() == MotionEvent.ACTION_UP) {
+      isPressed = false;
+      invalidate();
+      performClick();
+      return true;
+    }
+    return super.onTouchEvent(event);
+  }
+
+  @Override
+  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+    setMeasuredDimension((int) size, (int) size);
+  }
+
+  @Override
+  protected void onDraw(Canvas canvas) {
+    super.onDraw(canvas);
+    Paint backgroundPaint = isPressed ? circlePressedPaint : circlePaint;
+    canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, (getWidth() / 2f) - 1, backgroundPaint);
+    canvas.drawLine(x1, y1, x2, y2, linePaint);
+    canvas.drawLine(x2, y1, x1, y2, linePaint);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2017 Leanplum, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/README.md
@@ -0,0 +1,12 @@
+# Leanplum-Android-SDK
+## Installation & Usage
+Please refer to: https://www.leanplum.com/docs#/setup/android
+## Development Workflow
+- We are using GitFlow branching model: https://github.com/nvie/gitflow
+- We use the Conventional Changelog Commit Style for commit messages: https://github.com/commitizen/cz-cli
+## Contributing
+Please follow the Conventional Changelog Commit Style and send a pull request to `develop` branch.
+## License
+See LICENSE file.
+## Support
+Leanplum does not support custom modifications to the SDK, without an approved pull request (PR). If you wish to include your changes, please fork the repo and send a PR to the develop branch. After the PR has been reviewed and merged into develop, it will go into our regular release cycle, which includes QA. Once the release process has finished, the PR will be available in master and your changes are now officialy supported by Leanplum.
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+    repositories {
+        mavenCentral()
+        jcenter()
+    }
+    dependencies {
+        classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.4.12'
+        classpath 'com.android.tools.build:gradle:2.3.0'
+    }
+}
+
+allprojects {
+    repositories {
+        mavenCentral()
+        jcenter()
+        maven {
+            url "https://repo.leanplum.com/"
+        }
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
new file mode 100755
--- /dev/null
+++ b/mobile/android/leanplum/build.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+#
+# LPM | Author: Ben Marten
+# Copyright (c) 2017 Leanplum Inc. All rights reserved.
+#
+set -eo pipefail; [[ $DEBUG ]] && set -x
+
+# Check for Jenkins build number, otherwise default to curent time in seconds.
+if [[ -z "${BUILD_NUMBER+x}" ]]; then 
+  BUILD_NUMBER=$(date "+%s")
+fi
+export ANDROID_VERSION_STRING="$ANDROID_VERSION.$BUILD_NUMBER"
+
+for i in "$@"; do
+  case $i in
+    --upload)
+    upload=true
+    shift # past argument=value
+    ;;
+  esac
+done
+
+LEANPLUM_SDK_ROOT=${LEANPLUM_SDK_ROOT:-"$(pwd)/."}
+configuration="Release"
+default="${LEANPLUM_SDK_ROOT}"
+android_dir=${android_dir:-$default}
+default="${android_dir}/AndroidSDK"
+sdk_dir=${sdk_dir:-$default}
+release_dir="${android_dir}/Release"
+
+rm -rf "$release_dir"
+mkdir -p "$release_dir"
+
+# Build the AndroidSDK using gradle.
+rm -rf "${sdk_dir}/build"
+rm -rf "${sdk_dir}/javadoc"
+if [[ -z ${upload+x} ]]; then
+  GRADLE_TASK="assemble${configuration} makeJar generateJavadoc"
+else
+  GRADLE_TASK="assemble${configuration} makeJar generateJavadoc artifactoryPublish"
+fi
+
+cd "${sdk_dir}"
+# shellcheck disable=SC2086
+gradle $GRADLE_TASK
+
+mv "${sdk_dir}/javadoc" "${release_dir}/."
+cp "${sdk_dir}/build/intermediates/bundles/release/classes.jar" "${release_dir}/Leanplum.jar"
+
+echo "${GREEN} Done.${NORMAL}"
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Mar 03 11:12:57 PST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
new file mode 100755
--- /dev/null
+++ b/mobile/android/leanplum/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/local.properties
@@ -0,0 +1,12 @@
+## This file is automatically generated by Android Studio.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Thu May 11 17:01:15 PDT 2017
+ndk.dir=/Users/nevin/.android-sdk/ndk-bundle
+sdk.dir=/Users/nevin/.android-sdk
new file mode 100644
--- /dev/null
+++ b/mobile/android/leanplum/settings.gradle
@@ -0,0 +1,1 @@
+include ':AndroidSDK'
--- a/settings.gradle
+++ b/settings.gradle
@@ -23,17 +23,17 @@ if (json.substs.MOZ_BUILD_APP != 'mobile
 
 // Set the Android SDK location.  This is the *least specific* mechanism, which
 // is unfortunate: we'd prefer to use the *most specific* mechanism.  That is,
 // local.properties (first 'sdk.dir', then 'android.dir') and then the
 // environment variable ANDROID_HOME will override this.  That's unfortunate,
 // but it's hard to automatically arrange better.
 System.setProperty('android.home', json.substs.ANDROID_SDK_ROOT)
 
-include ':app'
+include ':app', ':leanplum'
 include ':geckoview'
 include ':geckoview_example'
 include ':omnijar'
 include ':thirdparty'
 
 project(':app').projectDir = new File("${json.topsrcdir}/mobile/android/app")
 project(':geckoview').projectDir = new File("${json.topsrcdir}/mobile/android/geckoview")
 project(':geckoview_example').projectDir = new File("${json.topsrcdir}/mobile/android/geckoview_example")
@@ -48,8 +48,9 @@ if (json.substs.MOZ_ANDROID_PACKAGE_INST
 // The Gradle instance is shared between settings.gradle and all the
 // other build.gradle files (see
 // http://forums.gradle.org/gradle/topics/define_extension_properties_from_settings_xml).
 // We use this ext property to pass the per-object-directory mozconfig
 // between scripts.  This lets us execute set-up code before we gradle
 // tries to configure the project even once, and as a side benefit
 // saves invoking |mach environment| multiple times.
 gradle.ext.mozconfig = json
+project(':leanplum').projectDir = new File('mobile/android/leanplum/AndroidSDK')
\ No newline at end of file