diff --git a/.gitignore b/.gitignore
index 17a7bd89..321c3a7b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,8 @@ Samples/Cordova/ExampleProject/plugins/clevertap-cordova/ExampleProject/platform
Samples/Cordova/ExampleProject/plugins/clevertap-cordova/ExampleProject/platforms/android/CordovaLib/build
Samples/Cordova/ExampleProject/plugins/clevertap-cordova/ExampleProject/platforms/ios/Pods
Samples/Cordova/ExampleProject/plugins/clevertap-cordova/ExampleProject/platforms/ios/Podfile.lock
+src/android/google-services.json
+Samples/Cordova/ExampleProject/platforms/android/app/src/main/google-services.json
Samples/IonicCapacitor/IonicCapReactProject/.project
Samples/IonicCapacitor/IonicCapReactProject/.idea
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28fd3cc7..c52b0a38 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,29 @@
Change Log
==========
+
+Version 3.2.0 *(August 12, 2024)*
+-------------------------------------------
+#### New Features
+**Android Specific**
+* Supports [CleverTap Android SDK v6.2.1](https://github.com/CleverTap/clevertap-android-sdk/releases/tag/corev6.2.1).
+* Supports Android 14, made it compliant with Android 14 requirements. Details [here](https://developer.android.com/about/versions/14/summary).
+* Extends the push primer callback to notify permission denial when cancel button is clicked on `PromptForSettings` alert dialog.
+* Adds Accessibility ids for UI components of SDK.
+* Migrates `JobScheduler` to `WorkManager` for [Pull Notifications](https://developer.clevertap.com/docs/android-push#pull-notification).
+
+#### Bug Fixes
+**Android Specific**
+* Fixes [#239](https://github.com/CleverTap/clevertap-cordova/issues/239), an issue where the `onPushNotification` callback was not triggered when notification was tapped from the `killed` state on `capacitor` apps.
+* Fixes InApps crash in a rare activity destroyed race condition.
+* Fixes Potential ANR in a race condition of SDK initialisation in multithreaded setup.
+* Fixes a bug in Client Side InApps with regards to frequency limits.
+* Fixes a crash due to `NullPointerException` related to `deviceInfo.deviceId`.
+* Fixes an ANR related to `isMainProcess` check.
+* Fixes an ANR due to eager initialisation of `CtApi` triggered by DeviceId generation.
+
+#### Breaking API Changes
+* Removes all `Xiaomi` related public methods as the `Xiaomi` SDK has been discontinued. Details [here](https://developer.clevertap.com/docs/discontinuation-of-xiaomi-push-service).
+
Version 3.1.0 *(April 27, 2024)*
-------------------------------------------
#### New Features
diff --git a/README.md b/README.md
index f4acb332..709bae99 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ To get started, sign up [here](https://clevertap.com/live-product-demo/).
## ✅ Supported Versions
-- [CleverTap Android SDK version 6.0.0](https://github.com/CleverTap/clevertap-android-sdk/releases/tag/corev6.0.0_ptv1.2.2)
+- [CleverTap Android SDK version 6.2.1](https://github.com/CleverTap/clevertap-android-sdk/releases/tag/corev6.2.1)
- [CleverTap iOS SDK version 6.2.1](https://github.com/CleverTap/clevertap-ios-sdk/releases/tag/6.2.1)
## 🚀 Installation and Quick Start
diff --git a/Samples/Cordova/ExampleProject/package.json b/Samples/Cordova/ExampleProject/package.json
index 66a13c2d..1c51dbf6 100644
--- a/Samples/Cordova/ExampleProject/package.json
+++ b/Samples/Cordova/ExampleProject/package.json
@@ -14,7 +14,7 @@
"license": "Apache-2.0",
"devDependencies": {
"clevertap-cordova": "file:../../..",
- "cordova-android": "^12.0.1",
+ "cordova-android": "^13.0.0",
"cordova-android-support-gradle-release": "^3.0.1",
"cordova-ios": "^7.0.0",
"ios": "0.0.1"
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/AndroidManifest.xml b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/AndroidManifest.xml
index 320c2538..77a4bf7a 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/AndroidManifest.xml
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/AndroidManifest.xml
@@ -18,5 +18,6 @@
under the License.
-->
+ android:versionName="1.0"
+ android:versionCode="1">
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/build.gradle b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/build.gradle
index 8fcf4b59..02ea7e8f 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/build.gradle
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/build.gradle
@@ -44,12 +44,14 @@ allprojects {
apply plugin: 'com.android.library'
android {
+ namespace 'org.apache.cordova'
+
compileSdkVersion cordovaConfig.COMPILE_SDK_VERSION
buildToolsVersion cordovaConfig.BUILD_TOOLS_VERSION
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaLanguageVersion.of(cordovaConfig.JAVA_SOURCE_COMPATIBILITY)
+ targetCompatibility JavaLanguageVersion.of(cordovaConfig.JAVA_TARGET_COMPATIBILITY)
}
// For the Android Cordova Lib, we allow changing the minSdkVersion, but it is at the users own risk
@@ -75,10 +77,16 @@ android {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
}
+
+ publishing {
+ singleVariant('release') {
+ withSourcesJar()
+ }
+ }
}
dependencies {
- implementation "androidx.appcompat:appcompat:${cordovaConfig.ANDROIDX_APP_COMPAT_VERSION}"
+ api "androidx.appcompat:appcompat:${cordovaConfig.ANDROIDX_APP_COMPAT_VERSION}"
implementation "androidx.webkit:webkit:${cordovaConfig.ANDROIDX_WEBKIT_VERSION}"
implementation "androidx.core:core-splashscreen:${cordovaConfig.ANDROIDX_CORE_SPLASHSCREEN_VERSION}"
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/cordova.gradle b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/cordova.gradle
index 427cfc23..9b978398 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/cordova.gradle
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/cordova.gradle
@@ -43,6 +43,10 @@ Boolean isVersionValid(version) {
return !(new Version(version)).isEqual('0.0.0')
}
+Boolean isVersionGreaterThanEqual(versionX, versionY) {
+ return (new Version(versionX)) >= (new Version(versionY))
+}
+
String doFindLatestInstalledBuildTools(String minBuildToolsVersionString) {
def buildToolsDirContents
try {
@@ -83,9 +87,9 @@ String doFindLatestInstalledBuildTools(String minBuildToolsVersionString) {
String getAndroidSdkDir() {
def rootDir = project.rootDir
def androidSdkDir = null
- String envVar = System.getenv("ANDROID_SDK_ROOT")
+ String envVar = System.getenv("ANDROID_HOME")
if (envVar == null) {
- envVar = System.getenv("ANDROID_HOME")
+ envVar = System.getenv("ANDROID_SDK_ROOT")
}
def localProperties = new File(rootDir, 'local.properties')
@@ -125,14 +129,6 @@ def doExtractIntFromManifest(name) {
return new BigInteger(matcher.group(1))
}
-def doExtractStringFromManifest(name) {
- def manifestFile = file(android.sourceSets.main.manifest.srcFile)
- def pattern = Pattern.compile(name + "=\"(\\S+)\"")
- def matcher = pattern.matcher(manifestFile.getText())
- matcher.find()
- return matcher.group(1)
-}
-
def doGetConfigXml() {
def xml = file("src/main/res/xml/config.xml").getText()
// Disable namespace awareness since Cordova doesn't use them properly
@@ -231,7 +227,6 @@ ext {
privateHelpers.getProjectTarget = { doGetProjectTarget() }
privateHelpers.applyCordovaConfigCustomization = { doApplyCordovaConfigCustomization() }
privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) }
- privateHelpers.extractStringFromManifest = { name -> doExtractStringFromManifest(name) }
privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) }
// These helpers can be used by plugins / projects and will not change.
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/project.properties b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/project.properties
index f8d807d5..029b9d28 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/project.properties
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/project.properties
@@ -1,3 +1,20 @@
+# 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.
+
# GENERATED FILE! DO NOT EDIT!
# This file was originally created by the Android Tools, but is now
@@ -10,4 +27,4 @@ split.density=false
apk-configurations=
renderscript.opt.level=O0
android.library=true
-target=android-32
\ No newline at end of file
+target=android-34
\ No newline at end of file
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/BuildHelper.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/BuildHelper.java
index 94fe9612..2899ee2a 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/BuildHelper.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/BuildHelper.java
@@ -51,7 +51,8 @@ public static Object getBuildConfigValue(Context ctx, String key)
{
try
{
- Class> clazz = Class.forName(ctx.getClass().getPackage().getName() + ".BuildConfig");
+ String packageName = ctx.getApplicationInfo().packageName;
+ Class> clazz = Class.forName(packageName + ".BuildConfig");
Field field = clazz.getField(key);
return field.get(null);
} catch (ClassNotFoundException e) {
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java
index ca3cbdaa..0b92e96b 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java
@@ -34,6 +34,7 @@ public class ConfigXmlParser {
private static String SCHEME_HTTP = "http";
private static String SCHEME_HTTPS = "https";
private static String DEFAULT_HOSTNAME = "localhost";
+ private static final String DEFAULT_CONTENT_SRC = "index.html";
private String launchUrl;
private String contentSrc;
@@ -110,6 +111,18 @@ else if (eventType == XmlPullParser.END_TAG)
e.printStackTrace();
}
}
+
+ onPostParse();
+ }
+
+ private void onPostParse() {
+ // After parsing, if contentSrc is still null, it signals
+ // that tag was completely missing. In this case,
+ // default it.
+ // https://github.com/apache/cordova-android/issues/1432
+ if (contentSrc == null) {
+ contentSrc = DEFAULT_CONTENT_SRC;
+ }
}
public void handleStartTag(XmlPullParser xml) {
@@ -140,7 +153,7 @@ else if (strNode.equals("content")) {
contentSrc = src;
} else {
// Default
- contentSrc = "index.html";
+ contentSrc = DEFAULT_CONTENT_SRC;
}
}
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java
index ef6ae5e5..325e9e9d 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java
@@ -391,6 +391,7 @@ public void onReceivedError(final int errorCode, final String description, final
if ((errorUrl != null) && (!failingUrl.equals(errorUrl)) && (appView != null)) {
// Load URL on UI thread
me.runOnUiThread(new Runnable() {
+ @Override
public void run() {
me.appView.showWebPage(errorUrl, false, true, null);
}
@@ -400,6 +401,7 @@ public void run() {
else {
final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);
me.runOnUiThread(new Runnable() {
+ @Override
public void run() {
if (exit) {
me.appView.getView().setVisibility(View.GONE);
@@ -416,6 +418,7 @@ public void run() {
public void displayError(final String title, final String message, final String button, final boolean exit) {
final CordovaActivity me = this;
me.runOnUiThread(new Runnable() {
+ @Override
public void run() {
try {
AlertDialog.Builder dlg = new AlertDialog.Builder(me);
@@ -424,6 +427,7 @@ public void run() {
dlg.setCancelable(false);
dlg.setPositiveButton(button,
new AlertDialog.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (exit) {
@@ -488,6 +492,7 @@ public Object onMessage(String id, Object data) {
return null;
}
+ @Override
protected void onSaveInstanceState(Bundle outState) {
cordovaInterface.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java
index ad7c588a..a7889341 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java
@@ -41,6 +41,7 @@ public CordovaClientCertRequest(ClientCertRequest request) {
* Cancel this request
*/
@SuppressLint("NewApi")
+ @Override
public void cancel()
{
request.cancel();
@@ -50,6 +51,7 @@ public void cancel()
* Returns the host name of the server requesting the certificate.
*/
@SuppressLint("NewApi")
+ @Override
public String getHost()
{
return request.getHost();
@@ -59,6 +61,7 @@ public String getHost()
* Returns the acceptable types of asymmetric keys (can be null).
*/
@SuppressLint("NewApi")
+ @Override
public String[] getKeyTypes()
{
return request.getKeyTypes();
@@ -68,6 +71,7 @@ public String[] getKeyTypes()
* Returns the port number of the server requesting the certificate.
*/
@SuppressLint("NewApi")
+ @Override
public int getPort()
{
return request.getPort();
@@ -77,6 +81,7 @@ public int getPort()
* Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
*/
@SuppressLint("NewApi")
+ @Override
public Principal[] getPrincipals()
{
return request.getPrincipals();
@@ -86,6 +91,7 @@ public Principal[] getPrincipals()
* Ignore the request for now. Do not remember user's choice.
*/
@SuppressLint("NewApi")
+ @Override
public void ignore()
{
request.ignore();
@@ -98,6 +104,7 @@ public void ignore()
* @param chain The certificate chain
*/
@SuppressLint("NewApi")
+ @Override
public void proceed(PrivateKey privateKey, X509Certificate[] chain)
{
request.proceed(privateKey, chain);
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java
index a219c992..a4c7ceb7 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java
@@ -43,18 +43,21 @@ public void showAlert(String message, final Result result) {
dlg.setCancelable(true);
dlg.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
result.gotResult(true, null);
}
});
dlg.setOnCancelListener(
new DialogInterface.OnCancelListener() {
+ @Override
public void onCancel(DialogInterface dialog) {
result.gotResult(false, null);
}
});
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
//DO NOTHING
+ @Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK)
{
@@ -75,24 +78,28 @@ public void showConfirm(String message, final Result result) {
dlg.setCancelable(true);
dlg.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
result.gotResult(true, null);
}
});
dlg.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
result.gotResult(false, null);
}
});
dlg.setOnCancelListener(
new DialogInterface.OnCancelListener() {
+ @Override
public void onCancel(DialogInterface dialog) {
result.gotResult(false, null);
}
});
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
//DO NOTHING
+ @Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK)
{
@@ -126,6 +133,7 @@ public void showPrompt(String message, String defaultValue, final Result result)
dlg.setCancelable(false);
dlg.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
String userText = input.getText().toString();
result.gotResult(true, userText);
@@ -133,6 +141,7 @@ public void onClick(DialogInterface dialog, int which) {
});
dlg.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
result.gotResult(false, null);
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java
index a2692f8c..aecf200c 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java
@@ -35,6 +35,7 @@ public CordovaHttpAuthHandler(HttpAuthHandler handler) {
/**
* Instructs the WebView to cancel the authentication request.
*/
+ @Override
public void cancel () {
this.handler.cancel();
}
@@ -45,6 +46,7 @@ public void cancel () {
* @param username
* @param password
*/
+ @Override
public void proceed (String username, String password) {
this.handler.proceed(username, password);
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java
index 84e2c0a4..649dd573 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java
@@ -223,28 +223,23 @@ public void onRequestPermissionResult(int requestCode, String[] permissions,
}
}
+ @Override
public void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
String[] permissions = new String [1];
permissions[0] = permission;
requestPermissions(plugin, requestCode, permissions);
}
- @SuppressLint("NewApi")
+ @SuppressLint("NewApi")
+ @Override
public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) {
int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode);
getActivity().requestPermissions(permissions, mappedRequestCode);
}
+ @Override
public boolean hasPermission(String permission)
{
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
- {
- int result = activity.checkSelfPermission(permission);
- return PackageManager.PERMISSION_GRANTED == result;
- }
- else
- {
- return true;
- }
+ return PackageManager.PERMISSION_GRANTED == activity.checkSelfPermission(permission);
}
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java
index 38e2e4af..1140c4af 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java
@@ -31,6 +31,8 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.webkit.RenderProcessGoneDetail;
+import android.webkit.WebView;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -442,4 +444,19 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions,
public CordovaPluginPathHandler getPathHandler() {
return null;
}
+
+ /**
+ * Called when the WebView's render process has exited. Can be used to collect information regarding the crash for crashlytics or optionally attempt to gracefully handle/recover the crashed webview by recreating it.
+ *
+ * See WebViewClient#onRenderProcessGone
+ *
+ * Note: A plugin must not attempt to recover a webview that it does not own/manage.
+ *
+ * @return true if the host application handled the situation that process has exited,
+ * otherwise, application will crash if render process crashed, or be killed
+ * if render process was killed by the system.
+ */
+ public boolean onRenderProcessGone(final WebView view, RenderProcessGoneDetail detail) {
+ return false;
+ }
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java
index c7f119ab..ed277882 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java
@@ -31,7 +31,7 @@ Licensed to the Apache Software Foundation (ASF) under one
* are not expected to implement it.
*/
public interface CordovaWebView {
- public static final String CORDOVA_VERSION = "11.0.0";
+ public static final String CORDOVA_VERSION = "13.0.0";
void init(CordovaInterface cordova, List pluginEntries, CordovaPreferences preferences);
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java
index 2b8a8f89..4d5221e2 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java
@@ -115,7 +115,7 @@ public void init(CordovaInterface cordova, List pluginEntries, Cord
// This isn't enforced by the compiler, so assert here.
assert engine.getView() instanceof CordovaWebViewEngine.EngineView;
- pluginManager.addService(CoreAndroid.PLUGIN_NAME, "org.apache.cordova.CoreAndroid");
+ pluginManager.addService(CoreAndroid.PLUGIN_NAME, "org.apache.cordova.CoreAndroid", true);
pluginManager.init();
}
@@ -149,6 +149,7 @@ public void loadUrlIntoView(final String url, boolean recreatePlugins) {
// Timeout error method
final Runnable loadError = new Runnable() {
+ @Override
public void run() {
stopLoading();
LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
@@ -168,6 +169,7 @@ public void run() {
// Timeout timer method
final Runnable timeoutCheck = new Runnable() {
+ @Override
public void run() {
try {
synchronized (this) {
@@ -189,6 +191,7 @@ public void run() {
if (cordova.getActivity() != null) {
final boolean _recreatePlugins = recreatePlugins;
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
if (loadUrlTimeoutValue > 0) {
cordova.getThreadPool().execute(timeoutCheck);
@@ -579,11 +582,13 @@ public void onPageFinishedLoading(String url) {
// Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly
if (engine.getView().getVisibility() != View.VISIBLE) {
Thread t = new Thread(new Runnable() {
+ @Override
public void run() {
try {
Thread.sleep(2000);
if (cordova.getActivity() != null) {
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
pluginManager.postMessage("spinner", "stop");
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java
index 6ebdecb3..36b28b2d 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java
@@ -19,6 +19,8 @@ Licensed to the Apache Software Foundation (ASF) under one
package org.apache.cordova;
+import org.apache.cordova.BuildHelper;
+
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -30,7 +32,6 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
-import java.lang.reflect.Field;
import java.util.HashMap;
/**
@@ -72,6 +73,7 @@ public void pluginInitialize() {
* @param callbackContext The callback context from which we were invoked.
* @return A PluginResult object with a status and message.
*/
+ @Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
@@ -85,6 +87,7 @@ else if (action.equals("show")) {
// I recommend we change the name of the Message as spinner/stop is not
// indicative of what this actually does (shows the webview).
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
webView.getPluginManager().postMessage("spinner", "stop");
}
@@ -143,6 +146,7 @@ else if (action.equals("messageChannel")) {
*/
public void clearCache() {
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
webView.clearCache();
}
@@ -214,6 +218,7 @@ else if (value.getClass().equals(Integer.class)) {
*/
public void clearHistory() {
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
webView.clearHistory();
}
@@ -226,6 +231,7 @@ public void run() {
*/
public void backHistory() {
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
webView.backHistory();
}
@@ -352,6 +358,7 @@ private void sendEventMessage(PluginResult payload) {
* Unregister the receiver
*
*/
+ @Override
public void onDestroy()
{
webView.getContext().unregisterReceiver(this.telephonyReceiver);
@@ -376,35 +383,19 @@ public void sendResumeEvent(PluginResult resumeEvent) {
}
}
- /*
+ /*
* This needs to be implemented if you wish to use the Camera Plugin or other plugins
* that read the Build Configuration.
*
* Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to
* StackOverflow. This is annoying as hell!
*
+ * @deprecated Use {@link BuildHelper#getBuildConfigValue} instead.
*/
-
+ @Deprecated
public static Object getBuildConfigValue(Context ctx, String key)
{
- try
- {
- Class> clazz = Class.forName(ctx.getClass().getPackage().getName() + ".BuildConfig");
- Field field = clazz.getField(key);
- return field.get(null);
- } catch (ClassNotFoundException e) {
- LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?");
- e.printStackTrace();
- } catch (NoSuchFieldException e) {
- LOG.d(TAG, key + " is not a valid field. Check your build.gradle");
- } catch (IllegalAccessException e) {
- LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace.");
- e.printStackTrace();
- } catch (NullPointerException e) {
- LOG.d(TAG, "Null Pointer Exception: Let's print a stack trace.");
- e.printStackTrace();
- }
-
- return null;
+ LOG.w(TAG, "CoreAndroid.getBuildConfigValue is deprecated and will be removed in a future release. Use BuildHelper.getBuildConfigValue instead.");
+ return BuildHelper.getBuildConfigValue(ctx, key);
}
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java
index 311ba444..6e6f2a73 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -302,6 +302,7 @@ public LoadUrlBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova)
@Override
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
String js = queue.popAndEncodeAsJs();
if (js != null) {
@@ -330,6 +331,7 @@ public OnlineEventsBridgeMode(OnlineEventsBridgeModeDelegate delegate) {
@Override
public void reset() {
delegate.runOnUiThread(new Runnable() {
+ @Override
public void run() {
online = false;
// If the following call triggers a notifyOfFlush, then ignore it.
@@ -342,6 +344,7 @@ public void run() {
@Override
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
delegate.runOnUiThread(new Runnable() {
+ @Override
public void run() {
if (!queue.isEmpty()) {
ignoreNextFlush = false;
@@ -372,6 +375,7 @@ public EvalBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) {
@Override
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
public void run() {
String js = queue.popAndEncodeAsJs();
if (js != null) {
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java
index 05029937..255eacd0 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java
@@ -32,6 +32,8 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.os.Bundle;
import android.os.Debug;
import android.os.Build;
+import android.webkit.RenderProcessGoneDetail;
+import android.webkit.WebView;
/**
* PluginManager is exposed to JavaScript in the Cordova WebView.
@@ -197,7 +199,18 @@ public CordovaPlugin getPlugin(String service) {
* @param className The plugin class name
*/
public void addService(String service, String className) {
- PluginEntry entry = new PluginEntry(service, className, false);
+ addService(service, className, false);
+ }
+
+ /**
+ * Add a plugin class that implements a service to the service entry table.
+ *
+ * @param service The service name
+ * @param className The plugin class name
+ * @param onload If true, the plugin will be instantiated immediately
+ */
+ public void addService(String service, String className, boolean onload) {
+ PluginEntry entry = new PluginEntry(service, className, onload);
this.addService(entry);
}
@@ -339,22 +352,11 @@ public void onDestroy() {
public Object postMessage(String id, Object data) {
LOG.d(TAG, "postMessage: " + id);
synchronized (this.pluginMap) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.pluginMap.forEach((s, plugin) -> {
- if (plugin != null) {
- plugin.onMessage(id, data);
- }
- });
- } else {
- for (CordovaPlugin plugin : this.pluginMap.values()) {
- if (plugin != null) {
- Object obj = plugin.onMessage(id, data);
- if (obj != null) {
- return obj;
- }
- }
+ this.pluginMap.forEach((s, plugin) -> {
+ if (plugin != null) {
+ plugin.onMessage(id, data);
}
- }
+ });
}
return ctx.onMessage(id, data);
}
@@ -617,4 +619,29 @@ public ArrayList getPluginPathHandlers() {
}
return handlers;
}
+
+ /**
+ * Called when the WebView's render process has exited.
+ *
+ * See https://developer.android.com/reference/android/webkit/WebViewClient#onRenderProcessGone(android.webkit.WebView,%20android.webkit.RenderProcessGoneDetail)
+ *
+ * @return true if the host application handled the situation that process has exited,
+ * otherwise, application will crash if render process crashed, or be killed
+ * if render process was killed by the system.
+ */
+ public boolean onRenderProcessGone(final WebView view, RenderProcessGoneDetail detail) {
+ boolean result = false;
+ synchronized (this.entryMap) {
+ for (PluginEntry entry : this.entryMap.values()) {
+ CordovaPlugin plugin = pluginMap.get(entry.service);
+ if (plugin != null) {
+ if (plugin.onRenderProcessGone(view, detail)) {
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/SplashScreenPlugin.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/SplashScreenPlugin.java
index 79b2bc2a..425b13f9 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/SplashScreenPlugin.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/SplashScreenPlugin.java
@@ -127,7 +127,7 @@ private void setupSplashScreen(SplashScreen splashScreen) {
// auto hide splash screen when custom delay is defined.
if (autoHide && delayTime != DEFAULT_DELAY_TIME) {
- Handler splashScreenDelayHandler = new Handler();
+ Handler splashScreenDelayHandler = new Handler(cordova.getContext().getMainLooper());
splashScreenDelayHandler.postDelayed(() -> keepOnScreen = false, delayTime);
}
@@ -137,27 +137,29 @@ private void setupSplashScreen(SplashScreen splashScreen) {
// If auto hide is disabled (false), the hiding of the splash screen must be determined &
// triggered by the front-end code with the `navigator.splashscreen.hide()` method.
- // Setup the fade
- splashScreen.setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
- @Override
- public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenViewProvider) {
- View splashScreenView = splashScreenViewProvider.getView();
-
- splashScreenView
- .animate()
- .alpha(0.0f)
- .setDuration(isFadeEnabled ? fadeDuration : 0)
- .setStartDelay(isFadeEnabled ? 0 : fadeDuration)
- .setInterpolator(new AccelerateInterpolator())
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- splashScreenViewProvider.remove();
- }
- }).start();
- }
- });
+ if (isFadeEnabled) {
+ // Setup the fade
+ splashScreen.setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
+ @Override
+ public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenViewProvider) {
+ View splashScreenView = splashScreenViewProvider.getView();
+
+ splashScreenView
+ .animate()
+ .alpha(0.0f)
+ .setDuration(fadeDuration)
+ .setStartDelay(0)
+ .setInterpolator(new AccelerateInterpolator())
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ splashScreenViewProvider.remove();
+ }
+ }).start();
+ }
+ });
+ }
}
private void attemptCloseOnPageFinished() {
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java
index bc980356..16cf5482 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java
@@ -41,22 +41,27 @@ public void setAcceptFileSchemeCookies() {
cookieManager.setAcceptFileSchemeCookies(true);
}
+ @Override
public void setCookiesEnabled(boolean accept) {
cookieManager.setAcceptCookie(accept);
}
+ @Override
public void setCookie(final String url, final String value) {
cookieManager.setCookie(url, value);
}
+ @Override
public String getCookie(final String url) {
return cookieManager.getCookie(url);
}
+ @Override
public void clearCookies() {
cookieManager.removeAllCookies(null);
}
+ @Override
public void flush() {
cookieManager.flush();
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java
index 94c3d934..c37d4558 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java
@@ -37,16 +37,19 @@ class SystemExposedJsApi implements ExposedJsApi {
}
@JavascriptInterface
+ @Override
public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
}
@JavascriptInterface
+ @Override
public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
}
@JavascriptInterface
+ @Override
public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java
index cad098e4..8a48e351 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java
@@ -18,18 +18,22 @@ Licensed to the Apache Software Foundation (ASF) under one
*/
package org.apache.cordova.engine;
+import java.io.IOException;
+import java.io.File;
import java.util.Arrays;
-import android.annotation.TargetApi;
+import java.util.ArrayList;
+import java.util.List;
import android.app.Activity;
+import android.content.ClipData;
import android.content.Context;
import android.content.ActivityNotFoundException;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.Uri;
-import android.os.Build;
+import android.provider.MediaStore;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
-import android.webkit.ConsoleMessage;
import android.webkit.GeolocationPermissions.Callback;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
@@ -41,6 +45,7 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
+import androidx.core.content.FileProvider;
import org.apache.cordova.CordovaDialogsHelper;
import org.apache.cordova.CordovaPlugin;
@@ -212,52 +217,110 @@ public View getVideoLoadingProgressView() {
}
@Override
- public boolean onShowFileChooser(WebView webView, final ValueCallback filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
+ public boolean onShowFileChooser(WebView webView, final ValueCallback filePathsCallback,
+ final WebChromeClient.FileChooserParams fileChooserParams) {
+ Intent fileIntent = fileChooserParams.createIntent();
+
// Check if multiple-select is specified
Boolean selectMultiple = false;
if (fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE) {
selectMultiple = true;
}
- Intent intent = fileChooserParams.createIntent();
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, selectMultiple);
-
+ fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, selectMultiple);
+
// Uses Intent.EXTRA_MIME_TYPES to pass multiple mime types.
String[] acceptTypes = fileChooserParams.getAcceptTypes();
if (acceptTypes.length > 1) {
- intent.setType("*/*"); // Accept all, filter mime types by Intent.EXTRA_MIME_TYPES.
- intent.putExtra(Intent.EXTRA_MIME_TYPES, acceptTypes);
+ fileIntent.setType("*/*"); // Accept all, filter mime types by Intent.EXTRA_MIME_TYPES.
+ fileIntent.putExtra(Intent.EXTRA_MIME_TYPES, acceptTypes);
+ }
+
+ // Image from camera intent
+ Uri tempUri = null;
+ Intent captureIntent = null;
+ if (fileChooserParams.isCaptureEnabled()) {
+ captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ Context context = parentEngine.getView().getContext();
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
+ && captureIntent.resolveActivity(context.getPackageManager()) != null) {
+ try {
+ File tempFile = createTempFile(context);
+ LOG.d(LOG_TAG, "Temporary photo capture file: " + tempFile);
+ tempUri = createUriForFile(context, tempFile);
+ LOG.d(LOG_TAG, "Temporary photo capture URI: " + tempUri);
+ captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempUri);
+ } catch (IOException e) {
+ LOG.e(LOG_TAG, "Unable to create temporary file for photo capture", e);
+ captureIntent = null;
+ }
+ } else {
+ LOG.w(LOG_TAG, "Device does not support photo capture");
+ captureIntent = null;
+ }
+ }
+ final Uri captureUri = tempUri;
+
+ // Chooser intent
+ Intent chooserIntent = Intent.createChooser(fileIntent, null);
+ if (captureIntent != null) {
+ chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { captureIntent });
}
+
try {
+ LOG.i(LOG_TAG, "Starting intent for file chooser");
parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ // Handle result
Uri[] result = null;
- if (resultCode == Activity.RESULT_OK && intent != null) {
- if (intent.getClipData() != null) {
- // handle multiple-selected files
- final int numSelectedFiles = intent.getClipData().getItemCount();
- result = new Uri[numSelectedFiles];
- for (int i = 0; i < numSelectedFiles; i++) {
- result[i] = intent.getClipData().getItemAt(i).getUri();
- LOG.d(LOG_TAG, "Receive file chooser URL: " + result[i]);
+ if (resultCode == Activity.RESULT_OK) {
+ List uris = new ArrayList();
+
+ if (intent != null && intent.getData() != null) { // single file
+ LOG.v(LOG_TAG, "Adding file (single): " + intent.getData());
+ uris.add(intent.getData());
+ } else if (captureUri != null) { // camera
+ LOG.v(LOG_TAG, "Adding camera capture: " + captureUri);
+ uris.add(captureUri);
+ } else if (intent != null && intent.getClipData() != null) { // multiple files
+ ClipData clipData = intent.getClipData();
+ int count = clipData.getItemCount();
+ for (int i = 0; i < count; i++) {
+ Uri uri = clipData.getItemAt(i).getUri();
+ LOG.v(LOG_TAG, "Adding file (multiple): " + uri);
+ if (uri != null) {
+ uris.add(uri);
+ }
}
}
- else if (intent.getData() != null) {
- // handle single-selected file
- result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);
- LOG.d(LOG_TAG, "Receive file chooser URL: " + result);
+
+ if (!uris.isEmpty()) {
+ LOG.d(LOG_TAG, "Receive file chooser URL: " + uris.toString());
+ result = uris.toArray(new Uri[uris.size()]);
}
}
filePathsCallback.onReceiveValue(result);
}
- }, intent, FILECHOOSER_RESULTCODE);
+ }, chooserIntent, FILECHOOSER_RESULTCODE);
} catch (ActivityNotFoundException e) {
- LOG.w("No activity found to handle file chooser intent.", e);
+ LOG.w(LOG_TAG, "No activity found to handle file chooser intent.", e);
filePathsCallback.onReceiveValue(null);
}
return true;
}
+ private File createTempFile(Context context) throws IOException {
+ // Create an image file name
+ File tempFile = File.createTempFile("temp", ".jpg", context.getCacheDir());
+ return tempFile;
+ }
+
+ private Uri createUriForFile(Context context, File tempFile) throws IOException {
+ String appId = context.getPackageName();
+ Uri uri = FileProvider.getUriForFile(context, appId + ".cdv.core.file.provider", tempFile);
+ return uri;
+ }
+
@Override
public void onPermissionRequest(final PermissionRequest request) {
LOG.d(LOG_TAG, "onPermissionRequest: " + Arrays.toString(request.getResources()));
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java
index 05400417..fd719f09 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java
@@ -28,6 +28,9 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.webkit.ClientCertRequest;
import android.webkit.HttpAuthHandler;
import android.webkit.MimeTypeMap;
+import android.webkit.RenderProcessGoneDetail;
+import android.webkit.ServiceWorkerClient;
+import android.webkit.ServiceWorkerController;
import android.webkit.SslErrorHandler;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
@@ -115,6 +118,18 @@ public SystemWebViewClient(SystemWebViewEngine parentEngine) {
});
this.assetLoader = assetLoaderBuilder.build();
+ boolean setAsServiceWorkerClient = parentEngine.preferences.getBoolean("ResolveServiceWorkerRequests", true);
+ ServiceWorkerController controller = null;
+
+ if (setAsServiceWorkerClient) {
+ controller = ServiceWorkerController.getInstance();
+ controller.setServiceWorkerClient(new ServiceWorkerClient(){
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+ return assetLoader.shouldInterceptRequest(request.getUrl());
+ }
+ });
+ }
}
/**
@@ -422,4 +437,15 @@ private static boolean needsSpecialsInAssetUrlFix(Uri uri) {
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return this.assetLoader.shouldInterceptRequest(request.getUrl());
}
+
+ @Override
+ public boolean onRenderProcessGone(final WebView view, RenderProcessGoneDetail detail) {
+ // Check if there is some plugin which can handle this event
+ PluginManager pluginManager = this.parentEngine.pluginManager;
+ if (pluginManager != null && pluginManager.onRenderProcessGone(view, detail)) {
+ return true;
+ }
+
+ return super.onRenderProcessGone(view, detail);
+ }
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java
index 5ff1abff..cbe727cd 100755
--- a/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java
+++ b/Samples/Cordova/ExampleProject/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java
@@ -175,9 +175,20 @@ private void initWebViewSettings() {
String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setDatabaseEnabled(true);
- //Determine whether we're in debug or release mode, and turn on Debugging!
- ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo();
- if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ // The default is to use the module's debuggable state to decide if the webview inspecter
+ // should be enabled. However, users can configure InspectableWebview preference to forcefully enable
+ // or disable the webview inspecter.
+ String inspectableWebview = preferences.getString("InspectableWebview", null);
+ boolean shouldEnableInspector = false;
+ if (inspectableWebview == null) {
+ ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo();
+ shouldEnableInspector = (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ }
+ else if ("true".equals(inspectableWebview)) {
+ shouldEnableInspector = true;
+ }
+
+ if (shouldEnableInspector) {
enableRemoteDebugging();
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/android.json b/Samples/Cordova/ExampleProject/platforms/android/android.json
index c1fcee40..c9641c43 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/android.json
+++ b/Samples/Cordova/ExampleProject/platforms/android/android.json
@@ -49,7 +49,7 @@
"count": 1
},
{
- "xml": "",
+ "xml": "",
"count": 1
},
{
@@ -62,14 +62,10 @@
}
},
"installed_plugins": {
- "cordova-android-support-gradle-release": {
- "ANDROID_SUPPORT_VERSION": "27.+",
- "PACKAGE_NAME": "com.clevertap.example"
- },
"clevertap-cordova": {
"CLEVERTAP_ACCOUNT_ID": "67Z-RRK-696Z",
"CLEVERTAP_TOKEN": "322-1a6",
- "CLEVERTAP_REGION": " ",
+ "CLEVERTAP_REGION": "sk1-staging-25",
"FIREBASE_MESSAGING_VERSION": "23.0.6",
"PACKAGE_NAME": "com.clevertap.example"
}
@@ -86,7 +82,6 @@
}
],
"plugin_metadata": {
- "cordova-android-support-gradle-release": "3.0.1",
- "clevertap-cordova": "3.0.0"
+ "clevertap-cordova": "3.2.0"
}
}
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/build.gradle b/Samples/Cordova/ExampleProject/platforms/android/app/build.gradle
index ec419d78..94d0cf51 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/app/build.gradle
+++ b/Samples/Cordova/ExampleProject/platforms/android/app/build.gradle
@@ -21,7 +21,11 @@ apply plugin: 'com.android.application'
if (cordovaConfig.IS_GRADLE_PLUGIN_KOTLIN_ENABLED) {
apply plugin: 'kotlin-android'
- apply plugin: 'kotlin-android-extensions'
+
+ if(!cdvHelpers.isVersionGreaterThanEqual(cordovaConfig.KOTLIN_VERSION, '1.8.0')) {
+ println "Kotlin version < 1.8.0 detected. Applying kotlin-android-extensions plugin."
+ apply plugin: 'kotlin-android-extensions'
+ }
}
buildscript {
@@ -109,7 +113,6 @@ ext {
}
// PLUGIN GRADLE EXTENSIONS START
-apply from: "../cordova-android-support-gradle-release/example-cordova-android-support-gradle-release.gradle"
// PLUGIN GRADLE EXTENSIONS END
def hasBuildExtras1 = file('build-extras.gradle').exists()
@@ -180,9 +183,15 @@ task cdvPrintProps {
}
android {
+ namespace cordovaConfig.PACKAGE_NAMESPACE
+
+ buildFeatures {
+ buildConfig true
+ }
+
defaultConfig {
versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
- applicationId privateHelpers.extractStringFromManifest("package")
+ applicationId cordovaConfig.PACKAGE_NAMESPACE
minSdkVersion cordovaConfig.MIN_SDK_VERSION
if (cordovaConfig.MAX_SDK_VERSION != null) {
@@ -247,8 +256,39 @@ android {
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaLanguageVersion.of(cordovaConfig.JAVA_SOURCE_COMPATIBILITY)
+ targetCompatibility JavaLanguageVersion.of(cordovaConfig.JAVA_TARGET_COMPATIBILITY)
+ }
+
+ if (cordovaConfig.IS_GRADLE_PLUGIN_KOTLIN_ENABLED) {
+ if (cordovaConfig.KOTLIN_JVM_TARGET == null) {
+ // If the value is null, fallback to JAVA_TARGET_COMPATIBILITY,
+ // as they generally should be equal
+ def javaTarget = JavaLanguageVersion.of(cordovaConfig.JAVA_TARGET_COMPATIBILITY)
+
+ // check if javaTarget is <= 8; if so, we need to prefix it with "1."
+ // Starting with 9 and later, the value can be used as is.
+ if (javaTarget.compareTo(JavaLanguageVersion.of(8)) <= 0) {
+ javaTarget = "1." + javaTarget
+ }
+
+ cordovaConfig.KOTLIN_JVM_TARGET = javaTarget
+ }
+
+ // Similar to above, check if kotlin target is <= 8, if so prefix it.
+ // This allows the user to use consistent set of values in config.xml
+ // Rather than having to be aware whether the "1."" prefix is needed.
+ // This check is only done if the value isn't already prefixed with 1.
+ if (
+ !cordovaConfig.KOTLIN_JVM_TARGET.startsWith("1.") &&
+ JavaLanguageVersion.of(cordovaConfig.KOTLIN_JVM_TARGET).compareTo(JavaLanguageVersion.of(8)) <= 0
+ ) {
+ cordovaConfig.KOTLIN_JVM_TARGET = "1." + cordovaConfig.KOTLIN_JVM_TARGET
+ }
+
+ kotlinOptions {
+ jvmTarget = cordovaConfig.KOTLIN_JVM_TARGET
+ }
}
if (cdvReleaseSigningPropertiesFile) {
@@ -297,7 +337,8 @@ dependencies {
// SUB-PROJECT DEPENDENCIES START
implementation(project(path: ":CordovaLib"))
implementation "com.google.firebase:firebase-messaging:23.0.6"
- implementation "com.clevertap.android:clevertap-android-sdk:6.0.0"
+ implementation "com.clevertap.android:clevertap-android-sdk:6.2.1"
+ implementation "com.clevertap.android:push-templates:1.2.4"
implementation "com.github.bumptech.glide:glide:4.12.0"
implementation "androidx.appcompat:appcompat:1.6.0-rc01"
implementation "androidx.core:core:1.9.0"
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/google-services.json b/Samples/Cordova/ExampleProject/platforms/android/app/google-services.json
deleted file mode 100644
index e81478cd..00000000
--- a/Samples/Cordova/ExampleProject/platforms/android/app/google-services.json
+++ /dev/null
@@ -1,155 +0,0 @@
-{
- "project_info": {
- "project_number": "729062631412",
- "project_id": "sampledogimagesapp",
- "storage_bucket": "sampledogimagesapp.appspot.com"
- },
- "client": [
- {
- "client_info": {
- "mobilesdk_app_id": "1:729062631412:android:1c217b1c17db782127fba1",
- "android_client_info": {
- "package_name": "com.clevertap.demo"
- }
- },
- "oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyCO9fzRfw-it06OAhE5k5buTSzqLJIe5eQ"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:729062631412:android:67233198bc946f3827fba1",
- "android_client_info": {
- "package_name": "com.clevertap.example"
- }
- },
- "oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyCO9fzRfw-it06OAhE5k5buTSzqLJIe5eQ"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:729062631412:android:5ad81c1d364ac42127fba1",
- "android_client_info": {
- "package_name": "com.clevertap.xamarindemo"
- }
- },
- "oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyCO9fzRfw-it06OAhE5k5buTSzqLJIe5eQ"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:729062631412:android:64c80512617fc57c27fba1",
- "android_client_info": {
- "package_name": "com.example.clevertap_plugin_example"
- }
- },
- "oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyCO9fzRfw-it06OAhE5k5buTSzqLJIe5eQ"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:729062631412:android:19a47ef52604efdf27fba1",
- "android_client_info": {
- "package_name": "com.example.quizapp"
- }
- },
- "oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyCO9fzRfw-it06OAhE5k5buTSzqLJIe5eQ"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "729062631412-p6f9t5ci4200veao5e6mdn95in8qhipa.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- }
- ],
- "configuration_version": "1"
-}
\ No newline at end of file
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/AndroidManifest.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/AndroidManifest.xml
index 4308e679..f71a65ed 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/AndroidManifest.xml
+++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/AndroidManifest.xml
@@ -1,6 +1,7 @@
-
+
+
@@ -8,7 +9,9 @@
-
+
+
+
@@ -19,11 +22,16 @@
-
-
+
+
+
-
+
+
+
+
+
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova.js b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova.js
index cd613205..291798d0 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova.js
+++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova.js
@@ -19,7 +19,7 @@
under the License.
*/
;(function() {
-var PLATFORM_VERSION_BUILD_LABEL = '11.0.0';
+var PLATFORM_VERSION_BUILD_LABEL = '13.0.0';
// file: src/scripts/require.js
var require;
var define;
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova_plugins.js b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova_plugins.js
index 0bb04294..398ee257 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova_plugins.js
+++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/cordova_plugins.js
@@ -10,7 +10,6 @@ cordova.define('cordova/plugin_list', function(require, exports, module) {
}
];
module.exports.metadata = {
- "cordova-android-support-gradle-release": "3.0.1",
- "clevertap-cordova": "3.0.0"
+ "clevertap-cordova": "3.2.0"
};
});
\ No newline at end of file
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/plugins/clevertap-cordova/www/CleverTap.js b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/plugins/clevertap-cordova/www/CleverTap.js
index 68f111e0..fcc9c9c5 100644
--- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/plugins/clevertap-cordova/www/CleverTap.js
+++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/assets/www/plugins/clevertap-cordova/www/CleverTap.js
@@ -6,11 +6,7 @@ cordova.define("clevertap-cordova.CleverTap", function(require, exports, module)
// with this source code.
//
-var CleverTap = function () {
- const libName = 'Cordova';
- const libVersion = 30000;
- cordova.exec(null, null, "CleverTapPlugin", "setLibrary", [libName, libVersion]);
-}
+var CleverTap = function () {}
/*******************
* notify device ready
@@ -62,11 +58,6 @@ CleverTap.prototype.setPushToken = function (token) {
cordova.exec(null, null, "CleverTapPlugin", "setPushTokenAsString", [token]);
}
-// Sets the devices Xiaomi push token
-CleverTap.prototype.setPushXiaomiToken = function (token,region) {
- cordova.exec(null, null, "CleverTapPlugin", "setPushXiaomiTokenAsString", [token,region]);
-}
-
// Sets the devices Baidu push token
CleverTap.prototype.setPushBaiduToken = function (token) {
cordova.exec(null, null, "CleverTapPlugin", "setPushBaiduTokenAsString", [token]);
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/java/com/clevertap/cordova/CleverTapPlugin.java b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/java/com/clevertap/cordova/CleverTapPlugin.java
deleted file mode 120000
index 080df64c..00000000
--- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/java/com/clevertap/cordova/CleverTapPlugin.java
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../../../../../../../src/android/CleverTapPlugin.java
\ No newline at end of file
diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/java/com/clevertap/cordova/CleverTapPlugin.java b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/java/com/clevertap/cordova/CleverTapPlugin.java
new file mode 100644
index 00000000..08c4c57e
--- /dev/null
+++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/java/com/clevertap/cordova/CleverTapPlugin.java
@@ -0,0 +1,2701 @@
+//
+// CleverTapPlugin.java
+// Copyright (C) 2015 CleverTap
+//
+// This code is provided under a commercial License.
+// A copy of this license has been distributed in a file called LICENSE
+// with this source code.
+//
+//
+
+package com.clevertap.cordova;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.location.Location;
+
+import androidx.annotation.NonNull;
+import com.clevertap.android.sdk.PushPermissionResponseListener;
+import com.clevertap.android.sdk.inapp.CTInAppNotification;
+import com.clevertap.android.sdk.inapp.CTLocalInApp;
+import com.clevertap.android.sdk.pushnotification.CTPushNotificationListener;
+import com.clevertap.android.sdk.pushnotification.amp.CTPushAmpListener;
+import com.clevertap.android.sdk.variables.CTVariableUtils;
+import com.clevertap.android.sdk.variables.Var;
+import com.clevertap.android.sdk.variables.callbacks.VariableCallback;
+import com.clevertap.android.sdk.variables.callbacks.VariablesChangedCallback;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.PluginResult;
+
+import org.apache.cordova.PluginResult.Status;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import java.lang.Exception;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Locale;
+import java.util.Date;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+import com.clevertap.android.sdk.ActivityLifecycleCallback;
+import com.clevertap.android.sdk.CTFeatureFlagsListener;
+import com.clevertap.android.sdk.CleverTapAPI;
+import com.clevertap.android.sdk.SyncListener;
+import com.clevertap.android.sdk.InAppNotificationListener;
+import com.clevertap.android.sdk.events.EventDetail;
+import com.clevertap.android.sdk.UTMDetail;
+import com.clevertap.android.sdk.CTInboxListener;
+import com.clevertap.android.sdk.CTInboxStyleConfig;
+import com.clevertap.android.sdk.inbox.CTInboxMessage;
+import com.clevertap.android.sdk.InboxMessageButtonListener;
+import com.clevertap.android.sdk.InboxMessageListener;
+import com.clevertap.android.sdk.InAppNotificationButtonListener;
+import com.clevertap.android.sdk.displayunits.model.CleverTapDisplayUnit;
+import com.clevertap.android.sdk.displayunits.DisplayUnitListener;
+import com.clevertap.android.sdk.product_config.CTProductConfigListener;
+import com.clevertap.android.sdk.interfaces.OnInitCleverTapIDListener;
+import com.clevertap.android.sdk.interfaces.NotificationHandler;
+
+
+public class CleverTapPlugin extends CordovaPlugin implements SyncListener, InAppNotificationListener, CTInboxListener,
+ InboxMessageButtonListener, InAppNotificationButtonListener, DisplayUnitListener,
+ CTFeatureFlagsListener, CTProductConfigListener, CTPushNotificationListener, CTPushAmpListener, InboxMessageListener,
+ PushPermissionResponseListener {
+
+ private static final String LOG_TAG = "CLEVERTAP_PLUGIN";
+ private static String CLEVERTAP_API_ERROR;
+ private static CleverTapAPI cleverTap;
+ private boolean callbackDone = false;
+ public static Map variables = new HashMap<>();
+
+
+ @Override
+ public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+ super.initialize(cordova, webView);
+
+ cleverTap = CleverTapAPI.getDefaultInstance(cordova.getActivity().getApplicationContext());
+ cleverTap.setSyncListener(this);
+ cleverTap.setInAppNotificationListener(this);
+ cleverTap.setCTNotificationInboxListener(this);
+ cleverTap.setInboxMessageButtonListener(this);
+ cleverTap.setCTInboxMessageListener(this);
+ cleverTap.setInAppNotificationButtonListener(this);
+ cleverTap.setDisplayUnitListener(this);
+ cleverTap.setCTFeatureFlagsListener(this);
+ cleverTap.setCTProductConfigListener(this);
+ cleverTap.setCTPushNotificationListener(this);
+ cleverTap.setCTPushAmpListener(this);
+ cleverTap.registerPushPermissionNotificationResponseListener(this);
+
+ String libName = "Cordova";
+ int libVersion = 30200;
+ cleverTap.setLibrary(libName);
+ cleverTap.setCustomSdkVersion(libName, libVersion);
+
+ try {
+ String ptHandler = "com.clevertap.android.pushtemplates.PushTemplateNotificationHandler";
+ CleverTapAPI.setNotificationHandler((NotificationHandler) (Class.forName(ptHandler).getConstructor().newInstance()));
+ System.out.println("Push templates dependency available");
+ }
+ catch (Throwable e){
+ System.out.println("Push templates dependency not found");
+ }
+
+ onNewIntent(cordova.getActivity().getIntent());
+
+ }
+
+ /**
+ * Called when the activity receives a new intent.
+ */
+ public void onNewIntent(Intent intent) {
+ if (intent == null) return;
+
+ // deeplink
+ if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_VIEW)) {
+ Uri data = intent.getData();
+ if (data != null) {
+ if(!isDeepLinkValid(data)){
+ Log.w(LOG_TAG, "Found malicious deep link. Not processing further.");
+ return;
+ }
+ final String json = "{'deeplink':'" + data.toString() + "'}";
+
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ webView.loadUrl("javascript:cordova.fireDocumentEvent('onDeepLink'," + json + ");");
+ }
+ });
+
+ }
+ }
+ // push notification
+ else {
+ Bundle extras = intent.getExtras();
+ Boolean isPushNotification = (extras != null && extras.get("wzrk_pn") != null);
+ if (isPushNotification) {
+ JSONObject data = new JSONObject();
+
+ for (String key : extras.keySet()) {
+ try {
+ Object value = extras.get(key);
+ if (value instanceof Map) {
+ JSONObject jsonObject = new JSONObject((Map) value);
+ data.put(key, jsonObject);
+ } else if (value instanceof List) {
+ JSONArray jsonArray = new JSONArray((List) value);
+ data.put(key, jsonArray);
+ } else {
+ data.put(key, extras.get(key));
+ }
+ } catch (Throwable t) {
+ // no-op
+ }
+ }
+
+ final String json = "{'notification':" + data.toString() + "}";
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ webView.loadUrl("javascript:cordova.fireDocumentEvent('onPushNotification'," + json + ");");
+ }
+ });
+
+ if (!callbackDone) {
+ final String callbackJson = "{'customExtras':" + data.toString() + "}";
+
+ webView.getView().post(new Runnable() {
+ public void run() {
+
+ webView.loadUrl(
+ "javascript:cordova.fireDocumentEvent('onCleverTapPushNotificationTappedWithCustomExtras',"
+ + callbackJson + ");");
+ }
+ });
+ }
+
+ }
+ }
+ }
+
+ @Override
+ public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
+
+ Log.d(LOG_TAG, "handling action " + action);
+
+ boolean haveError = false;
+ String errorMsg = "unhandled CleverTapPlugin action";
+
+ PluginResult result = null;
+
+ if (!checkCleverTapInitialized()) {
+ result = new PluginResult(PluginResult.Status.ERROR, "CleverTap API not initialized");
+ result.setKeepCallback(true);
+ callbackContext.sendPluginResult(result);
+ return true;
+ }
+
+ // manually start application life cycle
+ else if (action.equals("notifyDeviceReady")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ ActivityLifecycleCallback.register(cordova.getActivity().getApplication());
+ CleverTapAPI.setAppForeground(true);
+ CleverTapAPI.onActivityResumed(cordova.getActivity());
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+
+ return true;
+ }
+
+ // not required for Android here but handle as its in the JS interface
+ else if (action.equals("registerPush")) {
+ result = new PluginResult(PluginResult.Status.NO_RESULT);
+ result.setKeepCallback(true);
+ callbackContext.sendPluginResult(result);
+ return true;
+ } else if (action.equals("setPushTokenAsString")) {
+ final String token = args.getString(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushFcmRegistrationId(token, true);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("setPushBaiduTokenAsString")) {
+ final String token = args.getString(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushBaiduRegistrationId(token, true);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("setPushHuaweiTokenAsString")) {
+ final String token = args.getString(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushHuaweiRegistrationId(token, true);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("createNotification")) {
+ final String extras = args.getString(0);
+ JSONObject json = new JSONObject(extras);
+ Bundle bundle = new Bundle();
+ for (Iterator entry = json.keys(); entry.hasNext(); ) {
+ String key = entry.next();
+ String str = json.optString(key);
+ bundle.putString(key, str);
+ }
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.createNotification(cordova.getActivity().getApplicationContext(), bundle);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+
+ /* Android O functions start*/
+ else if (action.equals("createNotificationChannel")) {
+ final String channelId = (args.length() == 5 ? args.getString(0) : "");
+ final String channelName = (args.length() == 5 ? args.getString(1) : "");
+ final String channelDescription = (args.length() == 5 ? args.getString(2) : "");
+ final int importance = Integer.parseInt((args.length() == 5 ? args.getString(3) : "0"));
+ final boolean showBadge = Boolean.valueOf((args.length() == 5 ? args.getString(4) : "false"));
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.createNotificationChannel(cordova.getActivity().getApplicationContext(), channelId, channelName, channelDescription, importance, showBadge);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("createNotificationChannelWithSound")) {
+ final String channelId = (args.length() == 6 ? args.getString(0) : "");
+ final String channelName = (args.length() == 6 ? args.getString(1) : "");
+ final String channelDescription = (args.length() == 6 ? args.getString(2) : "");
+ final int importance = Integer.parseInt((args.length() == 6 ? args.getString(3) : "0"));
+ final boolean showBadge = Boolean.valueOf((args.length() == 6 ? args.getString(4) : "false"));
+ final String sound = (args.length() == 6 ? args.getString(5) : "");
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.createNotificationChannel(cordova.getActivity().getApplicationContext(), channelId, channelName, channelDescription, importance, showBadge, sound);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("createNotificationChannelWithGroupId")) {
+ final String channelId = (args.length() == 6 ? args.getString(0) : "");
+ final String channelName = (args.length() == 6 ? args.getString(1) : "");
+ final String channelDescription = (args.length() == 6 ? args.getString(2) : "");
+ final int importance = Integer.parseInt((args.length() == 6 ? args.getString(3) : "0"));
+ final String groupId = (args.length() == 6 ? args.getString(4) : "");
+ final boolean showBadge = Boolean.valueOf((args.length() == 6 ? args.getString(5) : "false"));
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.createNotificationChannel(cordova.getActivity().getApplicationContext(), channelId, channelName, channelDescription, importance, groupId, showBadge);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("createNotificationChannelWithGroupIdAndSound")) {
+ final String channelId = (args.length() == 7 ? args.getString(0) : "");
+ final String channelName = (args.length() == 7 ? args.getString(1) : "");
+ final String channelDescription = (args.length() == 7 ? args.getString(2) : "");
+ final int importance = Integer.parseInt((args.length() == 7 ? args.getString(3) : "0"));
+ final String groupId = (args.length() == 7 ? args.getString(4) : "");
+ final boolean showBadge = Boolean.valueOf((args.length() == 7 ? args.getString(5) : "false"));
+ final String sound = (args.length() == 7 ? args.getString(6) : "");
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.createNotificationChannel(cordova.getActivity().getApplicationContext(), channelId, channelName, channelDescription, importance, groupId, showBadge, sound);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("createNotificationChannelGroup")) {
+ final String groupId = (args.length() == 2 ? args.getString(0) : "");
+ final String groupName = (args.length() == 2 ? args.getString(1) : "");
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.createNotificationChannelGroup(cordova.getActivity().getApplicationContext(), groupId, groupName);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("deleteNotificationChannel")) {
+ final String channelId = (args.length() == 1 ? args.getString(0) : "");
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.deleteNotificationChannel(cordova.getActivity().getApplicationContext(), channelId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("deleteNotificationChannelGroup")) {
+ final String groupId = (args.length() == 1 ? args.getString(0) : "");
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.deleteNotificationChannelGroup(cordova.getActivity().getApplicationContext(), groupId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ /* Android O functions end*/
+
+ else if (action.equals("recordScreenView")) {
+ final String screen = (args.length() == 1 ? args.getString(0) : "");
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.recordScreen(screen);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("setDebugLevel")) {
+ int level = (args.length() == 1 ? args.getInt(0) : -2);
+ if (level >= -1) {
+ CleverTapAPI.setDebugLevel(level);
+ result = new PluginResult(PluginResult.Status.NO_RESULT);
+ result.setKeepCallback(true);
+ callbackContext.sendPluginResult(result);
+ return true;
+ }
+
+ }
+
+ //Enables tracking opt out for the currently active user.
+ else if (action.equals("setOptOut")) {
+ final boolean value = args.getBoolean(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.setOptOut(value);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ //Sets the SDK to offline mode
+ else if (action.equals("setOffline")) {
+ final boolean value = args.getBoolean(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.setOffline(value);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+
+ //Enables the reporting of device network related information, including IP address. This reporting is disabled by default.
+ else if (action.equals("enableDeviceNetworkInfoReporting")) {
+ final boolean value = args.getBoolean(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.enableDeviceNetworkInfoReporting(value);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("enablePersonalization")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.enablePersonalization();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else if (action.equals("disablePersonalization")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.disablePersonalization();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else if (action.equals("recordEventWithName")) {
+ final String eventName = (args.length() == 1 ? args.getString(0) : null);
+ if (eventName != null) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushEvent(eventName);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else {
+ errorMsg = "eventName cannot be null";
+ }
+ } else if (action.equals("recordEventWithNameAndProps")) {
+ String eventName = null;
+ JSONObject jsonProps;
+ HashMap _props = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ eventName = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "eventName cannot be null";
+ }
+ if (!args.isNull(1)) {
+ jsonProps = args.getJSONObject(1);
+ try {
+ _props = toMap(jsonProps);
+ } catch (JSONException e) {
+ haveError = true;
+ errorMsg = "Error parsing event properties";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Arg cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _eventName = eventName;
+ final HashMap props = _props;
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushEvent(_eventName, props);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("recordChargedEventWithDetailsAndItems")) {
+ JSONObject jsonDetails;
+ JSONArray jsonItems;
+ HashMap _details = null;
+ ArrayList> _items = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ jsonDetails = args.getJSONObject(0);
+ try {
+ _details = toMap(jsonDetails);
+ } catch (JSONException e) {
+ haveError = true;
+ errorMsg = "Error parsing arg " + e.getLocalizedMessage();
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Arg cannot be null";
+ }
+ if (!args.isNull(1)) {
+ jsonItems = args.getJSONArray(1);
+ try {
+ _items = toArrayListOfStringObjectMaps(jsonItems);
+ } catch (JSONException e) {
+ haveError = true;
+ errorMsg = "Error parsing arg " + e.getLocalizedMessage();
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Arg cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final HashMap details = _details;
+ final ArrayList> items = _items;
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushChargedEvent(details, items);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("pushInstallReferrer")) {
+ String source = null;
+ String campaign = null;
+ String medium = null;
+
+ if (args.length() == 3) {
+ if (!args.isNull(0)) {
+ source = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "source cannot be null";
+ }
+ if (!args.isNull(1)) {
+ medium = args.getString(1);
+ } else {
+ haveError = true;
+ errorMsg = "medium cannot be null";
+ }
+ if (!args.isNull(2)) {
+ campaign = args.getString(2);
+ } else {
+ haveError = true;
+ errorMsg = "campaign cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 3 arguments";
+ }
+
+ if (!haveError) {
+ final String _source = source;
+ final String _medium = medium;
+ final String _campaign = campaign;
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushInstallReferrer(_source, _medium, _campaign);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("eventGetFirstTime")) {
+ final String eventName = (args.length() == 1 ? args.getString(0) : null);
+ if (eventName != null) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ double first = cleverTap.getFirstTime(eventName);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, (float) first);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else {
+ errorMsg = "eventName cannot be null";
+ }
+ } else if (action.equals("eventGetLastTime")) {
+ final String eventName = (args.length() == 1 ? args.getString(0) : null);
+ if (eventName != null) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ double lastTime = cleverTap.getLastTime(eventName);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, (float) lastTime);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else {
+ errorMsg = "eventName cannot be null";
+ }
+ } else if (action.equals("eventGetOccurrences")) {
+ final String eventName = (args.length() == 1 ? args.getString(0) : null);
+ if (eventName != null) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ int num = cleverTap.getCount(eventName);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, num);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else {
+ errorMsg = "eventName cannot be null";
+ }
+ } else if (action.equals("eventGetDetails")) {
+ final String eventName = (args.length() == 1 ? args.getString(0) : null);
+ if (eventName != null) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ EventDetail details = cleverTap.getDetails(eventName);
+ try {
+ JSONObject jsonDetails = CleverTapPlugin.eventDetailsToJSON(details);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, jsonDetails);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR, e.getLocalizedMessage());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ return true;
+
+ } else {
+ errorMsg = "eventName cannot be null";
+ }
+ } else if (action.equals("getEventHistory")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ Map history = cleverTap.getHistory();
+ try {
+ JSONObject jsonDetails = CleverTapPlugin.eventHistoryToJSON(history);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, jsonDetails);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR, e.getLocalizedMessage());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ return true;
+ } else if (action.equals("setLocation")) {
+ Double lat = null;
+ Double lon = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ lat = args.getDouble(0);
+ } else {
+ haveError = true;
+ errorMsg = "lat cannot be null";
+ }
+ if (!args.isNull(1)) {
+ lon = args.getDouble(1);
+ } else {
+ haveError = true;
+ errorMsg = "lon cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final Location location = new Location("CleverTapPlugin");
+ location.setLatitude(lat);
+ location.setLongitude(lon);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.setLocation(location);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("getLocation")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ Location location = cleverTap.getLocation();
+ PluginResult _result = null;
+ try {
+ if (location != null) {
+ JSONObject jsonLoc = new JSONObject();
+ jsonLoc.put("lat", location.getLatitude());
+ jsonLoc.put("lon", location.getLongitude());
+ _result = new PluginResult(PluginResult.Status.OK, jsonLoc);
+ }
+ } catch (Throwable t) {
+ // no-op
+ }
+
+ if (_result == null) {
+ _result = new PluginResult(PluginResult.Status.ERROR, "Unable to get location");
+ }
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("profileSet")) {
+ JSONObject jsonProfile = null;
+
+ if (args.length() == 1) {
+ if (!args.isNull(0)) {
+ jsonProfile = args.getJSONObject(0);
+ } else {
+ haveError = true;
+ errorMsg = "profile cannot be null";
+ }
+
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+
+ if (!haveError) {
+ final JSONObject _jsonProfile = jsonProfile;
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ try {
+ HashMap profile = formatProfile(_jsonProfile);
+ cleverTap.pushProfile(profile);
+ } catch (Exception e) {
+ Log.d(LOG_TAG, "Error setting profile " + e.getLocalizedMessage());
+ }
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+
+ return true;
+ }
+ } else if (action.equals("onUserLogin")) {
+ JSONObject jsonProfile = null;
+
+ if (args.length() == 1) {
+ if (!args.isNull(0)) {
+ jsonProfile = args.getJSONObject(0);
+ } else {
+ haveError = true;
+ errorMsg = "profile cannot be null";
+ }
+
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+
+ if (!haveError) {
+ final JSONObject _jsonProfile = jsonProfile;
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ try {
+ HashMap profile = formatProfile(_jsonProfile);
+ cleverTap.onUserLogin(profile);
+ } catch (Exception e) {
+ Log.d(LOG_TAG, "Error in onUserLogin " + e.getLocalizedMessage());
+ }
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+
+ return true;
+ }
+ } else if (action.equals("profileGetProperty")) {
+ final String propertyName = (args.length() == 1 ? args.getString(0) : null);
+ if (propertyName != null) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ PluginResult _result;
+ Object prop = cleverTap.getProperty(propertyName);
+
+ if (prop instanceof JSONArray) {
+ JSONArray _prop = (JSONArray) prop;
+ _result = new PluginResult(PluginResult.Status.OK, _prop);
+
+ } else {
+ String _prop;
+ if (prop != null) {
+ _prop = prop.toString();
+ } else {
+ _prop = null;
+ }
+ _result = new PluginResult(PluginResult.Status.OK, _prop);
+ }
+
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else {
+ errorMsg = "propertyName cannot be null";
+ }
+ } else if (action.equals("profileGetCleverTapID")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ String CleverTapID = cleverTap.getCleverTapID();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, CleverTapID);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("profileGetCleverTapAttributionIdentifier")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ String attributionID = cleverTap.getCleverTapAttributionIdentifier();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, attributionID);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getCleverTapID")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.getCleverTapID(new OnInitCleverTapIDListener() {
+ @Override
+ public void onInitCleverTapID(final String cleverTapID) {
+ // Callback on main thread
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, cleverTapID);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+
+ });
+ }
+ });
+ return true;
+ } else if (action.equals("profileRemoveValueForKey")) {
+ final String key = (args.length() == 1 ? args.getString(0) : null);
+ if (key != null) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.removeValueForKey(key);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+
+ } else {
+ errorMsg = "property key cannot be null";
+ }
+ } else if (action.equals("profileSetMultiValues")) {
+ String key = null;
+ JSONArray values = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ key = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "key cannot be null";
+ }
+ if (!args.isNull(1)) {
+ values = args.getJSONArray(1);
+ if (values == null) {
+ haveError = true;
+ errorMsg = "values cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "values cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _key = key;
+ final ArrayList _values = new ArrayList();
+ try {
+ for (int i = 0; i < values.length(); i++) {
+ _values.add(values.get(i).toString());
+ }
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.setMultiValuesForKey(_key, _values);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+
+ return true;
+
+ } catch (Exception e) {
+ // no-op
+ }
+ }
+ } else if (action.equals("profileAddMultiValues")) {
+ String key = null;
+ JSONArray values = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ key = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "key cannot be null";
+ }
+ if (!args.isNull(1)) {
+ values = args.getJSONArray(1);
+ if (values == null) {
+ haveError = true;
+ errorMsg = "values cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "values cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _key = key;
+ final ArrayList _values = new ArrayList();
+ try {
+ for (int i = 0; i < values.length(); i++) {
+ _values.add(values.get(i).toString());
+ }
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.addMultiValuesForKey(_key, _values);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+
+ return true;
+
+ } catch (Exception e) {
+ // no-op
+ }
+ }
+ } else if (action.equals("profileRemoveMultiValues")) {
+ String key = null;
+ JSONArray values = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ key = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "key cannot be null";
+ }
+ if (!args.isNull(1)) {
+ values = args.getJSONArray(1);
+ if (values == null) {
+ haveError = true;
+ errorMsg = "values cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "values cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _key = key;
+ final ArrayList _values = new ArrayList();
+ try {
+ for (int i = 0; i < values.length(); i++) {
+ _values.add(values.get(i).toString());
+ }
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.removeMultiValuesForKey(_key, _values);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+
+ return true;
+
+ } catch (Exception e) {
+ // no-op
+ }
+ }
+ } else if (action.equals("profileAddMultiValue")) {
+ String key = null;
+ String value = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ key = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "key cannot be null";
+ }
+ if (!args.isNull(1)) {
+ value = args.getString(1);
+ } else {
+ haveError = true;
+ errorMsg = "value cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _key = key;
+ final String _value = value;
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.addMultiValueForKey(_key, _value);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("profileRemoveMultiValue")) {
+ String key = null;
+ String value = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ key = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "key cannot be null";
+ }
+ if (!args.isNull(1)) {
+ value = args.getString(1);
+ } else {
+ haveError = true;
+ errorMsg = "value cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _key = key;
+ final String _value = value;
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.removeMultiValueForKey(_key, _value);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("profileIncrementValueBy")) {
+ String key = null;
+ Double value = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ key = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "key cannot be null";
+ }
+ if (!args.isNull(1)) {
+ value = args.getDouble(1);
+ } else {
+ haveError = true;
+ errorMsg = "value cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _key = key;
+ final Double _value = value;
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.incrementValue(_key, _value);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("profileDecrementValueBy")) {
+ String key = null;
+ Double value = null;
+
+ if (args.length() == 2) {
+ if (!args.isNull(0)) {
+ key = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "key cannot be null";
+ }
+ if (!args.isNull(1)) {
+ value = args.getDouble(1);
+ } else {
+ haveError = true;
+ errorMsg = "value cannot be null";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 2 arguments";
+ }
+
+ if (!haveError) {
+ final String _key = key;
+ final Double _value = value;
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.decrementValue(_key, _value);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("sessionGetTimeElapsed")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ int time = cleverTap.getTimeElapsed();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, time);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("sessionGetTotalVisits")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ int count = cleverTap.getTotalVisits();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, count);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("sessionGetScreenCount")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ int count = cleverTap.getScreenCount();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, count);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("sessionGetPreviousVisitTime")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ int time = cleverTap.getPreviousVisitTime();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, time);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("sessionGetUTMDetails")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ UTMDetail details = cleverTap.getUTMDetails();
+ try {
+ JSONObject jsonDetails = CleverTapPlugin.utmDetailsToJSON(details);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, jsonDetails);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR, e.getLocalizedMessage());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ return true;
+ }
+ //Notification Inbox methods
+ else if (action.equals("initializeInbox")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.initializeInbox();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ } else if (action.equals("showInbox")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ try {
+ JSONObject styleConfigJSON;
+ CTInboxStyleConfig styleConfig = new CTInboxStyleConfig();
+ if (args.length() == 1) {
+ styleConfigJSON = args.getJSONObject(0);
+ styleConfig = toStyleConfig(styleConfigJSON);
+ }
+ cleverTap.showAppInbox(styleConfig);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR, e.getLocalizedMessage());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ } else if (action.equals("getInboxMessageUnreadCount")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ int unreadCount = cleverTap.getInboxMessageUnreadCount();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, unreadCount);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getInboxMessageCount")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ int msgCount = cleverTap.getInboxMessageCount();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, msgCount);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getAllInboxMessages")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ try {
+ ArrayList messageList = cleverTap.getAllInboxMessages();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, inboxMessageListToJSONArray(messageList));
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ return true;
+ } else if (action.equals("getUnreadInboxMessages")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ try {
+ ArrayList messageList = cleverTap.getUnreadInboxMessages();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, inboxMessageListToJSONArray(messageList));
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ return true;
+ } else if (action.equals("getInboxMessageForId")) {
+ final String messageId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ CTInboxMessage message = cleverTap.getInboxMessageForId(messageId);
+ try {
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, message.getData());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (Exception e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR, "InboxMessage with ID=" + messageId + " not found!");
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ return true;
+ } else if (action.equals("deleteInboxMessageForId")) {
+ final String messageId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.deleteInboxMessage(messageId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("markReadInboxMessageForId")) {
+ final String messageId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.markReadInboxMessage(messageId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("markReadInboxMessagesForIds")) {
+ JSONArray jsonArray = null;
+ if (args.length() == 1) {
+ jsonArray = args.getJSONArray(0);
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+ if (!haveError) {
+ final JSONArray finalJsonArray = jsonArray;
+ cordova.getThreadPool().execute(() -> {
+ try {
+ cleverTap.markReadInboxMessagesForIDs((ArrayList) toStringList(finalJsonArray));
+
+ PluginResult _result = new PluginResult(Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (Exception e) {
+ PluginResult _result = new PluginResult(Status.ERROR, e.getLocalizedMessage());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("deleteInboxMessagesForIds")) {
+ JSONArray jsonArray = null;
+ if (args.length() == 1) {
+ jsonArray = args.getJSONArray(0);
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+ if (!haveError) {
+ final JSONArray finalJsonArray = jsonArray;
+ cordova.getThreadPool().execute(() -> {
+ try {
+ cleverTap.deleteInboxMessagesForIDs((ArrayList) toStringList(finalJsonArray));
+
+ PluginResult _result = new PluginResult(Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (Exception e) {
+ PluginResult _result = new PluginResult(Status.ERROR, e.getLocalizedMessage());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("dismissInbox")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.dismissAppInbox();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ } else if (action.equals("pushInboxNotificationViewedEventForId")) {
+ final String messageId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushInboxNotificationViewedEvent(messageId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("pushInboxNotificationClickedEventForId")) {
+ final String messageId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushInboxNotificationClickedEvent(messageId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getAllDisplayUnits")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ try {
+ ArrayList displayUnits = cleverTap.getAllDisplayUnits();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, displayUnitListToJSONArray(displayUnits));
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ }
+ });
+ return true;
+ } else if (action.equals("getDisplayUnitForId")) {
+ final String unitId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ CleverTapDisplayUnit displayUnit = cleverTap.getDisplayUnitForId(unitId);
+ PluginResult _result;
+ if (displayUnit != null) {
+ _result = new PluginResult(PluginResult.Status.OK, displayUnit.getJsonObject());
+ } else {
+ _result = new PluginResult(PluginResult.Status.ERROR, "DisplayUnit with ID=" + unitId + " not found!");
+ }
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("pushDisplayUnitViewedEventForID")) {
+ final String unitId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushDisplayUnitViewedEventForID(unitId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("pushDisplayUnitClickedEventForID")) {
+ final String unitId = (args.length() == 1 ? args.getString(0) : "");
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.pushDisplayUnitClickedEventForID(unitId);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("isFeatureFlagInitialized")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ boolean value = cleverTap.featureFlag().isInitialized();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getFeatureFlag")) {
+ final String name = args.getString(0);
+ final boolean defaultValue = args.getBoolean(1);
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ boolean value = cleverTap.featureFlag().get(name, defaultValue);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("isProducConfigInitialized")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ boolean value = cleverTap.productConfig().isInitialized();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("setDefaultsMap")) {
+ try {
+ final HashMap defaultValue = toMap(args.getJSONObject(0));
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.productConfig().setDefaults(defaultValue);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+
+ } catch (JSONException e) {
+ PluginResult _result = new PluginResult(PluginResult.Status.ERROR);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+
+ return true;
+ } else if (action.equals("fetch")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.productConfig().fetch();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("fetchWithMinimumFetchIntervalInSeconds")) {
+ long interval = args.getInt(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.productConfig().fetch(interval);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("activate")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.productConfig().activate();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("fetchAndActivate")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.productConfig().activate();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("setMinimumFetchIntervalInSeconds")) {
+ long interval = args.getInt(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.productConfig().setMinimumFetchIntervalInSeconds(interval);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getLastFetchTimeStampInMillis")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ long value = cleverTap.productConfig().getLastFetchTimeStampInMillis();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getString")) {
+ String key = args.getString(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ String value = cleverTap.productConfig().getString(key);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getBoolean")) {
+ String key = args.getString(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ boolean value = cleverTap.productConfig().getBoolean(key);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getLong")) {
+ String key = args.getString(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ long value = cleverTap.productConfig().getLong(key);
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("getDouble")) {
+ String key = args.getString(0);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ float value = cleverTap.productConfig().getDouble(key).floatValue();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("reset")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.productConfig().reset();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("suspendInAppNotifications")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.suspendInAppNotifications();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("discardInAppNotifications")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.discardInAppNotifications();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("resumeInAppNotifications")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.resumeInAppNotifications();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("promptPushPrimer")) {
+ JSONObject pushPrimerJsonObject = null;
+ if (args.length() == 1) {
+ if (!args.isNull(0)) {
+ try {
+ pushPrimerJsonObject = processPushPrimerArgument(args.getJSONObject(0));
+ if (pushPrimerJsonObject == null)
+ {
+ haveError = true;
+ errorMsg = "Invalid parameters in push primer config";
+ }
+ } catch (Exception e) {
+ haveError = true;
+ errorMsg = e.getLocalizedMessage();
+ }
+ } else {
+ haveError = true;
+ errorMsg = "object passed to promptPushPrimer can not be null!";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+
+ if (!haveError) {
+ final JSONObject finalPushPrimerJsonObject = pushPrimerJsonObject;
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.promptPushPrimer(finalPushPrimerJsonObject);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("promptForPushPermission")) {
+ boolean showFallbackSettings = false;
+
+ if (args.length() == 1) {
+ showFallbackSettings = args.getBoolean(0);
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+ if (!haveError) {
+ final boolean finalShowFallbackSettings = showFallbackSettings;
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.promptForPushPermission(finalShowFallbackSettings);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("isPushPermissionGranted")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ boolean value = cleverTap.isPushPermissionGranted();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("setLibrary")) {
+ String libName = args.getString(0);
+ int libVersion = args.getInt(1);
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.setCustomSdkVersion(libName,libVersion);
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("syncVariables")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ cleverTap.syncVariables();
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("syncVariablesinProd")) {
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ Log.d(LOG_TAG, "syncVariablesinProd is no-op in Android");
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ } else if (action.equals("fetchVariables")) {
+ cordova.getThreadPool().execute(() -> {
+ cleverTap.fetchVariables(isSuccess -> {
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, isSuccess);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ });
+
+ });
+ return true;
+ } else if (action.equals("defineVariables")) {
+ Map variablesMap = null;
+ if (args.length() == 1) {
+ if (!args.isNull(0)) {
+ try {
+ variablesMap = toMap(args.getJSONObject(0));
+ } catch (Exception e) {
+ haveError = true;
+ errorMsg = e.getLocalizedMessage();
+ }
+ } else {
+ haveError = true;
+ errorMsg = "object passed to defineVariables can not be null!";
+ }
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+
+ if (!haveError) {
+ final Map finalVariablesJsonObject = variablesMap;
+ cordova.getThreadPool().execute(() -> {
+ for (Map.Entry entry : finalVariablesJsonObject.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ variables.put(key, cleverTap.defineVariable(key, value));
+ }
+ PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ });
+ return true;
+ }
+ } else if (action.equals("getVariable")) {
+ String variableName = null;
+
+ if (args.length() == 1) {
+ variableName = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+
+ if (!haveError) {
+ final String finalVariableName = variableName;
+ cordova.getThreadPool().execute(() -> {
+ try {
+ Object value = getVariableValue(finalVariableName);
+ PluginResult _result = getPluginResult(Status.OK, value);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ } catch (Exception e) {
+ PluginResult _result = new PluginResult(Status.ERROR, e.getLocalizedMessage());
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ return true;
+ }
+ } else if (action.equals("getVariables")) {
+ cordova.getThreadPool().execute(() -> {
+ JSONObject jsonVariables = getVariablesAsJson();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK, jsonVariables);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ });
+ return true;
+ } else if (action.equals("onVariablesChanged")) {
+ cordova.getThreadPool().execute(() -> {
+ cleverTap.addVariablesChangedCallback(new VariablesChangedCallback() {
+ @Override
+ public void variablesChanged() {
+ JSONObject jsonVariables = getVariablesAsJson();
+ PluginResult _result = new PluginResult(PluginResult.Status.OK,jsonVariables);
+ _result.setKeepCallback(true);
+ callbackContext.sendPluginResult(_result);
+ }
+ });
+ });
+ return true;
+ } else if (action.equals("onValueChanged")) {
+
+ String variableName = null;
+
+ if (args.length() == 1) {
+ variableName = args.getString(0);
+ } else {
+ haveError = true;
+ errorMsg = "Expected 1 argument";
+ }
+
+ if (!haveError) {
+ final String finalVariableName = variableName;
+ cordova.getThreadPool().execute(() -> {
+ try {
+ if (variables.containsKey(finalVariableName)) {
+ Var