From 131f6a759bf427da46f5d09d887c61c46d952f67 Mon Sep 17 00:00:00 2001 From: anush Date: Thu, 1 Aug 2024 12:36:37 +0530 Subject: [PATCH 01/13] task(SDK-3895) - Fixes calllback issue for capacitor when notification clicked from app in killed state - Moves setLibrary to native side for android - Same needs to be done for iOS --- src/android/CleverTapPlugin.java | 6 +++++- www/CleverTap.js | 6 +----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/android/CleverTapPlugin.java b/src/android/CleverTapPlugin.java index 8c2c20fc..99453f63 100644 --- a/src/android/CleverTapPlugin.java +++ b/src/android/CleverTapPlugin.java @@ -101,7 +101,11 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { cleverTap.setCTPushNotificationListener(this); cleverTap.setCTPushAmpListener(this); cleverTap.registerPushPermissionNotificationResponseListener(this); - cleverTap.setLibrary("Cordova"); + + String libName = "Cordova"; + int libVersion = 30100; + cleverTap.setLibrary(libName); + cleverTap.setCustomSdkVersion(libName, libVersion); try { String ptHandler = "com.clevertap.android.pushtemplates.PushTemplateNotificationHandler"; diff --git a/www/CleverTap.js b/www/CleverTap.js index 4aed47bc..e6c30bdf 100644 --- a/www/CleverTap.js +++ b/www/CleverTap.js @@ -5,11 +5,7 @@ // with this source code. // -var CleverTap = function () { - const libName = 'Cordova'; - const libVersion = 30100; - cordova.exec(null, null, "CleverTapPlugin", "setLibrary", [libName, libVersion]); -} +var CleverTap = function () {} /******************* * notify device ready From 750125213588c490e7dde2e3f45be4fe75898f10 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 12:28:01 +0530 Subject: [PATCH 02/13] task(SDK-3980) - Adds support for v6.2.1 --- package.json | 7 ++++++- plugin.xml | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 7b0af8ed..4663d52a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "clevertap-cordova", - "version": "3.1.0", + "version": "3.2.0", "description": "CleverTap Plugin for Cordova/PhoneGap", "cordova": { "id": "clevertap-cordova", @@ -35,6 +35,11 @@ "cordova-ios": ">=4.3.0", "cordova-android": ">=12.0.0", "cordova": ">=12.0.0" + }, + "3.2.0": { + "cordova-ios": ">=4.3.0", + "cordova-android": ">=13.0.0", + "cordova": ">=12.0.0" } } }, diff --git a/plugin.xml b/plugin.xml index 8f8e7b64..9e40e7da 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,5 +1,5 @@ - + CleverTap CleverTap Plugin for Cordova/PhoneGap Commercial @@ -104,7 +104,7 @@ - + From 7299f7c12c6808b382c20801020dc4b361883656 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 13:33:20 +0530 Subject: [PATCH 03/13] task(SDK-3980) - Removes xiaomi related code --- src/android/CleverTapPlugin.java | 12 ------------ www/CleverTap.js | 5 ----- 2 files changed, 17 deletions(-) diff --git a/src/android/CleverTapPlugin.java b/src/android/CleverTapPlugin.java index 8c2c20fc..f1801708 100644 --- a/src/android/CleverTapPlugin.java +++ b/src/android/CleverTapPlugin.java @@ -240,18 +240,6 @@ public void run() { } }); return true; - } else if (action.equals("setPushXiaomiTokenAsString")) { - final String token = args.getString(0); - final String region = args.getString(1); - cordova.getThreadPool().execute(new Runnable() { - public void run() { - cleverTap.pushXiaomiRegistrationId(token,(region!=null && region.equalsIgnoreCase("null")) ? null : region, 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() { diff --git a/www/CleverTap.js b/www/CleverTap.js index 4aed47bc..1189d990 100644 --- a/www/CleverTap.js +++ b/www/CleverTap.js @@ -61,11 +61,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]); From 9eefa682a08afb23f08d80ad0f983e51663a2630 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 14:10:09 +0530 Subject: [PATCH 04/13] task(SDK-3980) - Updates version in CleverTapPlugin --- src/android/CleverTapPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/CleverTapPlugin.java b/src/android/CleverTapPlugin.java index eba317b6..08c4c57e 100644 --- a/src/android/CleverTapPlugin.java +++ b/src/android/CleverTapPlugin.java @@ -103,7 +103,7 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { cleverTap.registerPushPermissionNotificationResponseListener(this); String libName = "Cordova"; - int libVersion = 30100; + int libVersion = 30200; cleverTap.setLibrary(libName); cleverTap.setCustomSdkVersion(libName, libVersion); From 142e0cd6b833fc526557212834a1bbfcab887023 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 16:02:50 +0530 Subject: [PATCH 05/13] task(SDK-3980) - Adds CHANGELOG.md --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28fd3cc7..683eebe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ 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. + +#### 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 From f199a94c96e149ee84a8c6d85946e301e729ed27 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 16:25:12 +0530 Subject: [PATCH 06/13] task(SDK-3980) - Updates sample app --- Samples/Cordova/ExampleProject/package.json | 2 +- .../android/CordovaLib/AndroidManifest.xml | 3 +- .../platforms/android/CordovaLib/build.gradle | 14 +- .../android/CordovaLib/cordova.gradle | 17 +- .../android/CordovaLib/project.properties | 19 ++- .../src/org/apache/cordova/BuildHelper.java | 3 +- .../org/apache/cordova/ConfigXmlParser.java | 15 +- .../org/apache/cordova/CordovaActivity.java | 5 + .../cordova/CordovaClientCertRequest.java | 7 + .../apache/cordova/CordovaDialogsHelper.java | 9 + .../cordova/CordovaHttpAuthHandler.java | 2 + .../apache/cordova/CordovaInterfaceImpl.java | 15 +- .../src/org/apache/cordova/CordovaPlugin.java | 17 ++ .../org/apache/cordova/CordovaWebView.java | 2 +- .../apache/cordova/CordovaWebViewImpl.java | 7 +- .../src/org/apache/cordova/CoreAndroid.java | 35 ++-- .../cordova/NativeToJsMessageQueue.java | 4 + .../src/org/apache/cordova/PluginManager.java | 59 +++++-- .../apache/cordova/SplashScreenPlugin.java | 46 +++--- .../cordova/engine/SystemCookieManager.java | 5 + .../cordova/engine/SystemExposedJsApi.java | 3 + .../cordova/engine/SystemWebChromeClient.java | 109 +++++++++--- .../cordova/engine/SystemWebViewClient.java | 26 +++ .../cordova/engine/SystemWebViewEngine.java | 17 +- .../platforms/android/android.json | 11 +- .../platforms/android/app/build.gradle | 53 +++++- .../android/app/google-services.json | 155 ------------------ .../android/app/src/main/AndroidManifest.xml | 14 +- .../app/src/main/assets/www/cordova.js | 2 +- .../src/main/assets/www/cordova_plugins.js | 3 +- .../clevertap-cordova/www/CleverTap.js | 11 +- .../main/res/mipmap-hdpi-v26/ic_launcher.xml | 21 ++- .../main/res/mipmap-ldpi-v26/ic_launcher.xml | 21 ++- .../main/res/mipmap-mdpi-v26/ic_launcher.xml | 21 ++- .../main/res/mipmap-xhdpi-v26/ic_launcher.xml | 21 ++- .../res/mipmap-xxhdpi-v26/ic_launcher.xml | 21 ++- .../res/mipmap-xxxhdpi-v26/ic_launcher.xml | 21 ++- .../android/app/src/main/res/xml/config.xml | 6 +- .../platforms/android/cdv-gradle-config.json | 2 +- ...dova-android-support-gradle-release.gradle | 29 ---- .../platforms/android/platform_www/cordova.js | 2 +- .../android/platform_www/cordova_plugins.js | 3 +- .../clevertap-cordova/www/CleverTap.js | 11 +- .../platforms/android/project.properties | 35 +++- .../platforms/android/wrapper.gradle | 1 - 45 files changed, 541 insertions(+), 364 deletions(-) delete mode 100644 Samples/Cordova/ExampleProject/platforms/android/app/google-services.json delete mode 100644 Samples/Cordova/ExampleProject/platforms/android/cordova-android-support-gradle-release/example-cordova-android-support-gradle-release.gradle delete mode 100644 Samples/Cordova/ExampleProject/platforms/android/wrapper.gradle 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..9214d7fb 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 @@ - + + + @@ -21,9 +24,14 @@ + - + + + + + 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/res/mipmap-hdpi-v26/ic_launcher.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher.xml index be316184..6555f936 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher.xml @@ -1,5 +1,24 @@ + - \ No newline at end of file + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher.xml index be316184..6555f936 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher.xml @@ -1,5 +1,24 @@ + - \ No newline at end of file + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher.xml index be316184..6555f936 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher.xml @@ -1,5 +1,24 @@ + - \ No newline at end of file + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher.xml index be316184..6555f936 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher.xml @@ -1,5 +1,24 @@ + - \ No newline at end of file + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher.xml index be316184..6555f936 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher.xml @@ -1,5 +1,24 @@ + - \ No newline at end of file + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher.xml index be316184..6555f936 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher.xml @@ -1,5 +1,24 @@ + - \ No newline at end of file + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/xml/config.xml b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/xml/config.xml index f84203a2..8a86fc50 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/xml/config.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/xml/config.xml @@ -1,8 +1,5 @@ - - - ExampleProject A sample Apache Cordova application that responds to the deviceready event. @@ -26,4 +23,7 @@ + + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/cdv-gradle-config.json b/Samples/Cordova/ExampleProject/platforms/android/cdv-gradle-config.json index dda634fc..fe832fa4 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/cdv-gradle-config.json +++ b/Samples/Cordova/ExampleProject/platforms/android/cdv-gradle-config.json @@ -1 +1 @@ -{"MIN_SDK_VERSION":21,"SDK_VERSION":33,"COMPILE_SDK_VERSION":null,"GRADLE_VERSION":"7.6","MIN_BUILD_TOOLS_VERSION":"33.0.2","AGP_VERSION":"7.4.2","KOTLIN_VERSION":"1.7.21","ANDROIDX_APP_COMPAT_VERSION":"1.6.1","ANDROIDX_WEBKIT_VERSION":"1.6.0","ANDROIDX_CORE_SPLASHSCREEN_VERSION":"1.0.0","GRADLE_PLUGIN_GOOGLE_SERVICES_VERSION":"4.3.15","IS_GRADLE_PLUGIN_GOOGLE_SERVICES_ENABLED":true,"IS_GRADLE_PLUGIN_KOTLIN_ENABLED":false,"PACKAGE_NAMESPACE":"com.clevertap.example","MAX_SDK_VERSION":33} +{"MIN_SDK_VERSION":21,"SDK_VERSION":33,"COMPILE_SDK_VERSION":null,"GRADLE_VERSION":"8.7","MIN_BUILD_TOOLS_VERSION":"34.0.0","AGP_VERSION":"8.3.0","KOTLIN_VERSION":"1.9.24","ANDROIDX_APP_COMPAT_VERSION":"1.6.1","ANDROIDX_WEBKIT_VERSION":"1.6.0","ANDROIDX_CORE_SPLASHSCREEN_VERSION":"1.0.0","GRADLE_PLUGIN_GOOGLE_SERVICES_VERSION":"4.3.15","IS_GRADLE_PLUGIN_GOOGLE_SERVICES_ENABLED":true,"IS_GRADLE_PLUGIN_KOTLIN_ENABLED":false,"PACKAGE_NAMESPACE":"com.clevertap.example","JAVA_SOURCE_COMPATIBILITY":8,"JAVA_TARGET_COMPATIBILITY":8,"KOTLIN_JVM_TARGET":null,"MAX_SDK_VERSION":33} diff --git a/Samples/Cordova/ExampleProject/platforms/android/cordova-android-support-gradle-release/example-cordova-android-support-gradle-release.gradle b/Samples/Cordova/ExampleProject/platforms/android/cordova-android-support-gradle-release/example-cordova-android-support-gradle-release.gradle deleted file mode 100644 index f551b028..00000000 --- a/Samples/Cordova/ExampleProject/platforms/android/cordova-android-support-gradle-release/example-cordova-android-support-gradle-release.gradle +++ /dev/null @@ -1,29 +0,0 @@ -repositories{ - // Google APIs are now hosted at Maven - maven { - url 'https://maven.google.com' - } -} - -def ANDROID_SUPPORT_VERSION = "27.+" -def PLUGIN_NAME = "cordova-android-support-gradle-release" - -// List of libs to search for. -def LIBS = [ - 'com.android.support' -] - -def IGNORED = [ - 'multidex', - 'multidex-instrumentation' -] - -println("+-----------------------------------------------------------------"); -println("| " + PLUGIN_NAME + ": " + ANDROID_SUPPORT_VERSION); -println("+-----------------------------------------------------------------"); - -configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - if (details.requested.group in LIBS && !(details.requested.name in IGNORED)) { details.useVersion ANDROID_SUPPORT_VERSION } - } -} diff --git a/Samples/Cordova/ExampleProject/platforms/android/platform_www/cordova.js b/Samples/Cordova/ExampleProject/platforms/android/platform_www/cordova.js index cd613205..291798d0 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/platform_www/cordova.js +++ b/Samples/Cordova/ExampleProject/platforms/android/platform_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/platform_www/cordova_plugins.js b/Samples/Cordova/ExampleProject/platforms/android/platform_www/cordova_plugins.js index 0bb04294..398ee257 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/platform_www/cordova_plugins.js +++ b/Samples/Cordova/ExampleProject/platforms/android/platform_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/platform_www/plugins/clevertap-cordova/www/CleverTap.js b/Samples/Cordova/ExampleProject/platforms/android/platform_www/plugins/clevertap-cordova/www/CleverTap.js index 68f111e0..fcc9c9c5 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/platform_www/plugins/clevertap-cordova/www/CleverTap.js +++ b/Samples/Cordova/ExampleProject/platforms/android/platform_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/project.properties b/Samples/Cordova/ExampleProject/platforms/android/project.properties index b3018ec0..a7082ea9 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/project.properties +++ b/Samples/Cordova/ExampleProject/platforms/android/project.properties @@ -1,3 +1,21 @@ +# 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. + + # This file was originally created by the Android Tools, but is now # used by cordova-android to manage the state of the various third party # libraries used in your application @@ -8,20 +26,19 @@ # This is the application project. This is only required for Android Studio Gradle projects # Project target. -target=android-32 +target=android-34 android.library.reference.1=CordovaLib android.library.reference.2=app -cordova.gradle.include.1=cordova-android-support-gradle-release/example-cordova-android-support-gradle-release.gradle -cordova.system.library.1=com.google.firebase:firebase-messaging:22.0.0 -cordova.system.library.2=com.clevertap.android:clevertap-android-sdk:4.6.6 +cordova.system.library.1=com.google.firebase:firebase-messaging:23.0.6 +cordova.system.library.2=com.clevertap.android:clevertap-android-sdk:6.2.1 cordova.system.library.3=com.github.bumptech.glide:glide:4.12.0 -cordova.system.library.4=androidx.appcompat:appcompat:1.3.1 -cordova.system.library.5=androidx.core:core:1.3.0 +cordova.system.library.4=androidx.appcompat:appcompat:1.6.0-rc01 +cordova.system.library.5=androidx.core:core:1.9.0 cordova.system.library.6=androidx.fragment:fragment:1.3.6 cordova.system.library.7=androidx.recyclerview:recyclerview:1.2.1 cordova.system.library.8=androidx.viewpager:viewpager:1.0.0 cordova.system.library.9=com.google.android.material:material:1.4.0 cordova.system.library.10=com.android.installreferrer:installreferrer:2.2 -cordova.system.library.11=com.google.android.exoplayer:exoplayer:2.17.1 -cordova.system.library.12=com.google.android.exoplayer:exoplayer-hls:2.17.1 -cordova.system.library.13=com.google.android.exoplayer:exoplayer-ui:2.17.1 \ No newline at end of file +cordova.system.library.11=com.google.android.exoplayer:exoplayer:2.19.1 +cordova.system.library.12=com.google.android.exoplayer:exoplayer-hls:2.19.1 +cordova.system.library.13=com.google.android.exoplayer:exoplayer-ui:2.19.1 \ No newline at end of file diff --git a/Samples/Cordova/ExampleProject/platforms/android/wrapper.gradle b/Samples/Cordova/ExampleProject/platforms/android/wrapper.gradle deleted file mode 100644 index d7ebabd7..00000000 --- a/Samples/Cordova/ExampleProject/platforms/android/wrapper.gradle +++ /dev/null @@ -1 +0,0 @@ -//This file is intentionally just a comment From c222f258590b16b8a63f213b299a42381be66501 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 16:38:38 +0530 Subject: [PATCH 07/13] task(SDK-3980) - Updates sample app --- .../clevertap/cordova/CleverTapPlugin.java | 2702 ++++++++++++++++- .../ic_launcher_monochrome.png | Bin 0 -> 1400 bytes .../ic_launcher_monochrome.png | Bin 0 -> 916 bytes .../ic_launcher_monochrome.png | Bin 0 -> 1829 bytes .../ic_launcher_monochrome.png | Bin 0 -> 2911 bytes .../ic_launcher_monochrome.png | Bin 0 -> 4025 bytes .../res/xml/cdv_core_file_provider_paths.xml | 30 + .../platforms/android/tools/settings.gradle | 29 + 8 files changed, 2760 insertions(+), 1 deletion(-) mode change 120000 => 100644 Samples/Cordova/ExampleProject/platforms/android/app/src/main/java/com/clevertap/cordova/CleverTapPlugin.java create mode 100644 Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_monochrome.png create mode 100644 Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher_monochrome.png create mode 100644 Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_monochrome.png create mode 100644 Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_monochrome.png create mode 100644 Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_monochrome.png create mode 100644 Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/xml/cdv_core_file_provider_paths.xml create mode 100644 Samples/Cordova/ExampleProject/platforms/android/tools/settings.gradle 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 variable = (Var) variables.get(finalVariableName); + variable.addValueChangedCallback(new VariableCallback() { + @Override + public void onValueChanged(final Var variable) { + 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("setLocale")) { + 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(new Runnable() { + public void run() { + cleverTap.setLocale(finalVariableName); + PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT); + _result.setKeepCallback(true); + callbackContext.sendPluginResult(_result); + } + }); + return true; + } + } + else if (action.equals("clearInAppResources")) { + boolean expiredOnly = false; + if(args.length() == 1) { + expiredOnly = args.getBoolean(0); + } else { + haveError = true; + errorMsg = "Expected 1 argument"; + } + if (!haveError) { + final boolean finalExpiredOnly = expiredOnly; + cordova.getThreadPool().execute(new Runnable() { + public void run() { + cleverTap.clearInAppResources(finalExpiredOnly); + PluginResult _result = new PluginResult(PluginResult.Status.NO_RESULT); + _result.setKeepCallback(true); + callbackContext.sendPluginResult(_result); + } + }); + return true; + } + } else if (action.equals("fetchInApps")) { + cordova.getThreadPool().execute(() -> { + cleverTap.fetchInApps(isSuccess -> { + PluginResult _result = new PluginResult(PluginResult.Status.OK, isSuccess); + _result.setKeepCallback(true); + callbackContext.sendPluginResult(_result); + }); + + }); + return true; + } + + result = new PluginResult(PluginResult.Status.ERROR, errorMsg); + result.setKeepCallback(true); + callbackContext.sendPluginResult(result); + return true; + } + + @NonNull + private JSONObject getVariablesAsJson() { + JSONObject jsonVariables = new JSONObject(); + for (String key : variables.keySet()) { + try { + jsonVariables.put(key,getVariableValue(key)); + } catch (Exception e) { + e.printStackTrace(); + } + } + return jsonVariables; + } + + @NonNull + private PluginResult getPluginResult(final Status ok, final Object value) { + PluginResult _result; + if (value instanceof Boolean) { + _result = new PluginResult(ok, (Boolean) value); + } else if (value instanceof Double) { + _result = new PluginResult(ok, ((Double) value).floatValue()); + } else if (value instanceof Float) { + _result = new PluginResult(ok, (Float) value); + } else if (value instanceof Integer) { + _result = new PluginResult(ok, (Integer) value); + } else if (value instanceof Long) { + _result = new PluginResult(ok, ((Long) value).intValue()); + } else if (value instanceof String) { + _result = new PluginResult(ok, (String) value); + } else if (value instanceof JSONObject) { + _result = new PluginResult(ok, (JSONObject) value); + } else { + _result = new PluginResult(PluginResult.Status.ERROR, "unknown value type"); + } + + return _result; + } + + //DisplayUnitListener + + public void onDisplayUnitsLoaded(ArrayList units) { + + try { + final JSONArray unitsArray = displayUnitListToJSONArray(units); + + final String json = "{'units':" + unitsArray.toString() + "}"; + + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapDisplayUnitsLoaded'," + json + ");"); + } + }); + + } catch (JSONException e) { + Log.d(LOG_TAG, "JSONException in onDisplayUnitsLoaded" + e); + } + + } + + //CTInboxListener + + public void inboxDidInitialize() { + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapInboxDidInitialize');"); + } + }); + } + + public void inboxMessagesDidUpdate() { + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapInboxMessagesDidUpdate');"); + } + }); + } + + + // InAppNotificationListener + + public boolean beforeShow(Map var1) { + return true; + } + + public void onDismissed(Map var1, Map var2) { + if (var1 == null && var2 == null) { + return; + } + + JSONObject extras = var1 != null ? new JSONObject(var1) : new JSONObject(); + String _json = "{'extras':" + extras.toString() + ","; + + JSONObject actionExtras = var2 != null ? new JSONObject(var2) : new JSONObject(); + _json += "'actionExtras':" + actionExtras.toString() + "}"; + + final String json = _json; + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapInAppNotificationDismissed'," + json + ");"); + } + }); + } + + @Override + public void onPushPermissionResponse(final boolean accepted) { + final String json = "{'accepted':" + accepted + "}"; + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapPushPermissionResponseReceived'," + json + ");"); + } + }); + } + + // SyncListener + public void profileDataUpdated(JSONObject updates) { + + if (updates == null) { + return; + } + + final String json = "{'updates':" + updates.toString() + "}"; + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapProfileSync'," + json + ");"); + } + }); + } + + public void profileDidInitialize(String CleverTapID) { + + if (CleverTapID == null) { + return; + } + + final String json = "{'CleverTapID':" + "'" + CleverTapID + "'" + "}"; + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapProfileDidInitialize'," + json + ");"); + } + }); + } + + //Inbox/InApp Button Click Listeners + + public void onInboxButtonClick(HashMap payload) { + JSONObject jsonPayload = new JSONObject(payload); + + final String json = "{'customExtras':" + jsonPayload.toString() + "}"; + + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapInboxButtonClick'," + json + ");"); + } + }); + } + + @Override + public void onShow(CTInAppNotification inAppNotification) { + if(inAppNotification != null && inAppNotification.getJsonDescription() != null){ + //Read the values + final String json = "{'customExtras':" + inAppNotification.getJsonDescription().toString() + "}"; + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapInAppNotificationShow'," + json + ");"); + } + }); + } + } + + public void onInboxItemClicked(CTInboxMessage message, int contentPageIndex, int buttonIndex){ + if(message != null && message.getData() != null){ + //Read the values + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("data",message.getData()); + jsonObject.put("contentPageIndex",contentPageIndex); + jsonObject.put("buttonIndex",buttonIndex); + } catch (JSONException e) { + Log.e(LOG_TAG,"Failed to parse inbox message."); + } + + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapInboxItemClick'," + jsonObject + ");"); + } + }); + } + } + + //InApp Notification callback + public void onInAppButtonClick(HashMap hashMap) { + JSONObject jsonPayload = new JSONObject(hashMap); + final String json = "{'customExtras':" + jsonPayload.toString() + "}"; + + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapInAppButtonClick'," + json + ");"); + } + }); + } + + //Feature Flag Listener + public void featureFlagsUpdated() { + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapFeatureFlagsDidUpdate');"); + } + }); + } + + //Product Config Listener + public void onInit() { + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapProductConfigDidInitialize');"); + } + }); + } + + public void onFetched() { + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapProductConfigDidFetch');"); + } + }); + } + + public void onActivated() { + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapProductConfigDidActivate');"); + } + }); + } + + /******************* + * Private Methods + ******************/ + + private static boolean checkCleverTapInitialized() { + boolean initialized = (cleverTap != null); + if (!initialized) { + Log.d(LOG_TAG, "CleverTap API not initialized: " + CLEVERTAP_API_ERROR); + } + return initialized; + } + + private static HashMap formatProfile(JSONObject jsonProfile) { + try { + HashMap profile = toMap(jsonProfile); + return profile; + } catch (Throwable t) { + return null; + } + } + + private static Object fromJson(Object json) throws JSONException { + if (json == JSONObject.NULL) { + return null; + } else if (json instanceof JSONObject) { + return toMap((JSONObject) json); + } else { + return json; + } + } + + private static CTInboxStyleConfig toStyleConfig(JSONObject object) throws JSONException { + CTInboxStyleConfig styleConfig = new CTInboxStyleConfig(); + if (object.has("navBarColor")) { + styleConfig.setNavBarColor(object.getString("navBarColor")); + } + if (object.has("navBarTitle")) { + styleConfig.setNavBarTitle(object.getString("navBarTitle")); + } + if (object.has("navBarTitleColor")) { + styleConfig.setNavBarTitleColor(object.getString("navBarTitleColor")); + } + if (object.has("inboxBackgroundColor")) { + styleConfig.setInboxBackgroundColor(object.getString("inboxBackgroundColor")); + } + if (object.has("backButtonColor")) { + styleConfig.setBackButtonColor(object.getString("backButtonColor")); + } + if (object.has("selectedTabColor")) { + styleConfig.setSelectedTabColor(object.getString("selectedTabColor")); + } + if (object.has("unselectedTabColor")) { + styleConfig.setUnselectedTabColor(object.getString("unselectedTabColor")); + } + if (object.has("selectedTabIndicatorColor")) { + styleConfig.setSelectedTabIndicatorColor(object.getString("selectedTabIndicatorColor")); + } + if (object.has("tabBackgroundColor")) { + styleConfig.setTabBackgroundColor(object.getString("tabBackgroundColor")); + } + if (object.has("tabs")) { + JSONArray tabsArray = object.getJSONArray("tabs"); + ArrayList tabs = new ArrayList(); + for (int i = 0; i < tabsArray.length(); i++) { + tabs.add(tabsArray.getString(i)); + } + styleConfig.setTabs(tabs); + } + return styleConfig; + } + + private static HashMap toMap(JSONObject object) throws JSONException { + HashMap map = new HashMap(); + Iterator keys = object.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + map.put(key, fromJson(object.get(key))); + } + return map; + } + + private static ArrayList> toArrayListOfStringObjectMaps(JSONArray array) throws JSONException { + ArrayList> aList = new ArrayList>(); + + for (int i = 0; i < array.length(); i++) { + aList.add(toMap((JSONObject) array.get(i))); + } + + return aList; + } + + private static JSONObject eventDetailsToJSON(EventDetail details) throws JSONException { + + JSONObject json = new JSONObject(); + + if (details != null) { + json.put("name", details.getName()); + json.put("firstTime", details.getFirstTime()); + json.put("lastTime", details.getLastTime()); + json.put("count", details.getCount()); + } + + return json; + } + + private static JSONObject utmDetailsToJSON(UTMDetail details) throws JSONException { + + JSONObject json = new JSONObject(); + + if (details != null) { + json.put("campaign", details.getCampaign()); + json.put("source", details.getSource()); + json.put("medium", details.getMedium()); + } + + return json; + } + + private static JSONObject eventHistoryToJSON(Map history) throws JSONException { + + JSONObject json = new JSONObject(); + + if (history != null) { + for (Object key : history.keySet()) { + json.put(key.toString(), eventDetailsToJSON(history.get((String) key))); + } + } + + return json; + } + + private static JSONArray listToJSONArray(List list) throws JSONException { + JSONArray array = new JSONArray(); + + for (int i = 0; i < list.size(); i++) { + array.put(list.get(i)); + } + + return array; + } + + private List toBooleanList(JSONArray array) throws JSONException { + ArrayList list = new ArrayList(); + for (int i = 0; i < array.length(); i++) { + list.add(array.getBoolean(i)); + } + return list; + } + + private List toDoubleList(JSONArray array) throws JSONException { + ArrayList list = new ArrayList(); + for (int i = 0; i < array.length(); i++) { + list.add(array.getDouble(i)); + } + return list; + } + + private List toIntegerList(JSONArray array) throws JSONException { + ArrayList list = new ArrayList(); + for (int i = 0; i < array.length(); i++) { + list.add(array.getInt(i)); + } + return list; + } + + private List toStringList(JSONArray array) throws JSONException { + ArrayList list = new ArrayList(); + for (int i = 0; i < array.length(); i++) { + list.add(array.getString(i)); + } + return list; + } + + private static HashMap toBooleanMap(JSONObject object) throws JSONException { + HashMap map = new HashMap(); + Iterator keys = object.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + map.put(key, object.getBoolean(key)); + } + return map; + } + + private static HashMap toDoubleMap(JSONObject object) throws JSONException { + HashMap map = new HashMap(); + Iterator keys = object.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + map.put(key, object.getDouble(key)); + } + return map; + } + + private static HashMap toIntegerMap(JSONObject object) throws JSONException { + HashMap map = new HashMap(); + Iterator keys = object.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + map.put(key, object.getInt(key)); + } + return map; + } + + private static HashMap toStringMap(JSONObject object) throws JSONException { + HashMap map = new HashMap(); + Iterator keys = object.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + map.put(key, object.getString(key)); + } + return map; + } + + private Object getVariableValue(String name) { + if (variables.containsKey(name)) { + Var variable = (Var) variables.get(name); + Object variableValue = variable.value(); + Object value; + if (CTVariableUtils.DICTIONARY.equals(variable.kind())) { + value = new JSONObject((Map) variableValue); + } else { + value = variableValue; + } + return value; + } + throw new IllegalArgumentException( + "Variable name = " + name + " does not exist. Make sure you set variable first."); + } + + private JSONArray displayUnitListToJSONArray(ArrayList displayUnits) throws JSONException { + JSONArray array = new JSONArray(); + + if (displayUnits == null) { + return array; + } + + for (int i = 0; i < displayUnits.size(); i++) { + array.put(displayUnits.get(i).getJsonObject()); + } + + return array; + } + + private JSONArray inboxMessageListToJSONArray(ArrayList messageList) throws JSONException { + JSONArray array = new JSONArray(); + + for (int i = 0; i < messageList.size(); i++) { + array.put(messageList.get(i).getData()); + } + + return array; + } + + public void onNotificationClickedPayloadReceived(HashMap payload) { + + JSONObject jsonPayload = new JSONObject(payload); + + final String json = "{'customExtras':" + jsonPayload.toString() + "}"; + + webView.getView().post(new Runnable() { + public void run() { + + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapPushNotificationTappedWithCustomExtras'," + json + ");"); + } + }); + callbackDone = true; + } + + public void onPushAmpPayloadReceived(Bundle extras) { + JSONObject jsonPayload = toJson(extras); + + final String json = "{'customExtras':" + jsonPayload.toString() + "}"; + + webView.getView().post(new Runnable() { + public void run() { + webView.loadUrl("javascript:cordova.fireDocumentEvent('onCleverTapPushAmpPayloadDidReceived'," + json + ");"); + } + }); + } + + private JSONObject toJson(Bundle bundle) { + JSONObject json = new JSONObject(); + Set keys = bundle.keySet(); + for (String key : keys) { + try { + // json.put(key, bundle.get(key)); see edit below + json.put(key, JSONObject.wrap(bundle.get(key))); + } catch (JSONException e) { + //Handle exception here + } + } + return json; + } + + private boolean isDeepLinkValid(Uri data) { + String link = Uri.decode(data.toString()); + String patternString = "[{}\\[\\]()\"';]|javascript"; + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(link); + return !matcher.find(); + } + + private JSONObject processPushPrimerArgument(JSONObject jsonObject) { + CTLocalInApp.InAppType inAppType = null; + String titleText = null, messageText = null, positiveBtnText = null, negativeBtnText = null, + backgroundColor = null, btnBorderColor = null, titleTextColor = null, messageTextColor = null, + btnTextColor = null, imageUrl = null, btnBackgroundColor = null, btnBorderRadius = null; + boolean fallbackToSettings = false, followDeviceOrientation = false; + + final Iterator iterator = jsonObject.keys(); + while (iterator.hasNext()) { + try { + final String configKey = iterator.next(); + switch (configKey) { + case "inAppType": + inAppType = inAppTypeFromString(jsonObject.getString(configKey)); + break; + case "titleText": + titleText = jsonObject.getString(configKey); + break; + case "messageText": + messageText = jsonObject.getString(configKey); + break; + case "followDeviceOrientation": + followDeviceOrientation = jsonObject.getBoolean(configKey); + break; + case "positiveBtnText": + positiveBtnText = jsonObject.getString(configKey); + break; + case "negativeBtnText": + negativeBtnText = jsonObject.getString(configKey); + break; + case "fallbackToSettings": + fallbackToSettings = jsonObject.getBoolean(configKey); + break; + case "backgroundColor": + backgroundColor = jsonObject.getString(configKey); + break; + case "btnBorderColor": + btnBorderColor = jsonObject.getString(configKey); + break; + case "titleTextColor": + titleTextColor = jsonObject.getString(configKey); + break; + case "messageTextColor": + messageTextColor = jsonObject.getString(configKey); + break; + case "btnTextColor": + btnTextColor = jsonObject.getString(configKey); + break; + case "imageUrl": + imageUrl = jsonObject.getString(configKey); + break; + case "btnBackgroundColor": + btnBackgroundColor = jsonObject.getString(configKey); + break; + case "btnBorderRadius": + btnBorderRadius = jsonObject.getString(configKey); + break; + } + } catch (Throwable t) { + Log.e(LOG_TAG, "invalid parameters in push primer config" + t.getLocalizedMessage()); + return null; + } + } + + //creates the builder instance of localInApp with all the required parameters + CTLocalInApp.Builder.Builder6 builderWithRequiredParams = getLocalInAppBuilderWithRequiredParam( + inAppType, titleText, messageText, followDeviceOrientation, positiveBtnText, negativeBtnText + ); + + //adds the optional parameters to the builder instance + if (backgroundColor != null) { + builderWithRequiredParams.setBackgroundColor(backgroundColor); + } + if (btnBorderColor != null) { + builderWithRequiredParams.setBtnBorderColor(btnBorderColor); + } + if (titleTextColor != null) { + builderWithRequiredParams.setTitleTextColor(titleTextColor); + } + if (messageTextColor != null) { + builderWithRequiredParams.setMessageTextColor(messageTextColor); + } + if (btnTextColor != null) { + builderWithRequiredParams.setBtnTextColor(btnTextColor); + } + if (imageUrl != null) { + builderWithRequiredParams.setImageUrl(imageUrl); + } + if (btnBackgroundColor != null) { + builderWithRequiredParams.setBtnBackgroundColor(btnBackgroundColor); + } + if (btnBorderRadius != null) { + builderWithRequiredParams.setBtnBorderRadius(btnBorderRadius); + } + builderWithRequiredParams.setFallbackToSettings(fallbackToSettings); + + JSONObject localInAppConfig = builderWithRequiredParams.build(); + Log.i(LOG_TAG, "LocalInAppConfig for push primer prompt: " + localInAppConfig); + return localInAppConfig; + + + } + + /** + * Creates an instance of the {@link CTLocalInApp.Builder.Builder6} with the required parameters. + * + * @return the {@link CTLocalInApp.Builder.Builder6} instance + */ + private CTLocalInApp.Builder.Builder6 getLocalInAppBuilderWithRequiredParam(CTLocalInApp.InAppType inAppType, + String titleText, + String messageText, + boolean followDeviceOrientation, + String positiveBtnText, + String negativeBtnText) { + //throws exception if any of the required parameter is missing + if (inAppType == null || titleText == null || messageText == null || positiveBtnText == null + || negativeBtnText == null) { + throw new IllegalArgumentException("mandatory parameters are missing in push primer config"); + } + + CTLocalInApp.Builder builder = CTLocalInApp.builder(); + + return builder.setInAppType(inAppType) + .setTitleText(titleText) + .setMessageText(messageText) + .followDeviceOrientation(followDeviceOrientation) + .setPositiveBtnText(positiveBtnText) + .setNegativeBtnText(negativeBtnText); + } + + //returns InAppType type from the given string + private CTLocalInApp.InAppType inAppTypeFromString(String inAppType) { + if (inAppType == null) { + return null; + } + switch (inAppType) { + case "half-interstitial": + return CTLocalInApp.InAppType.HALF_INTERSTITIAL; + case "alert": + return CTLocalInApp.InAppType.ALERT; + default: + return null; + } + } +} \ No newline at end of file diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_monochrome.png b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..d13e3f5711189f7aa4a78725222b935e3eed050b GIT binary patch literal 1400 zcma)6`#%#36rbDNSRq}sP13x=l2^E`BsG_XHR>v}#Lc)Kb7QyUnml@4*Tz0WnPh1+ zG8-F_*Ge~SHj~>T@0M4t$0V=v*qzVk{sEoO=X<`N?>XP|Ip?R7fkAs}fuJA&0HB5P zLi($ixe1N$Re3yyld2-kOJ0FQ0ANSqCe$oC5C>I7HKM=gaR5iUdr~EU5$?Y306=y2 zwzW`o06<*}g>*l2Rc&T)FwWFN@0L89k>msHhg2b-QPV`nkg1CL+>F#6+jXbI_x_+3 z1B@~`M-=7x@vr1XdGq^Ob)}QU@#M!1Y=250bg_#*$$+3#OTICVVb0#>x#hlc7jI0u za-_Sk42I4acEmbuMNvGkt=OD$Pj}cBr7@GY1{^_aM4P&$t>7$RCCw!D56pmWdZ72# z@QUigHpGt-V9qGqu;s$gUs4}%!n{6-)sDXOo9PAj{I*V!9g?lHwL$G+8 z1P?N(aGE43Alv#XTKtr3?vj!n=E}zMK1wl)VEFm)aZ$jNklwN(vn0C~Hg^c8th8gB z1znuQ6AA2L==4h|CZS&HQ=%;ia25zHj85L6EMmSk{@c0Ldr+{aU8fbp4ip#Y+m<)E zh+BMAN~^xBK2~ocvlbEbGO8(lrFJ{4iw;53n&r;W;mVlRza98$16Jd(O7p`lI}P4A z$l~E{vG`#D>KsxO-_6b+_4K~7K>Kpy3u=iSw=YH2>NJ!;Jo$ZP>-hgh%wO;ENq)#3F@OprM^j&%nakJg#seuFZwF`Z&IEB=kY>-J6eC0&`*1cSl6h znJTpW5I6{7KO7L7Q0SiX)yp$mzd5O{!h6{qRIKEb^YPT85S*|yJTyvY zrn#1+iOn*2F}Ir>c*R>iAoFL6y}?i?q>}!?+;M|>biQk(V42WCwqd-&G;#YxymG>O z(n9^&Ep8H-+dfg-dPv=JNR76lqkwa?I|aS6d7 z#q)gpUF$kA7ELoU%DEq0pGamgpa@9*kvNMli7{ryJg`XH0Oyj3dahTcNoyZ825o%lZS`K0xq_MZ6vH zFX^{jE?`O#f~O~<#rkQXNYGDHbJ9%oVoiSIRcn!jqzYX1;>OO2(B^b|Nz?DTR$zWi+QFW=yBew)63w?P^7XH7CuOE! z)r4pGc9+-2Hee;SqkPYz|Lw>r7-HZ9)hVKl*!{_#H9K`b>_s~E8$Z#eZN*Hf#x=NzcbbL8V0?EBvRo~Se7&F{muHs6HR zCjyN}0}Yn1%iit_`mJQ+ePe6yE7mu8*ToLq(+ky)sQs<=Ms-EqhF{x6)NY^9PsmQ3 z#k>Q+AY&DESyZq>l_WbUnk zb^jfuKgU*Pp4x46OsD7Z{Arx46=NO1;PQRq0Fr z>|JA8Jon93^%e6b=~!R(S=v5%+3v7StG7?Gbv<9i{=_LaHGKUO)k9v!DZaMZKX*=( zH4)E$sxI}{v2Km#dpAED=5NPe@P88S`4?^Zk>|#?gfpG5xLK3aW+tlEe<@t1|K?V@ z?{&?16PBBc(lp+_jpVMLZnaOU!tFD?|dKrSaO4k)ZgQ)-d}l9etO*z>x8h( zeA_*>5jPW4Z^T<>*&Z(9f4}X6jPvb-ADta5H=o;(@#T3}^Xx;#Jby3!a6TWKUvW25 zOY`mVRofQ)wQCbIdako`{?fEHDd~Hj{r301`Tg;)YhB-`LF{_L#C4*z;S zqtx@hw&v34Ow-MOJ#}j&7yZw;saQ}Sr@JOG)2k;dK7=`nBcg~S+Zo84CD;7=7U%!OM+Wgp&iTA&kT3hsoUUD~GFqNmv6g);aQUT=L=4AHVc{WZpjtFv>A3tm#}^*sExiqmcG%5A!u2(c3`>*0d+(p79fv n|0~zC(buOPEfE8`2VVbTx0;z5b|iJ<5s<8>tDnm{r-UW|ci5#z literal 0 HcmV?d00001 diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_monochrome.png b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..0130c55580fc57b7825d309bb0e1cb4a1bf7844c GIT binary patch literal 1829 zcmb7F`#T#57ER(ks48SU57oDN9 zjfzB-6|bZ_ByFl#i6Bg9yEJJCn}W64)F>WMxG9{_+{ zskQ=r0y-rwgjWJT2Cegl-Mrw+`c!aVhJH!^)`n8ys;yC$-i-PFqZiB&}$TZ>;1KS z8F^F(R%6rPU+fzH$OJ*d24Lzj8t}5NRa(b~UrCuUTy>M|YK(?IQ`Sx`IZ(0RzuHt# zK{!e4D3Kev?XKgJty*|dv*|c9BYyfFz^Wq^R306V#2!MLOSBLtZ!YtUU?v}760OUv;L*olcEyexIy>=&g&?sgOohLkOJx-sxFm{=M4 z;UW#&3)Nsm#PRhJ011}tYE{;2Fp?W!mTSV8*J$v~v z?hss35FtE-?f=kpFqxE$6(gLOY~vG2rz*`NPHDV6E>>1C3C9Ycoo%CT9#$=^ihq=7 z|uaBQ!bQN&9N#g zjjdYEZSxDu1(5LV4=fj*hSBU6XqeR9J~t}?UN{roX%HbxA|rC8wy^J@b?ocCy}MB9 zJB$@2!+bF%rl)Tq$vrP3BU02?!WThrd72qTrT-MZL zM?5=Ek97E$IDxv-V#4V=Xn7+sMO{;k@%~MP!HMb%u%0dM<+2N+!3q8zp%FW^i;zP) z_0gmw50b={2Wa`M!xbi~^@bse?X%k$RC@LO|K+^p@u3Oc5;6mkr%%E=vD?>g4b3wh z)Bi0Lh#f>3qyJjJxFVTn_qNjj{bw^tIWag0#be?SogK_=L$xoxqRR!bQ+W~-q&t} zL5ir~V%hqOJn6YRwf}Q|5kiwrcNZ1CD#Ecat+c$HW_dz0FY(S?5~tE*e+qrMVCO$M z`~}f}2l15D>#rQpATe40iNzcQ|1*X@vWF;BTGO+h?gF?@?yqO#>}P)^T=;U>X*N`d zICSB>nEy?_Hd}btx0oFy^{qI~Ac(q$d-?`-NN(+Yba#ViQQ2ysr&Hg!Pa@!{S#!mJ zlv-NFj!`CjrSXl*6GgP4C&F8818)3CI6EoQwFtj_+xd3H)tAJo_j*K~^%qzm5 zq_7c}+!hbNpY+B1@rnV%E?sHbgXJ{)w{?*Igd--v>?zcZX-i>8;@VQ_ObyxCOgI4P zfBRtd7r=0ASpVGSg+;FVf67N!047Wh0 zI+7ARMU>{3X6#@%yf7rz9T%fR8YbvQa=t{ptJvrU9?xH~rEU>4sl+R=N!Tb-lnE~f z(ZL`g@v#=&CZ2?hnG9Q@1{8mGU6xNWeLr$$ic#9yFG6b zP9+4TOGj`HZ>#p|y^Ff-sNSa&#$xGW`qi$6(E)AJH24zXtOQypm5@HBKimHbC>w&f z@*F=c1zCjKVN(rJ?G_PYx>nnndwQ}NPalmVfAL$W>}{`|eXhohWm+_IJ}(FQhxifC Hqe}h+$?$z_ literal 0 HcmV?d00001 diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_monochrome.png b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..194cc2c35a7875c495e3c1fcba260edebd0eb723 GIT binary patch literal 2911 zcmcgui8q_s8xB%CO{;WM;k2qUmO&BwQfi6NCe+ea7)?>FrBO>FmbSK;O1co#U|Q7B zRvJrVH!78>CAJW1iKS&k6h*Wm`uqImf0*x_d%pWV&-*^_bHDGNdv4|hcP9neW3nI+ zNWsO~0R;kyIqVH-NdUp{oH~J*Or*0f4g}JG?+r0Wia`JXis4XB_Mj@3>LL(;gYA%Z zAP|i#w-dMz1d`owaj^4@6I-4fc%#4ygNbyTvd5C$`^)W#>!dTenQOZU8adl{#u=n zstOY*>k)2p@&e3$FHS4@j`P&F>IwX|!dZ@o%RhlJ4c|MsMijS%>#E*$$q6zT<#Mkk z&rDpy1VuXCNIRqWPIEo#O3(qpCBLax$Q={@Qy{563x-9U_EEG?txrO`l|BflQe1%1 zQYQ^7s*~t}U|dez;Q%AkG0vxsqaQW-6vRBSsnek=#Lw*wpW>1uYRt;aK9CtA*x#2~v!Lf<2l%Uhksf96 z`M9LYHGU74OL(X)tWpfl86F;aPJo5DpuP;|d#Xa;_USxz`g$?Gk54^029b47(=Bez8ECi;OY>w}>qpD@5?B75*LJ^$#YGK) zk(3vr#VjuCE z75abj24HMm&w#`B>PBxz=E|lUm-Sr-aZ6cOh^zty%kKJ|e>69bpR`02<3hjPJGV5D z2{X-TAuOy|_U27lbv9hBZaut+)0^q9s#tNzSvo;2++{KI$V-zebD<+!qBa^GYN8e( zPis>PviCsY%m^QTkPCa0f@%?sh{SJWNriX3h;3X>So*0}!0HmPxfXo65zx5h$Fzjq z6e{t7HqqzyP`)jn%6T zXbIXn)G7VX7WbL(|=!M6jE4b5UH^;vCYMZ)|gw~BJ}iDcV} z^JLj5SDP?*AAWl_9>!3RX58YhrJ&Jy$iFW^}d{Jz;S7+vkf#(;gSc+_!SqMNTr zw{XKb?cI9>vPxbr@983Z4FPBlsGw`zjuNBfpEW4V@n87EJ}LO&AxF+T<9G?@LI zQeUWM`eh40%63LLOvUQxF8xD0Bg6zMiAP!JZjSJqb@zMw>IQ|%VKA<#aRL9LUz!OD z46}fd#%o0=5A|>d_3&Ww@%Prz>AfKYfmPCUU7g+{XV;p`yx(;mJR9S;omX9yZod=X zIrz0>MNsgn<1I!?3qr49mYMcJ<8ConLe7dv7(X)b(%e&HPwpjfo^1BaZ0!^#_5GMM zENc6d^z5tSh()LNrf2%`gBjyIgIyEs)s;&a4Au>Ighjsa4Lw4foyx}R-kc8(MBt29 zo7jGYl2I!6`$}EsJgm04;t+=&#B~}^yydJO9tPNDwX)27@5M#x<DCmza1UB)@rv0ui8h{pa@^srSAr!uj)_ve=SUNHO5 z$rS*GmS{DZQ4F$a*;EMKu83qi;Sc;nS!kGRi;9URgw8=llrEfJ8P3L2CT_Z^hkK;f z@3%_yd<9N!_GMih6Rh?;8R+E(ZpMp0uUWR+{2qV6WZ`kVyp>*ojRM)Ytf>35m^8y+ zqyAYNN1~h*;%bEmmsE!^`%zR*c%Rd?ivkybu4UK2g=_eoJfGV}pcJ?yBBFC-j```B zNw5t-HXrq*^5fQxp6bsSBo^XL(oQ75PU|%AmPW%%zRR{ts!BwDuv83kUMMqHy>F|U z?jGfzC@-Y}VLn6u?k#r?k}(I#SQvf>0nfrG8t?3Jfs}Zib%}DFKdf`Vr}y8=xpzT> zRF+zE@r0s-I_bT_?!wSqzIlRr3Y?uij<)qeF7w#`&l&w{(|@U$k5#_HEl?40(DsVd1031slBwp z<4<75en&{Qs%XUP;^2IWD9rczhrv>2NFZE1%57MAHXBR2ps6R4hcT26W(3`+sH?4! zV{H0nTLB-hieiqi5Ds3RI$s<8ywVVoI`ap3wjO5DyH}*~R>!D}w3&YIV8&c!RTs-- z$Z}8~IHLAqK<3(u2J8==h8ZUrMpPZ!eB8YkSW!9KFb#eN5Pn3Ns^xQ?b48sHDNP7- u7!~#b8`!;@ReSik?1BIGrU(Khuk1)w9}2dfbmgAg>+Ry`?oeePaQA;fPEmLO literal 0 HcmV?d00001 diff --git a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_monochrome.png b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..1e3a4b4e77e1afe59b109a792312031985094605 GIT binary patch literal 4025 zcmds4i8oto_fBGtv0OtbI^1&Q8iE>&v?wKrD^$&KT{Sck1Xlqs~m$tMip=b=L)D*v?>-+r^-&yNjXYXe}``PhmS1*4u8;j$MYc2 zvs}?Ve*q9k(#g*Hyekg8`oTO-+4hFuTo_%(Sf;=PJp{G!Okvm2pbw6oy{ngA=?>q3 z9&b2TJbJ{qNdNWk=SHB`X*qvAKX>=I$eateYB_3Z*8(N*S^O3ycw(w*Cn_2O6#L&e zmZM|!lXUHK*$~=U%3z1uMqaL2fT zcB+QaxuoVr86ji`&YVG#6Ia%JC4CYZGS;RG0c;xqy30bz zUMD&F;78nE%-oOuD#5*=-3YO98q@g6yZ4{qb@mw<91hc+MnHs2Aw?H^3%Fq*{dlCL}As z+nOnuKJy_S)~kwzT?Is6w@!}!{0)sitc0jV4~&f`sQr`r{UtiLcse&~Ss)l( zVr;x2g1M_1-%LSLVUcedW#W<4YqW)y9Su;Bq0#ldaet2RP%X#gU2H;m;LzkKYALeL z9cB)hyTKkEFz#*>ufqvrilJ#hiQytMy_U{K4{*6d#07c21Fd28rfAgSKz~Uw} zEBCwEewRbJL^FXGr&$fiEik*qXc^v>VY1`n{h1u|Z?OsYEDjSG0$a{0>$+uC$Dr($z1ctqFR9u;sx3IQDWCky>V2QbjDu~MRpr!Z~9Z2{?0!4-qxbwCB)(xX1 zd%sx{`&ldK*qmOXI-8Ib=dQ}N9U(p^Q2LW(@w1C36V>YnIL*jeCKVA!ZCn7flI8KU zbEb*vPYD!?!y&FcKBb+Qdtj<)ileDQRO8Ah;EgHHY*9keJBkay0!xGFBd?*SC^>EebJXQw__$Zy~jquT@irZxS4j3 zr+4MS_J$AslN%1hHLY_@OFS6^zHOLp%g$IlSvQo)L4?)wi7m%ESRNyBMRnNpOi*t~ zwJzA_R&!h)kCl5{LSZy;2W2s(yIto|0CTVs68kI3+?H(@q@vR^-F-1TGDIFDJXNi` z^qhRdt%j@$!G3hFKH_`d|99U?y2U7*yi zfSw)uoNS;KJ>1}fcWigcem$>;ooua+$O&1*i??6Q&InY|!cJ;O59^C7lfhawI)umq zMON``2?pNe49wxT%^zmi4?wt;ddqRwhtUCZf7EcDUggg}Y$CV5OO8f|;^dH~r=D=) zdAitQ&a-TN+gI<5I0@`-P1NyArfd@#u;FbDgW$)r6qvk5O#@h% ztm_&=4D(;E@vaQ6P{o6ktcbN^_S}ocPwkO?F!E1Ahy2l?ME zV!6N*exs(;uN&q(=Rk3IAhOWJiP--*5|MX}G2hF^Ew!FRARlZl55W16cbHEm>}Qz< z?9PNX?2oX2Z>Q%3NaXtv&`T#4G{ny1vjgmv&DA>7)wX?F*1e|#W?9+;>r(oeGMIoO z7pvUY-=5hetqwSD#%wd5?MD*cx}>ft-T^5MJbB7-Q`?Tj)f8Xza6*cg9sERR(N+VE z7KpVb1Kd|udFpPHCKFYCUUdH)KjSiKf*d9PnZQ@Kx}8uxbg%Y3Ur7)ACqCL(*TUK) z@_oDW|3Tab@=xC+9u5Ui3RlC=_(!KD;l>x%)t0_A%K|nECvJn!t{T_->@r<8GIb22 zweJ>kt9m?e!19p3m*@VK=M^c_Z=uDi;>*)M#9T4R4}3El8yH!)GH^+cGk^g*a1~Ia z4Ud?^JESnoB9~Omzc~a&eg@`eaM2p;FM{mK=p<6z*Top&{ER{%!+NvtoqBV~2n#Xa z1q?#ZAzXvSb@WLnsLEiFt{UB?yA03JQA@;eupvpq;Q0i30d{SAbGtqFDN&G175tS( zKSR7t2y}?I@QcK+)|!z@-I3xD>^TV5!HvhbABV^JopbbP_}Kr>B~>s73{0M5^{2O* z0n?l9r~7){{(WgJV0fqv)9OdA&XL24R!x_`GxN$-YkM{mJQsyd)9407Dp8HPlrgf9 z5jLcZMF~s{l=`KaYq|NQN@JKcqxRH^OsQlu;Jy~};o`nDMIPkTu8sF6~MI;1wJ%(zp1_7nVC|?EP-osY4l4KDgM<#FTOdni(k)iuMmxZ_DW*{N?dx? z{jb%S@foK1i;$nWg`7AzS?5>~L?gj9!Ghx2)!PwIi*q`-79Swov^6&+BwM!C48)3i2p zMc(7IuP`&d1)e-r8uPvyuJPR22bm1X^4mWVUfWZ-rZeW`=aU8=ysv zQ}<$Tv{R~A`eazwf9z6rN~^j~(AvVF6M#sVF#KEXsJ$d=+hna6#H46Amq4?O_!YR0 zDbxH4hf#eK=LdokA4hFQ5Z3Z!$6o{O>RAZDVPa7|<1&{=*3_FH?D z8+uL!OyBjMcPYsH{o@H5ZuXZaA<*}yXt;7{Rtlj-<3Kx-!f+LRVgsR9gbaWWIKGy@_?lhBuNQv2XEP8%3J-b{5hqkADy{M> z4d;+{X(ynN^U-vxGk6IpYAz{_F}q^#r`3N16Q;cD!>Ol{Xngz%xkcl%x-zWk-(R6k zNhwyM=7Az`6}11jF=^LPVC!8z&`ZqVDG;_0#MDLaq|;O*jlo;*iqA>~)r1_Dv1dz> zmHI=1D}wIvE1c}f_io$cRK@!D}oS^o`8N5`R5 z2vVqkA>eg4cjS;GL59Y!U3-BtDFr>&1PCO~_mH1S?`=&No`R|{B6+qV@Ujh9B0E+2 zY-}jej~g?(yZ0Cvc?N; zH{g+ot@A&fZm%LQ2^KV|d-r%~MUW1d-d{LAqI>U&NO(7w=IXa{n)XBC>NR3{k8a#0 j4ElfLClT1iTpv%h(WkN@OYCOz;il{^I9b + + + + + diff --git a/Samples/Cordova/ExampleProject/platforms/android/tools/settings.gradle b/Samples/Cordova/ExampleProject/platforms/android/tools/settings.gradle new file mode 100644 index 00000000..c6c0f3e6 --- /dev/null +++ b/Samples/Cordova/ExampleProject/platforms/android/tools/settings.gradle @@ -0,0 +1,29 @@ +/* + 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. +*/ + +// This is an empty project used to provide Gradle Tooling +// Using the main project which loads AGP will enforce a minimum version +// requirement on the end-user, requiring a gradle install that satisfies AGP +// version requirements. +// To avoid that, we utilise this empty project of which we can +// freely run the gradle wrapper task against to obtain the +// wrapper at the desired version, without being restricted by AGP's version +// requirements. +// Of course, the installed wrapper must still be of at least the minimum +// required version of AGP for the build to work correctly. From 62c2e4235d2b5fbe9005cc0f2faa60711e882a6c Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 16:40:57 +0530 Subject: [PATCH 08/13] task(SDK-3980) - Update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) 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 From 1949919dd21f8691c2f5e76b48710c5ec494f4e8 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 17:39:25 +0530 Subject: [PATCH 09/13] task(SDK-3980) - Updates CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 683eebe1..f655e333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Version 3.2.0 *(August 12, 2024)* * 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** From c0e007085bfa3620e7f668bbd5ec2538001dbd5c Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 7 Aug 2024 17:39:44 +0530 Subject: [PATCH 10/13] task(SDK-3980) - Updates CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f655e333..c52b0a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Version 3.2.0 *(August 12, 2024)* * 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). +* Migrates `JobScheduler` to `WorkManager` for [Pull Notifications](https://developer.clevertap.com/docs/android-push#pull-notification). #### Bug Fixes **Android Specific** From 398467fa2bbc01f09b884ca80527fabca40ac148 Mon Sep 17 00:00:00 2001 From: anush Date: Fri, 9 Aug 2024 15:45:52 +0530 Subject: [PATCH 11/13] task(SDK-3980) - Updates version in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 02888b2af3b77a47cf0f04141def4e6333957c1e Mon Sep 17 00:00:00 2001 From: anush Date: Fri, 9 Aug 2024 17:28:06 +0530 Subject: [PATCH 12/13] task(SDK-3980) - Updates manifest in sample app --- .../platforms/android/app/src/main/AndroidManifest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 9214d7fb..f71a65ed 100644 --- a/Samples/Cordova/ExampleProject/platforms/android/app/src/main/AndroidManifest.xml +++ b/Samples/Cordova/ExampleProject/platforms/android/app/src/main/AndroidManifest.xml @@ -22,9 +22,9 @@ - - - + + + From e92e5c1d2a510a6e28c64ecd47c134fe896b7875 Mon Sep 17 00:00:00 2001 From: AishwaryaNanna <97506871+AishwaryaNanna@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:05:14 +0530 Subject: [PATCH 13/13] SDK-3977-Move_setLibrary_to_ios_side (#242) * - Updated setLibrary function to work on native side * -Update library version * - Removed xiaomi mehod call from ios side * - Called setLibrary on plugin init --- src/ios/CleverTapPlugin.h | 5 +---- src/ios/CleverTapPlugin.m | 11 ++++------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/ios/CleverTapPlugin.h b/src/ios/CleverTapPlugin.h index 2cf1c17f..531ac200 100644 --- a/src/ios/CleverTapPlugin.h +++ b/src/ios/CleverTapPlugin.h @@ -73,9 +73,8 @@ static NSString * const CTHandleOpenURLNotification = @"CTHandleOpenURLNotificat - (void)setPushToken:(NSData*)pushToken; /** - Xiaomi, Baidu and Huawei Push Token Changes + Baidu and Huawei Push Token Changes */ --(void)setPushXiaomiTokenAsString:(CDVInvokedUrlCommand *)command; -(void)setPushBaiduTokenAsString:(CDVInvokedUrlCommand *)command; -(void)setPushHuaweiTokenAsString:(CDVInvokedUrlCommand *)command; @@ -528,7 +527,5 @@ Called when the value of the variable changes. */ - (void)reset; -- (void)setLibrary: (CDVInvokedUrlCommand *)command; - @end diff --git a/src/ios/CleverTapPlugin.m b/src/ios/CleverTapPlugin.m index b980d218..989bdcff 100644 --- a/src/ios/CleverTapPlugin.m +++ b/src/ios/CleverTapPlugin.m @@ -114,6 +114,7 @@ - (void)pluginInitialize { [[clevertap productConfig] setDelegate:self]; [clevertap setPushNotificationDelegate:self]; [clevertap setInAppNotificationDelegate:self]; + [self setLibrary]; } @@ -398,10 +399,6 @@ - (void)setPushTokenAsString:(CDVInvokedUrlCommand *)command { }]; } -- (void)setPushXiaomiTokenAsString:(CDVInvokedUrlCommand *)command { - NSLog(@"XiaomiToken is no-op in iOS"); -} - - (void)setPushBaiduTokenAsString:(CDVInvokedUrlCommand *)command { NSLog(@"BaiduToken is no-op in iOS"); } @@ -1385,9 +1382,9 @@ - (void)reset { }]; } -- (void)setLibrary: (CDVInvokedUrlCommand *)command { - NSString *libName = [command argumentAtIndex:0]; - int libVersion = [[command argumentAtIndex:1]intValue]; +- (void)setLibrary { + NSString *libName = @"Cordova"; + int libVersion = 30200; [clevertap setLibrary:libName]; [clevertap setCustomSdkVersion:libName version:libVersion]; }