Showing
16 changed files
with
845 additions
and
1307 deletions
| ... | @@ -3,13 +3,14 @@ apply plugin: 'com.google.gms.google-services' | ... | @@ -3,13 +3,14 @@ apply plugin: 'com.google.gms.google-services' | 
| 3 | apply plugin: 'com.huawei.agconnect' | 3 | apply plugin: 'com.huawei.agconnect' | 
| 4 | 4 | ||
| 5 | android { | 5 | android { | 
| 6 | - compileSdkVersion 34 | 6 | + compileSdkVersion 35 | 
| 7 | - buildToolsVersion "34.0.0" | 7 | + buildToolsVersion "35.0.0" | 
| 8 | 8 | ||
| 9 | + namespace "warp.ly.android_sdk" | ||
| 9 | defaultConfig { | 10 | defaultConfig { | 
| 10 | applicationId "warp.ly.android_sdk" | 11 | applicationId "warp.ly.android_sdk" | 
| 11 | minSdkVersion 31 | 12 | minSdkVersion 31 | 
| 12 | - targetSdkVersion 34 | 13 | + targetSdkVersion 35 | 
| 13 | versionCode 100 | 14 | versionCode 100 | 
| 14 | versionName "1.0.0" | 15 | versionName "1.0.0" | 
| 15 | } | 16 | } | ... | ... | 
| ... | @@ -8,9 +8,9 @@ buildscript { | ... | @@ -8,9 +8,9 @@ buildscript { | 
| 8 | maven { url 'https://plugins.gradle.org/m2/' } | 8 | maven { url 'https://plugins.gradle.org/m2/' } | 
| 9 | } | 9 | } | 
| 10 | dependencies { | 10 | dependencies { | 
| 11 | - classpath 'com.android.tools.build:gradle:8.8.0' | 11 | + classpath 'com.android.tools.build:gradle:8.7.3' | 
| 12 | - classpath 'com.google.gms:google-services:4.4.2' | 12 | + classpath 'com.google.gms:google-services:4.4.3' | 
| 13 | - classpath 'com.huawei.agconnect:agcp:1.9.1.300' | 13 | + classpath 'com.huawei.agconnect:agcp:1.9.1.301' | 
| 14 | classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' | 14 | classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' | 
| 15 | 15 | ||
| 16 | // NOTE: Do not place your application dependencies here; they belong | 16 | // NOTE: Do not place your application dependencies here; they belong | 
| ... | @@ -18,6 +18,10 @@ buildscript { | ... | @@ -18,6 +18,10 @@ buildscript { | 
| 18 | } | 18 | } | 
| 19 | } | 19 | } | 
| 20 | 20 | ||
| 21 | +plugins { | ||
| 22 | + id 'maven-publish' | ||
| 23 | +} | ||
| 24 | + | ||
| 21 | allprojects { | 25 | allprojects { | 
| 22 | repositories { | 26 | repositories { | 
| 23 | mavenCentral() | 27 | mavenCentral() | 
| ... | @@ -27,5 +31,4 @@ allprojects { | ... | @@ -27,5 +31,4 @@ allprojects { | 
| 27 | } | 31 | } | 
| 28 | } | 32 | } | 
| 29 | 33 | ||
| 30 | -apply plugin: 'io.github.gradle-nexus.publish-plugin' | ||
| 31 | apply from: "${rootDir}/scripts/publish-root.gradle" | 34 | apply from: "${rootDir}/scripts/publish-root.gradle" | 
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... | 
| 1 | #Fri Jul 26 17:08:44 EEST 2024 | 1 | #Fri Jul 26 17:08:44 EEST 2024 | 
| 2 | distributionBase=GRADLE_USER_HOME | 2 | distributionBase=GRADLE_USER_HOME | 
| 3 | distributionPath=wrapper/dists | 3 | distributionPath=wrapper/dists | 
| 4 | -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip | 4 | +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip | 
| 5 | zipStoreBase=GRADLE_USER_HOME | 5 | zipStoreBase=GRADLE_USER_HOME | 
| 6 | zipStorePath=wrapper/dists | 6 | zipStorePath=wrapper/dists | ... | ... | 
| ... | @@ -40,7 +40,7 @@ afterEvaluate { | ... | @@ -40,7 +40,7 @@ afterEvaluate { | 
| 40 | // Sources are now handled by the android block's singleVariant | 40 | // Sources are now handled by the android block's singleVariant | 
| 41 | // artifact javadocJar | 41 | // artifact javadocJar | 
| 42 | 42 | ||
| 43 | - // Mostly self-explanatory metadata | 43 | + // POM metadata for Maven Central | 
| 44 | pom { | 44 | pom { | 
| 45 | name = PUBLISH_ARTIFACT_ID | 45 | name = PUBLISH_ARTIFACT_ID | 
| 46 | description = 'Warply Android SDK Maven Plugin' | 46 | description = 'Warply Android SDK Maven Plugin' | 
| ... | @@ -60,8 +60,7 @@ afterEvaluate { | ... | @@ -60,8 +60,7 @@ afterEvaluate { | 
| 60 | // Add all other devs here... | 60 | // Add all other devs here... | 
| 61 | } | 61 | } | 
| 62 | 62 | ||
| 63 | - // Version control info - if you're using GitHub, follow the | 63 | + // Version control info | 
| 64 | - // format as seen here | ||
| 65 | scm { | 64 | scm { | 
| 66 | connection = 'scm:git:git.warp.ly/open-source/warply_android_sdk_maven_plugin.git' | 65 | connection = 'scm:git:git.warp.ly/open-source/warply_android_sdk_maven_plugin.git' | 
| 67 | developerConnection = 'scm:git:ssh://git.warp.ly/open-source/warply_android_sdk_maven_plugin.git' | 66 | developerConnection = 'scm:git:ssh://git.warp.ly/open-source/warply_android_sdk_maven_plugin.git' | 
| ... | @@ -81,3 +80,365 @@ signing { | ... | @@ -81,3 +80,365 @@ signing { | 
| 81 | ) | 80 | ) | 
| 82 | sign publishing.publications | 81 | sign publishing.publications | 
| 83 | } | 82 | } | 
| 83 | + | ||
| 84 | +// Configuration for Central Publishing (similar to Maven plugin configuration) | ||
| 85 | +ext.centralPublishing = [ | ||
| 86 | + autoPublish : false, // Manual publishing for safety | ||
| 87 | + // waitUntil: "published", // Commented out - don't wait for publishing | ||
| 88 | + deploymentName: "Warply Android SDK ${PUBLISH_VERSION}", | ||
| 89 | + centralBaseUrl: "https://central.sonatype.com" | ||
| 90 | +] | ||
| 91 | + | ||
| 92 | +// Custom task that implements the same functionality as org.sonatype.central:central-publishing-maven-plugin:0.8.0 | ||
| 93 | +// This uses the Central Portal API directly to achieve the same result | ||
| 94 | +task publishToCentralPortal { | ||
| 95 | + dependsOn 'publishReleasePublicationToMavenLocal' | ||
| 96 | + | ||
| 97 | + description = 'Publishes to Maven Central Portal using the same API as central-publishing-maven-plugin:0.8.0' | ||
| 98 | + group = 'publishing' | ||
| 99 | + | ||
| 100 | + doLast { | ||
| 101 | + def username = rootProject.ext["centralPortalUsername"] | ||
| 102 | + def password = rootProject.ext["centralPortalPassword"] | ||
| 103 | + def config = project.ext.centralPublishing | ||
| 104 | + | ||
| 105 | + if (!username || !password) { | ||
| 106 | + throw new GradleException("Central Portal credentials not configured. Please set centralPortalUsername and centralPortalPassword in local.properties or environment variables.") | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + println "=== Central Portal Publishing ===" | ||
| 110 | + println "Deployment: ${config.deploymentName}" | ||
| 111 | + println "Auto-publish: ${config.autoPublish}" | ||
| 112 | + println "Portal URL: ${config.centralBaseUrl}" | ||
| 113 | + println "" | ||
| 114 | + | ||
| 115 | + // Step 1: Create deployment bundle | ||
| 116 | + println "Step 1: Creating deployment bundle..." | ||
| 117 | + def bundleFile = createDeploymentBundle() | ||
| 118 | + println "✓ Bundle created: ${bundleFile.name} (${bundleFile.length()} bytes)" | ||
| 119 | + | ||
| 120 | + // Step 2: Upload bundle to Central Portal | ||
| 121 | + println "\nStep 2: Uploading to Central Portal..." | ||
| 122 | + def deploymentId = uploadBundle(bundleFile, username, password, config) | ||
| 123 | + println "✓ Upload successful. Deployment ID: ${deploymentId}" | ||
| 124 | + | ||
| 125 | + // Step 3: Wait for validation | ||
| 126 | + println "\nStep 3: Waiting for validation..." | ||
| 127 | + def validationResult = waitForValidation(deploymentId, username, password, config) | ||
| 128 | + | ||
| 129 | + if (validationResult.success) { | ||
| 130 | + def state = validationResult.state | ||
| 131 | + println "✓ Validation successful! State: ${state}" | ||
| 132 | + | ||
| 133 | + if (config.autoPublish && state == "VALIDATED") { | ||
| 134 | + println "\nStep 4: Auto-publishing..." | ||
| 135 | + def publishResult = publishDeployment(deploymentId, username, password, config) | ||
| 136 | + if (publishResult.success) { | ||
| 137 | + println "✓ Published successfully to Maven Central!" | ||
| 138 | + } else { | ||
| 139 | + throw new GradleException("Auto-publishing failed: ${publishResult.error}") | ||
| 140 | + } | ||
| 141 | + } else if (state == "PUBLISHED") { | ||
| 142 | + println "✓ Already published to Maven Central!" | ||
| 143 | + def response = validationResult.response | ||
| 144 | + def purls = response.purls ?: [] | ||
| 145 | + if (purls) { | ||
| 146 | + println " Published artifacts:" | ||
| 147 | + purls.each { purl -> println " - ${purl}" } | ||
| 148 | + } | ||
| 149 | + } else { | ||
| 150 | + println "\n✓ Deployment uploaded and validated successfully!" | ||
| 151 | + println "📋 Manual action required:" | ||
| 152 | + println " Visit: ${config.centralBaseUrl}/publishing/deployments" | ||
| 153 | + println " Find deployment: ${config.deploymentName}" | ||
| 154 | + println " Click 'Publish' to complete the process" | ||
| 155 | + } | ||
| 156 | + } else { | ||
| 157 | + throw new GradleException("Validation failed: ${validationResult.error}") | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + println "\n=== Publishing Complete ===" | ||
| 161 | + } | ||
| 162 | +} | ||
| 163 | + | ||
| 164 | +def createDeploymentBundle() { | ||
| 165 | + def bundleDir = file("${buildDir}/central-publishing") | ||
| 166 | + def stagingDir = file("${bundleDir}/staging") | ||
| 167 | + | ||
| 168 | + // Clean and create directories | ||
| 169 | + bundleDir.deleteDir() | ||
| 170 | + stagingDir.mkdirs() | ||
| 171 | + | ||
| 172 | + // Create Maven repository structure | ||
| 173 | + def groupPath = PUBLISH_GROUP_ID.replace('.', '/') | ||
| 174 | + def artifactDir = file("${stagingDir}/${groupPath}/${PUBLISH_ARTIFACT_ID}/${PUBLISH_VERSION}") | ||
| 175 | + artifactDir.mkdirs() | ||
| 176 | + | ||
| 177 | + // Copy artifacts to staging area | ||
| 178 | + def artifacts = [:] | ||
| 179 | + | ||
| 180 | + // AAR file | ||
| 181 | + def aarFile = file("${buildDir}/outputs/aar/warply_android_sdk-release.aar") | ||
| 182 | + if (aarFile.exists()) { | ||
| 183 | + def targetAar = file("${artifactDir}/${PUBLISH_ARTIFACT_ID}-${PUBLISH_VERSION}.aar") | ||
| 184 | + copy { | ||
| 185 | + from aarFile | ||
| 186 | + into artifactDir | ||
| 187 | + rename { targetAar.name } | ||
| 188 | + } | ||
| 189 | + artifacts['aar'] = targetAar | ||
| 190 | + | ||
| 191 | + // Copy AAR signature if exists | ||
| 192 | + def aarSigFile = file("${aarFile.path}.asc") | ||
| 193 | + if (aarSigFile.exists()) { | ||
| 194 | + def targetAarSig = file("${targetAar.path}.asc") | ||
| 195 | + copy { | ||
| 196 | + from aarSigFile | ||
| 197 | + into artifactDir | ||
| 198 | + rename { targetAarSig.name } | ||
| 199 | + } | ||
| 200 | + artifacts['aar-sig'] = targetAarSig | ||
| 201 | + } | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + // Sources JAR | ||
| 205 | + def sourcesFile = file("${buildDir}/libs/warply_android_sdk-${PUBLISH_VERSION}-sources.jar") | ||
| 206 | + if (sourcesFile.exists()) { | ||
| 207 | + def targetSources = file("${artifactDir}/${PUBLISH_ARTIFACT_ID}-${PUBLISH_VERSION}-sources.jar") | ||
| 208 | + copy { | ||
| 209 | + from sourcesFile | ||
| 210 | + into artifactDir | ||
| 211 | + rename { targetSources.name } | ||
| 212 | + } | ||
| 213 | + artifacts['sources'] = targetSources | ||
| 214 | + | ||
| 215 | + // Copy sources signature if exists | ||
| 216 | + def sourcesSigFile = file("${sourcesFile.path}.asc") | ||
| 217 | + if (sourcesSigFile.exists()) { | ||
| 218 | + def targetSourcesSig = file("${targetSources.path}.asc") | ||
| 219 | + copy { | ||
| 220 | + from sourcesSigFile | ||
| 221 | + into artifactDir | ||
| 222 | + rename { targetSourcesSig.name } | ||
| 223 | + } | ||
| 224 | + artifacts['sources-sig'] = targetSourcesSig | ||
| 225 | + } | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + // POM file | ||
| 229 | + def pomFile = file("${buildDir}/publications/release/pom-default.xml") | ||
| 230 | + if (pomFile.exists()) { | ||
| 231 | + def targetPom = file("${artifactDir}/${PUBLISH_ARTIFACT_ID}-${PUBLISH_VERSION}.pom") | ||
| 232 | + copy { | ||
| 233 | + from pomFile | ||
| 234 | + into artifactDir | ||
| 235 | + rename { targetPom.name } | ||
| 236 | + } | ||
| 237 | + artifacts['pom'] = targetPom | ||
| 238 | + | ||
| 239 | + // Copy POM signature if exists | ||
| 240 | + def pomSigFile = file("${pomFile.path}.asc") | ||
| 241 | + if (pomSigFile.exists()) { | ||
| 242 | + def targetPomSig = file("${targetPom.path}.asc") | ||
| 243 | + copy { | ||
| 244 | + from pomSigFile | ||
| 245 | + into artifactDir | ||
| 246 | + rename { targetPomSig.name } | ||
| 247 | + } | ||
| 248 | + artifacts['pom-sig'] = targetPomSig | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + // Generate checksums for all files | ||
| 253 | + artifacts.each { type, artifactFile -> | ||
| 254 | + if (artifactFile.exists()) { | ||
| 255 | + generateChecksums(artifactFile) | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + // Create bundle ZIP | ||
| 260 | + def bundleFile = file("${bundleDir}/central-bundle.zip") | ||
| 261 | + ant.zip(destfile: bundleFile) { | ||
| 262 | + fileset(dir: stagingDir) | ||
| 263 | + } | ||
| 264 | + | ||
| 265 | + return bundleFile | ||
| 266 | +} | ||
| 267 | + | ||
| 268 | +def generateChecksums(File file) { | ||
| 269 | + ['md5', 'sha1', 'sha256', 'sha512'].each { algorithm -> | ||
| 270 | + def checksum = file.withInputStream { stream -> | ||
| 271 | + java.security.MessageDigest.getInstance(algorithm.toUpperCase()).digest(stream.bytes).encodeHex().toString() | ||
| 272 | + } | ||
| 273 | + new File("${file.path}.${algorithm}").text = checksum | ||
| 274 | + } | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +def uploadBundle(File bundleFile, String username, String password, Map config) { | ||
| 278 | + def url = "${config.centralBaseUrl}/api/v1/publisher/upload" | ||
| 279 | + def credentials = "${username}:${password}".bytes.encodeBase64().toString() | ||
| 280 | + | ||
| 281 | + // Add query parameters | ||
| 282 | + def publishingType = config.autoPublish ? "AUTOMATIC" : "USER_MANAGED" | ||
| 283 | + def urlWithParams = "${url}?publishingType=${publishingType}&name=${URLEncoder.encode(config.deploymentName, 'UTF-8')}" | ||
| 284 | + | ||
| 285 | + println " Uploading to: ${urlWithParams}" | ||
| 286 | + println " Publishing type: ${publishingType}" | ||
| 287 | + | ||
| 288 | + def connection = new URL(urlWithParams).openConnection() as HttpURLConnection | ||
| 289 | + connection.setRequestMethod("POST") | ||
| 290 | + connection.setRequestProperty("Authorization", "Bearer ${credentials}") | ||
| 291 | + connection.setDoOutput(true) | ||
| 292 | + connection.setDoInput(true) | ||
| 293 | + | ||
| 294 | + // Create multipart/form-data boundary | ||
| 295 | + def boundary = "----WebKitFormBoundary" + System.currentTimeMillis() | ||
| 296 | + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=${boundary}") | ||
| 297 | + | ||
| 298 | + // Write multipart data | ||
| 299 | + connection.outputStream.withWriter("UTF-8") { writer -> | ||
| 300 | + writer.write("--${boundary}\r\n") | ||
| 301 | + writer.write("Content-Disposition: form-data; name=\"bundle\"; filename=\"${bundleFile.name}\"\r\n") | ||
| 302 | + writer.write("Content-Type: application/octet-stream\r\n") | ||
| 303 | + writer.write("\r\n") | ||
| 304 | + writer.flush() | ||
| 305 | + | ||
| 306 | + // Write file content | ||
| 307 | + bundleFile.withInputStream { input -> | ||
| 308 | + connection.outputStream << input | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + writer.write("\r\n--${boundary}--\r\n") | ||
| 312 | + writer.flush() | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + // Get response | ||
| 316 | + def responseCode = connection.responseCode | ||
| 317 | + if (responseCode == 201) { | ||
| 318 | + def deploymentId = connection.inputStream.text.trim() | ||
| 319 | + println " ✓ Upload successful (HTTP ${responseCode})" | ||
| 320 | + return deploymentId | ||
| 321 | + } else { | ||
| 322 | + def errorMessage = connection.errorStream?.text ?: "Unknown error" | ||
| 323 | + throw new GradleException("Upload failed (HTTP ${responseCode}): ${errorMessage}") | ||
| 324 | + } | ||
| 325 | +} | ||
| 326 | + | ||
| 327 | +def waitForValidation(String deploymentId, String username, String password, Map config) { | ||
| 328 | + def credentials = "${username}:${password}".bytes.encodeBase64().toString() | ||
| 329 | + def maxAttempts = 60 // 5 minutes with 5-second intervals | ||
| 330 | + def attempt = 0 | ||
| 331 | + | ||
| 332 | + while (attempt < maxAttempts) { | ||
| 333 | + attempt++ | ||
| 334 | + | ||
| 335 | + def url = "${config.centralBaseUrl}/api/v1/publisher/status?id=${deploymentId}" | ||
| 336 | + def connection = new URL(url).openConnection() as HttpURLConnection | ||
| 337 | + connection.setRequestMethod("POST") | ||
| 338 | + connection.setRequestProperty("Authorization", "Bearer ${credentials}") | ||
| 339 | + connection.setRequestProperty("Content-Type", "application/json") | ||
| 340 | + | ||
| 341 | + def responseCode = connection.responseCode | ||
| 342 | + if (responseCode == 200) { | ||
| 343 | + def response = new groovy.json.JsonSlurper().parseText(connection.inputStream.text) | ||
| 344 | + def state = response.deploymentState | ||
| 345 | + | ||
| 346 | + println " Status check ${attempt}: ${state}" | ||
| 347 | + | ||
| 348 | + switch (state) { | ||
| 349 | + case "PENDING": | ||
| 350 | + case "VALIDATING": | ||
| 351 | + // Continue waiting | ||
| 352 | + Thread.sleep(5000) | ||
| 353 | + break | ||
| 354 | + case "VALIDATED": | ||
| 355 | + return [success: true, state: state, response: response] | ||
| 356 | + case "PUBLISHED": | ||
| 357 | + return [success: true, state: state, response: response] | ||
| 358 | + case "FAILED": | ||
| 359 | + def errors = response.errors ?: ["Unknown validation error"] | ||
| 360 | + return [success: false, error: "Validation failed: ${errors.join(', ')}", response: response] | ||
| 361 | + default: | ||
| 362 | + return [success: false, error: "Unknown deployment state: ${state}", response: response] | ||
| 363 | + } | ||
| 364 | + } else { | ||
| 365 | + def errorMessage = connection.errorStream?.text ?: "Unknown error" | ||
| 366 | + throw new GradleException("Status check failed (HTTP ${responseCode}): ${errorMessage}") | ||
| 367 | + } | ||
| 368 | + } | ||
| 369 | + | ||
| 370 | + return [success: false, error: "Timeout waiting for validation (${maxAttempts * 5} seconds)"] | ||
| 371 | +} | ||
| 372 | + | ||
| 373 | +def publishDeployment(String deploymentId, String username, String password, Map config) { | ||
| 374 | + def credentials = "${username}:${password}".bytes.encodeBase64().toString() | ||
| 375 | + def url = "${config.centralBaseUrl}/api/v1/publisher/deployment/${deploymentId}" | ||
| 376 | + | ||
| 377 | + println " Calling publish API..." | ||
| 378 | + | ||
| 379 | + def connection = new URL(url).openConnection() as HttpURLConnection | ||
| 380 | + connection.setRequestMethod("POST") | ||
| 381 | + connection.setRequestProperty("Authorization", "Bearer ${credentials}") | ||
| 382 | + | ||
| 383 | + def responseCode = connection.responseCode | ||
| 384 | + if (responseCode == 204) { | ||
| 385 | + println " ✓ Publish request successful (HTTP ${responseCode})" | ||
| 386 | + | ||
| 387 | + // Wait for publishing to complete | ||
| 388 | + println " Waiting for publishing to complete..." | ||
| 389 | + def result = waitForPublishing(deploymentId, username, password, config) | ||
| 390 | + return result | ||
| 391 | + } else { | ||
| 392 | + def errorMessage = connection.errorStream?.text ?: "Unknown error" | ||
| 393 | + throw new GradleException("Publish failed (HTTP ${responseCode}): ${errorMessage}") | ||
| 394 | + } | ||
| 395 | +} | ||
| 396 | + | ||
| 397 | +def waitForPublishing(String deploymentId, String username, String password, Map config) { | ||
| 398 | + def credentials = "${username}:${password}".bytes.encodeBase64().toString() | ||
| 399 | + def maxAttempts = 120 // 10 minutes with 5-second intervals | ||
| 400 | + def attempt = 0 | ||
| 401 | + | ||
| 402 | + while (attempt < maxAttempts) { | ||
| 403 | + attempt++ | ||
| 404 | + | ||
| 405 | + def url = "${config.centralBaseUrl}/api/v1/publisher/status?id=${deploymentId}" | ||
| 406 | + def connection = new URL(url).openConnection() as HttpURLConnection | ||
| 407 | + connection.setRequestMethod("POST") | ||
| 408 | + connection.setRequestProperty("Authorization", "Bearer ${credentials}") | ||
| 409 | + connection.setRequestProperty("Content-Type", "application/json") | ||
| 410 | + | ||
| 411 | + def responseCode = connection.responseCode | ||
| 412 | + if (responseCode == 200) { | ||
| 413 | + def response = new groovy.json.JsonSlurper().parseText(connection.inputStream.text) | ||
| 414 | + def state = response.deploymentState | ||
| 415 | + | ||
| 416 | + println " Publishing status ${attempt}: ${state}" | ||
| 417 | + | ||
| 418 | + switch (state) { | ||
| 419 | + case "PUBLISHING": | ||
| 420 | + // Continue waiting | ||
| 421 | + Thread.sleep(5000) | ||
| 422 | + break | ||
| 423 | + case "PUBLISHED": | ||
| 424 | + def purls = response.purls ?: [] | ||
| 425 | + println " ✓ Successfully published to Maven Central!" | ||
| 426 | + if (purls) { | ||
| 427 | + println " Published artifacts:" | ||
| 428 | + purls.each { purl -> println " - ${purl}" } | ||
| 429 | + } | ||
| 430 | + return [success: true, state: state, response: response] | ||
| 431 | + case "FAILED": | ||
| 432 | + def errors = response.errors ?: ["Unknown publishing error"] | ||
| 433 | + return [success: false, error: "Publishing failed: ${errors.join(', ')}", response: response] | ||
| 434 | + default: | ||
| 435 | + return [success: false, error: "Unexpected state during publishing: ${state}", response: response] | ||
| 436 | + } | ||
| 437 | + } else { | ||
| 438 | + def errorMessage = connection.errorStream?.text ?: "Unknown error" | ||
| 439 | + throw new GradleException("Publishing status check failed (HTTP ${responseCode}): ${errorMessage}") | ||
| 440 | + } | ||
| 441 | + } | ||
| 442 | + | ||
| 443 | + return [success: false, error: "Timeout waiting for publishing (${maxAttempts * 5} seconds)"] | ||
| 444 | +} | ... | ... | 
| 1 | // Create variables with empty default values | 1 | // Create variables with empty default values | 
| 2 | 2 | ||
| 3 | +// Central Portal credentials | ||
| 4 | +ext["centralPortalUsername"] = '' | ||
| 5 | +ext["centralPortalPassword"] = '' | ||
| 6 | + | ||
| 3 | // keyId is the last 8 characters of the GPG key | 7 | // keyId is the last 8 characters of the GPG key | 
| 4 | ext["signing.keyId"] = '' | 8 | ext["signing.keyId"] = '' | 
| 5 | // password is the passphrase of the GPG key | 9 | // password is the passphrase of the GPG key | 
| 6 | ext["signing.password"] = '' | 10 | ext["signing.password"] = '' | 
| 7 | // key is the base64 private GPG key | 11 | // key is the base64 private GPG key | 
| 8 | ext["signing.key"] = '' | 12 | ext["signing.key"] = '' | 
| 9 | -// osshrUsername and ossrhPassword are the account details for MavenCentral | ||
| 10 | -// which we’ve chosen at the Jira registration step (Sonatype site)) | ||
| 11 | -ext["ossrhUsername"] = '' | ||
| 12 | -ext["ossrhPassword"] = '' | ||
| 13 | -ext["sonatypeStagingProfileId"] = '' | ||
| 14 | 13 | ||
| 15 | File secretPropsFile = project.rootProject.file('local.properties') | 14 | File secretPropsFile = project.rootProject.file('local.properties') | 
| 16 | if (secretPropsFile.exists()) { | 15 | if (secretPropsFile.exists()) { | 
| ... | @@ -19,24 +18,11 @@ if (secretPropsFile.exists()) { | ... | @@ -19,24 +18,11 @@ if (secretPropsFile.exists()) { | 
| 19 | new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) } | 18 | new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) } | 
| 20 | p.each { name, value -> ext[name] = value } | 19 | p.each { name, value -> ext[name] = value } | 
| 21 | } else { | 20 | } else { | 
| 22 | - // Use system environment variables | 21 | + // Use system environment variables for signing | 
| 23 | - ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME') | ||
| 24 | - ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD') | ||
| 25 | - ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID') | ||
| 26 | ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID') | 22 | ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID') | 
| 27 | ext["signing.password"] = System.getenv('SIGNING_PASSWORD') | 23 | ext["signing.password"] = System.getenv('SIGNING_PASSWORD') | 
| 28 | ext["signing.key"] = System.getenv('SIGNING_KEY') | 24 | ext["signing.key"] = System.getenv('SIGNING_KEY') | 
| 25 | + // Central Portal credentials can also come from environment | ||
| 26 | + ext["centralPortalUsername"] = System.getenv('CENTRAL_PORTAL_USERNAME') | ||
| 27 | + ext["centralPortalPassword"] = System.getenv('CENTRAL_PORTAL_PASSWORD') | ||
| 29 | } | 28 | } | 
| 30 | - | ||
| 31 | -// Set up Sonatype repository | ||
| 32 | -nexusPublishing { | ||
| 33 | - repositories { | ||
| 34 | - sonatype { | ||
| 35 | - stagingProfileId = sonatypeStagingProfileId | ||
| 36 | - username = ossrhUsername | ||
| 37 | - password = ossrhPassword | ||
| 38 | - nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) | ||
| 39 | - snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) | ||
| 40 | - } | ||
| 41 | - } | ||
| 42 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... | 
| ... | @@ -5,15 +5,15 @@ android.buildFeatures.buildConfig = true | ... | @@ -5,15 +5,15 @@ android.buildFeatures.buildConfig = true | 
| 5 | 5 | ||
| 6 | ext { | 6 | ext { | 
| 7 | PUBLISH_GROUP_ID = 'ly.warp' | 7 | PUBLISH_GROUP_ID = 'ly.warp' | 
| 8 | - PUBLISH_VERSION = '4.5.5.4deh2' | 8 | + PUBLISH_VERSION = '4.5.5.4deh3' | 
| 9 | PUBLISH_ARTIFACT_ID = 'warply-android-sdk' | 9 | PUBLISH_ARTIFACT_ID = 'warply-android-sdk' | 
| 10 | } | 10 | } | 
| 11 | 11 | ||
| 12 | apply from: "${rootProject.projectDir}/scripts/publish-module.gradle" | 12 | apply from: "${rootProject.projectDir}/scripts/publish-module.gradle" | 
| 13 | 13 | ||
| 14 | android { | 14 | android { | 
| 15 | - compileSdkVersion 34 | 15 | + compileSdkVersion 35 | 
| 16 | - buildToolsVersion "34.0.0" | 16 | + buildToolsVersion "35.0.0" | 
| 17 | 17 | ||
| 18 | useLibrary 'org.apache.http.legacy' | 18 | useLibrary 'org.apache.http.legacy' | 
| 19 | 19 | ||
| ... | @@ -27,7 +27,7 @@ android { | ... | @@ -27,7 +27,7 @@ android { | 
| 27 | 27 | ||
| 28 | defaultConfig { | 28 | defaultConfig { | 
| 29 | minSdkVersion 31 | 29 | minSdkVersion 31 | 
| 30 | - targetSdkVersion 34 | 30 | + targetSdkVersion 35 | 
| 31 | consumerProguardFiles 'proguard-rules.pro' | 31 | consumerProguardFiles 'proguard-rules.pro' | 
| 32 | vectorDrawables.useSupportLibrary = true | 32 | vectorDrawables.useSupportLibrary = true | 
| 33 | } | 33 | } | 
| ... | @@ -61,45 +61,42 @@ android { | ... | @@ -61,45 +61,42 @@ android { | 
| 61 | 61 | ||
| 62 | dependencies { | 62 | dependencies { | 
| 63 | //------------------------------ Support -----------------------------// | 63 | //------------------------------ Support -----------------------------// | 
| 64 | - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' | 64 | + implementation 'androidx.appcompat:appcompat:1.7.1' | 
| 65 | - implementation 'androidx.appcompat:appcompat:1.4.1' | 65 | + implementation "androidx.security:security-crypto:1.1.0" | 
| 66 | - api "androidx.security:security-crypto:1.1.0-alpha03" | ||
| 67 | // For minSDK 23 use 1.0.0, for minSDK 21 use 1.1.0 that is currently in alpha | 66 | // For minSDK 23 use 1.0.0, for minSDK 21 use 1.1.0 that is currently in alpha | 
| 68 | - api 'org.altbeacon:android-beacon-library:2.19.3' | 67 | + implementation 'org.altbeacon:android-beacon-library:2.19.3' | 
| 69 | - api 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2' | 68 | + implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2' | 
| 70 | - api 'io.reactivex.rxjava3:rxjava:3.1.8' | 69 | + implementation 'io.reactivex.rxjava3:rxjava:3.1.8' | 
| 71 | - api 'io.reactivex.rxjava3:rxandroid:3.0.2' | 70 | + implementation 'io.reactivex.rxjava3:rxandroid:3.0.2' | 
| 72 | - implementation 'com.google.android.material:material:1.5.0' | 71 | + implementation 'com.google.android.material:material:1.12.0' | 
| 73 | implementation 'org.greenrobot:eventbus:3.3.1' | 72 | implementation 'org.greenrobot:eventbus:3.3.1' | 
| 74 | - api 'com.google.guava:guava:30.1-android' | 73 | + implementation 'com.google.guava:guava:33.0.0-android' | 
| 75 | 74 | ||
| 76 | //------------------------------ Firebase -----------------------------// | 75 | //------------------------------ Firebase -----------------------------// | 
| 77 | - api platform('com.google.firebase:firebase-bom:29.0.3') | 76 | + implementation platform('com.google.firebase:firebase-bom:34.2.0') | 
| 78 | implementation('com.google.firebase:firebase-messaging') { | 77 | implementation('com.google.firebase:firebase-messaging') { | 
| 79 | exclude group: 'com.google.android.gms', module: 'play-services-location' | 78 | exclude group: 'com.google.android.gms', module: 'play-services-location' | 
| 80 | } | 79 | } | 
| 81 | 80 | ||
| 82 | //------------------------------ GMS -----------------------------// | 81 | //------------------------------ GMS -----------------------------// | 
| 83 | - api 'com.google.android.gms:play-services-base:18.1.0' | 82 | + implementation 'com.google.android.gms:play-services-base:18.7.2' | 
| 84 | - implementation 'com.google.android.gms:play-services-location:19.0.1' | 83 | + implementation 'com.google.android.gms:play-services-location:21.3.0' | 
| 85 | 84 | ||
| 86 | //------------------------------ Work Manager -----------------------------// | 85 | //------------------------------ Work Manager -----------------------------// | 
| 87 | - api 'androidx.work:work-runtime:2.7.1' | 86 | + implementation 'androidx.work:work-runtime:2.10.3' | 
| 88 | 87 | ||
| 89 | //------------------------------ Glide -----------------------------// | 88 | //------------------------------ Glide -----------------------------// | 
| 90 | - implementation 'com.github.bumptech.glide:glide:4.12.0' | 89 | + implementation 'com.github.bumptech.glide:glide:4.16.0' | 
| 91 | - annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' | 90 | + annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' | 
| 92 | 91 | ||
| 93 | //------------------------------ Huawei -----------------------------// | 92 | //------------------------------ Huawei -----------------------------// | 
| 94 | - implementation 'com.huawei.agconnect:agconnect-core:1.7.2.300' | 93 | + implementation 'com.huawei.agconnect:agconnect-core:1.9.3.301' | 
| 95 | - implementation 'com.huawei.hms:base:6.6.0.300' | 94 | + implementation 'com.huawei.hms:base:6.13.0.303' | 
| 96 | - implementation 'com.huawei.hms:push:6.7.0.300' | 95 | + implementation 'com.huawei.hms:push:6.10.0.300' | 
| 97 | - implementation 'com.huawei.hms:ads-identifier:3.4.56.300' | 96 | + implementation 'com.huawei.hms:ads-identifier:3.4.62.300' | 
| 98 | - | 97 | + | 
| 99 | - //------------------------------ SQLCipher -----------------------------// | 98 | + //------------------------------ SQLite (Standard Android) -----------------------------// | 
| 100 | - api "net.zetetic:android-database-sqlcipher:4.5.2" | 99 | + implementation 'androidx.sqlite:sqlite:2.5.2' | 
| 101 | - api "androidx.sqlite:sqlite:2.2.0" | ||
| 102 | - api 'com.getkeepsafe.relinker:relinker:1.4.4' | ||
| 103 | 100 | ||
| 104 | //------------------------------ Retrofit -----------------------------// | 101 | //------------------------------ Retrofit -----------------------------// | 
| 105 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' | 102 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' | ... | ... | 
| ... | @@ -52,7 +52,6 @@ public class BaseFragmentActivity extends FragmentActivity implements Navigation | ... | @@ -52,7 +52,6 @@ public class BaseFragmentActivity extends FragmentActivity implements Navigation | 
| 52 | mBottomNavigationView = findViewById(R.id.bt_tabs); | 52 | mBottomNavigationView = findViewById(R.id.bt_tabs); | 
| 53 | 53 | ||
| 54 | if (WarplyDBHelper.getInstance(this).isTableNotEmpty("auth")) { | 54 | if (WarplyDBHelper.getInstance(this).isTableNotEmpty("auth")) { | 
| 55 | - WarplyManager.getSupermarketCampaign(mCampaignsCallback); | ||
| 56 | WarplyManager.getRedeemedSMHistory(mSMHistoryReceiver); | 55 | WarplyManager.getRedeemedSMHistory(mSMHistoryReceiver); | 
| 57 | } | 56 | } | 
| 58 | 57 | ||
| ... | @@ -138,18 +137,6 @@ public class BaseFragmentActivity extends FragmentActivity implements Navigation | ... | @@ -138,18 +137,6 @@ public class BaseFragmentActivity extends FragmentActivity implements Navigation | 
| 138 | // Inner and Anonymous Classes | 137 | // Inner and Anonymous Classes | 
| 139 | // =========================================================== | 138 | // =========================================================== | 
| 140 | 139 | ||
| 141 | - private final CallbackReceiver<ArrayList<Campaign>> mCampaignsCallback = new CallbackReceiver<ArrayList<Campaign>>() { | ||
| 142 | - @Override | ||
| 143 | - public void onSuccess(ArrayList<Campaign> result) { | ||
| 144 | - Toast.makeText(BaseFragmentActivity.this, "Campaigns Success " + String.valueOf(result.size()), Toast.LENGTH_SHORT).show(); | ||
| 145 | - } | ||
| 146 | - | ||
| 147 | - @Override | ||
| 148 | - public void onFailure(int errorCode) { | ||
| 149 | - Toast.makeText(BaseFragmentActivity.this, "Campaigns Error", Toast.LENGTH_SHORT).show(); | ||
| 150 | - } | ||
| 151 | - }; | ||
| 152 | - | ||
| 153 | private final CallbackReceiver<RedeemedSMHistoryModel> mSMHistoryReceiver = new CallbackReceiver<RedeemedSMHistoryModel>() { | 140 | private final CallbackReceiver<RedeemedSMHistoryModel> mSMHistoryReceiver = new CallbackReceiver<RedeemedSMHistoryModel>() { | 
| 154 | @Override | 141 | @Override | 
| 155 | public void onSuccess(RedeemedSMHistoryModel result) { | 142 | public void onSuccess(RedeemedSMHistoryModel result) { | ... | ... | 
| ... | @@ -7,32 +7,18 @@ import android.content.Context; | ... | @@ -7,32 +7,18 @@ import android.content.Context; | 
| 7 | import android.database.Cursor; | 7 | import android.database.Cursor; | 
| 8 | import android.database.SQLException; | 8 | import android.database.SQLException; | 
| 9 | import android.text.TextUtils; | 9 | import android.text.TextUtils; | 
| 10 | -import android.util.Log; | ||
| 11 | 10 | ||
| 12 | import androidx.annotation.Nullable; | 11 | import androidx.annotation.Nullable; | 
| 13 | 12 | ||
| 14 | -import com.getkeepsafe.relinker.ReLinker; | 13 | +import android.database.DatabaseUtils; | 
| 14 | +import android.database.sqlite.SQLiteDatabase; | ||
| 15 | +import android.database.sqlite.SQLiteOpenHelper; | ||
| 15 | 16 | ||
| 16 | -import net.sqlcipher.DatabaseUtils; | ||
| 17 | -import net.sqlcipher.database.SQLiteDatabase; | ||
| 18 | -import net.sqlcipher.database.SQLiteOpenHelper; | ||
| 19 | -import net.sqlcipher.database.SQLiteStatement; | ||
| 20 | - | ||
| 21 | -import org.json.JSONArray; | ||
| 22 | -import org.json.JSONObject; | ||
| 23 | - | ||
| 24 | -import java.io.File; | ||
| 25 | -import java.io.FileNotFoundException; | ||
| 26 | -import java.io.IOException; | ||
| 27 | import java.util.ArrayList; | 17 | import java.util.ArrayList; | 
| 28 | import java.util.List; | 18 | import java.util.List; | 
| 29 | -import java.util.concurrent.ExecutorService; | ||
| 30 | -import java.util.concurrent.Executors; | ||
| 31 | -import java.util.concurrent.Future; | ||
| 32 | -import java.util.concurrent.TimeUnit; | ||
| 33 | -import java.util.concurrent.TimeoutException; | ||
| 34 | 19 | ||
| 35 | import ly.warp.sdk.utils.constants.WarpConstants; | 20 | import ly.warp.sdk.utils.constants.WarpConstants; | 
| 21 | +import ly.warp.sdk.utils.CryptoUtils; | ||
| 36 | 22 | ||
| 37 | public class WarplyDBHelper extends SQLiteOpenHelper { | 23 | public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 38 | 24 | ||
| ... | @@ -40,17 +26,8 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -40,17 +26,8 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 40 | // Constants | 26 | // Constants | 
| 41 | // =========================================================== | 27 | // =========================================================== | 
| 42 | 28 | ||
| 43 | - private enum State { | 29 | + private static final String DB_NAME = "warply_v2.db"; | 
| 44 | - DOES_NOT_EXIST, UNENCRYPTED, ENCRYPTED | 30 | + private static final int DB_VERSION = 1; | 
| 45 | - } | ||
| 46 | - | ||
| 47 | - private static final String DB_NAME = "warply.db"; | ||
| 48 | - private static final int DB_VERSION = 14; | ||
| 49 | - private static final String KEY_CIPHER = "tn#mpOl3v3Dy1pr@W"; | ||
| 50 | - | ||
| 51 | - // Timeout constants | ||
| 52 | - private static final int CONNECTION_TIMEOUT_MS = 5000; // 5 seconds for database connection | ||
| 53 | - private static final int OPERATION_TIMEOUT_MS = 5000; // 5 seconds for database operations | ||
| 54 | 31 | ||
| 55 | //------------------------------ Fields -----------------------------// | 32 | //------------------------------ Fields -----------------------------// | 
| 56 | private static String TABLE_REQUESTS = "requests"; | 33 | private static String TABLE_REQUESTS = "requests"; | 
| ... | @@ -64,16 +41,12 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -64,16 +41,12 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 64 | private static String TABLE_CLIENT = "client"; | 41 | private static String TABLE_CLIENT = "client"; | 
| 65 | private static String TABLE_AUTH = "auth"; | 42 | private static String TABLE_AUTH = "auth"; | 
| 66 | private static String TABLE_TAGS = "tags"; | 43 | private static String TABLE_TAGS = "tags"; | 
| 67 | - private static String TABLE_TELEMATICS = "telematics"; | ||
| 68 | public static final String KEY_TAG = "tag"; | 44 | public static final String KEY_TAG = "tag"; | 
| 69 | public static final String KEY_TAG_LAST_ADD_DATE = "last_add_date"; | 45 | public static final String KEY_TAG_LAST_ADD_DATE = "last_add_date"; | 
| 70 | public static final String KEY_CLIENT_ID = "client_id"; | 46 | public static final String KEY_CLIENT_ID = "client_id"; | 
| 71 | public static final String KEY_CLIENT_SECRET = "client_secret"; | 47 | public static final String KEY_CLIENT_SECRET = "client_secret"; | 
| 72 | public static final String KEY_ACCESS_TOKEN = "access_token"; | 48 | public static final String KEY_ACCESS_TOKEN = "access_token"; | 
| 73 | public static final String KEY_REFRESH_TOKEN = "refresh_token"; | 49 | public static final String KEY_REFRESH_TOKEN = "refresh_token"; | 
| 74 | - public static final String KEY_TIMESTAMP = "timestamp"; | ||
| 75 | - public static final String KEY_ACCELERATION = "acceleration"; | ||
| 76 | - public static final String KEY_SPEED = "speed"; | ||
| 77 | 50 | ||
| 78 | //------------------------------ Tables -----------------------------// | 51 | //------------------------------ Tables -----------------------------// | 
| 79 | public static final String CREATE_TABLE_REQUESTS = "create table if not exists " | 52 | public static final String CREATE_TABLE_REQUESTS = "create table if not exists " | 
| ... | @@ -115,12 +88,6 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -115,12 +88,6 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 115 | + KEY_ACCESS_TOKEN + " text, " | 88 | + KEY_ACCESS_TOKEN + " text, " | 
| 116 | + KEY_REFRESH_TOKEN + " text)"; | 89 | + KEY_REFRESH_TOKEN + " text)"; | 
| 117 | 90 | ||
| 118 | - public static final String CREATE_TABLE_TELEMATICS = "create table if not exists " | ||
| 119 | - + TABLE_TELEMATICS + " (" | ||
| 120 | - + KEY_TIMESTAMP + " text, " | ||
| 121 | - + KEY_ACCELERATION + " real, " | ||
| 122 | - + KEY_SPEED + " real)"; | ||
| 123 | - | ||
| 124 | // =========================================================== | 91 | // =========================================================== | 
| 125 | // Fields | 92 | // Fields | 
| 126 | // =========================================================== | 93 | // =========================================================== | 
| ... | @@ -128,21 +95,12 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -128,21 +95,12 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 128 | private SQLiteDatabase mDb; | 95 | private SQLiteDatabase mDb; | 
| 129 | private static WarplyDBHelper mDBHelperInstance; | 96 | private static WarplyDBHelper mDBHelperInstance; | 
| 130 | 97 | ||
| 131 | - // Single-threaded executor for database operations | ||
| 132 | - private final ExecutorService dbExecutor = Executors.newSingleThreadExecutor(); | ||
| 133 | - | ||
| 134 | // =========================================================== | 98 | // =========================================================== | 
| 135 | // Constructors | 99 | // Constructors | 
| 136 | // =========================================================== | 100 | // =========================================================== | 
| 137 | 101 | ||
| 138 | public static synchronized WarplyDBHelper getInstance(Context context) { | 102 | public static synchronized WarplyDBHelper getInstance(Context context) { | 
| 139 | if (mDBHelperInstance == null) { | 103 | if (mDBHelperInstance == null) { | 
| 140 | -// SQLiteDatabase.loadLibs(context); //old implementation | ||
| 141 | - SQLiteDatabase.loadLibs(context, libraries -> { | ||
| 142 | - for (String library : libraries) { | ||
| 143 | - ReLinker.loadLibrary(context, library); | ||
| 144 | - } | ||
| 145 | - }); | ||
| 146 | mDBHelperInstance = new WarplyDBHelper(context); | 104 | mDBHelperInstance = new WarplyDBHelper(context); | 
| 147 | } | 105 | } | 
| 148 | return mDBHelperInstance; | 106 | return mDBHelperInstance; | 
| ... | @@ -150,141 +108,26 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -150,141 +108,26 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 150 | 108 | ||
| 151 | private WarplyDBHelper(Context context) { | 109 | private WarplyDBHelper(Context context) { | 
| 152 | super(context, DB_NAME, null, DB_VERSION); | 110 | super(context, DB_NAME, null, DB_VERSION); | 
| 153 | - State tempDatabaseState = getDatabaseState(context, DB_NAME); | ||
| 154 | - if (tempDatabaseState.equals(State.UNENCRYPTED)) { | ||
| 155 | - encrypt(context, context.getDatabasePath(DB_NAME), KEY_CIPHER.getBytes()); | ||
| 156 | - } | ||
| 157 | } | 111 | } | 
| 158 | 112 | ||
| 159 | /** | 113 | /** | 
| 160 | - * Gets a writable database connection on a background thread with timeout. | 114 | + * Get standard SQLite database connection | 
| 161 | - * This prevents ANR issues by ensuring database operations don't block the main thread. | ||
| 162 | */ | 115 | */ | 
| 163 | private SQLiteDatabase getDb() { | 116 | private SQLiteDatabase getDb() { | 
| 164 | if (mDb == null || !mDb.isOpen()) { | 117 | if (mDb == null || !mDb.isOpen()) { | 
| 165 | - try { | 118 | + mDb = getWritableDatabase(); | 
| 166 | - // Submit task to executor and get future | ||
| 167 | - Future<SQLiteDatabase> future = dbExecutor.submit(() -> getWritableDatabase(KEY_CIPHER)); | ||
| 168 | - | ||
| 169 | - // Wait for result with timeout | ||
| 170 | - mDb = future.get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); | ||
| 171 | - | ||
| 172 | - // Set busy timeout on the database connection | ||
| 173 | - if (mDb != null && mDb.isOpen()) { | ||
| 174 | - mDb.rawExecSQL("PRAGMA busy_timeout = " + CONNECTION_TIMEOUT_MS); | ||
| 175 | - } | ||
| 176 | - } catch (TimeoutException e) { | ||
| 177 | - Log.e("WarplyDBHelper", "Timeout getting writable database connection", e); | ||
| 178 | - // Return null or handle timeout as appropriate | ||
| 179 | - } catch (Exception e) { | ||
| 180 | - Log.e("WarplyDBHelper", "Error getting writable database connection", e); | ||
| 181 | - // Handle other exceptions | ||
| 182 | - } | ||
| 183 | } | 119 | } | 
| 184 | return mDb; | 120 | return mDb; | 
| 185 | } | 121 | } | 
| 186 | 122 | ||
| 187 | - /** | ||
| 188 | - * Gets a readable database connection on a background thread with timeout. | ||
| 189 | - * This prevents ANR issues by ensuring database operations don't block the main thread. | ||
| 190 | - */ | ||
| 191 | - private SQLiteDatabase getReadableDb() { | ||
| 192 | - if (mDb == null || !mDb.isOpen()) { | ||
| 193 | - try { | ||
| 194 | - // Submit task to executor and get future | ||
| 195 | - Future<SQLiteDatabase> future = dbExecutor.submit(() -> getReadableDatabase(KEY_CIPHER)); | ||
| 196 | - | ||
| 197 | - // Wait for result with timeout | ||
| 198 | - mDb = future.get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); | ||
| 199 | - | ||
| 200 | - // Set busy timeout on the database connection | ||
| 201 | - if (mDb != null && mDb.isOpen()) { | ||
| 202 | - mDb.rawExecSQL("PRAGMA busy_timeout = " + CONNECTION_TIMEOUT_MS); | ||
| 203 | - } | ||
| 204 | - } catch (TimeoutException e) { | ||
| 205 | - Log.e("WarplyDBHelper", "Timeout getting readable database connection", e); | ||
| 206 | - // Return null or handle timeout as appropriate | ||
| 207 | - } catch (Exception e) { | ||
| 208 | - Log.e("WarplyDBHelper", "Error getting readable database connection", e); | ||
| 209 | - // Handle other exceptions | ||
| 210 | - } | ||
| 211 | - } | ||
| 212 | - return mDb; | ||
| 213 | - } | ||
| 214 | - | ||
| 215 | - /** | ||
| 216 | - * Close database connection - should only be called when app is being destroyed | ||
| 217 | - * or when database won't be used for a long time | ||
| 218 | - */ | ||
| 219 | - private void closeDb() { | ||
| 220 | - if (mDb != null && mDb.isOpen()) { | ||
| 221 | - mDb.close(); | ||
| 222 | - mDb = null; | ||
| 223 | - } | ||
| 224 | - } | ||
| 225 | - | ||
| 226 | - /** | ||
| 227 | - * Initialize database connection on a background thread. | ||
| 228 | - * Call this during app startup to prevent ANR issues. | ||
| 229 | - */ | ||
| 230 | - public void initialize() { | ||
| 231 | - if (mDb == null || !mDb.isOpen()) { | ||
| 232 | - try { | ||
| 233 | - // Submit task to executor and get future | ||
| 234 | - Future<SQLiteDatabase> future = dbExecutor.submit(() -> getWritableDatabase(KEY_CIPHER)); | ||
| 235 | - | ||
| 236 | - // Wait for result with timeout | ||
| 237 | - mDb = future.get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); | ||
| 238 | - | ||
| 239 | - // Set busy timeout on the database connection | ||
| 240 | - if (mDb != null && mDb.isOpen()) { | ||
| 241 | - mDb.rawExecSQL("PRAGMA busy_timeout = " + CONNECTION_TIMEOUT_MS); | ||
| 242 | - } | ||
| 243 | - } catch (TimeoutException e) { | ||
| 244 | - Log.e("WarplyDBHelper", "Timeout initializing database connection", e); | ||
| 245 | - } catch (Exception e) { | ||
| 246 | - Log.e("WarplyDBHelper", "Error initializing database connection", e); | ||
| 247 | - } | ||
| 248 | - } | ||
| 249 | - } | ||
| 250 | - | ||
| 251 | - /** | ||
| 252 | - * Shutdown database connection and executor service. | ||
| 253 | - * Call this when app is being destroyed. | ||
| 254 | - */ | ||
| 255 | - public void shutdown() { | ||
| 256 | - closeDb(); | ||
| 257 | - | ||
| 258 | - // Shutdown executor service | ||
| 259 | - dbExecutor.shutdown(); | ||
| 260 | - try { | ||
| 261 | - if (!dbExecutor.awaitTermination(5, TimeUnit.SECONDS)) { | ||
| 262 | - dbExecutor.shutdownNow(); | ||
| 263 | - } | ||
| 264 | - } catch (InterruptedException e) { | ||
| 265 | - dbExecutor.shutdownNow(); | ||
| 266 | - Thread.currentThread().interrupt(); | ||
| 267 | - } | ||
| 268 | - } | ||
| 269 | - | ||
| 270 | @Override | 123 | @Override | 
| 271 | public void onCreate(SQLiteDatabase db) { | 124 | public void onCreate(SQLiteDatabase db) { | 
| 272 | - // Create tables | ||
| 273 | db.execSQL(CREATE_TABLE_REQUESTS); | 125 | db.execSQL(CREATE_TABLE_REQUESTS); | 
| 274 | db.execSQL(CREATE_TABLE_TAGS); | 126 | db.execSQL(CREATE_TABLE_TAGS); | 
| 275 | db.execSQL(CREATE_TABLE_PUSH_REQUESTS); | 127 | db.execSQL(CREATE_TABLE_PUSH_REQUESTS); | 
| 276 | db.execSQL(CREATE_TABLE_PUSH_ACK_REQUESTS); | 128 | db.execSQL(CREATE_TABLE_PUSH_ACK_REQUESTS); | 
| 277 | db.execSQL(CREATE_TABLE_CLIENT); | 129 | db.execSQL(CREATE_TABLE_CLIENT); | 
| 278 | db.execSQL(CREATE_TABLE_AUTH); | 130 | db.execSQL(CREATE_TABLE_AUTH); | 
| 279 | - db.execSQL(CREATE_TABLE_TELEMATICS); | ||
| 280 | - | ||
| 281 | - // Create indexes for frequently queried columns to improve performance | ||
| 282 | - db.execSQL("CREATE INDEX IF NOT EXISTS idx_requests_force ON " + TABLE_REQUESTS + "(" + KEY_REQUESTS_FORCE + ")"); | ||
| 283 | - db.execSQL("CREATE INDEX IF NOT EXISTS idx_requests_date ON " + TABLE_REQUESTS + "(" + KEY_REQUESTS_DATE_ADDED + ")"); | ||
| 284 | - db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_requests_force ON " + TABLE_PUSH_REQUESTS + "(" + KEY_REQUESTS_FORCE + ")"); | ||
| 285 | - db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_requests_date ON " + TABLE_PUSH_REQUESTS + "(" + KEY_REQUESTS_DATE_ADDED + ")"); | ||
| 286 | - db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_ack_requests_force ON " + TABLE_PUSH_ACK_REQUESTS + "(" + KEY_REQUESTS_FORCE + ")"); | ||
| 287 | - db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_ack_requests_date ON " + TABLE_PUSH_ACK_REQUESTS + "(" + KEY_REQUESTS_DATE_ADDED + ")"); | ||
| 288 | } | 131 | } | 
| 289 | 132 | ||
| 290 | @Override | 133 | @Override | 
| ... | @@ -297,7 +140,6 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -297,7 +140,6 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 297 | db.execSQL("drop table if exists " + TABLE_TAGS); | 140 | db.execSQL("drop table if exists " + TABLE_TAGS); | 
| 298 | db.execSQL("drop table if exists " + TABLE_CLIENT); | 141 | db.execSQL("drop table if exists " + TABLE_CLIENT); | 
| 299 | db.execSQL("drop table if exists " + TABLE_AUTH); | 142 | db.execSQL("drop table if exists " + TABLE_AUTH); | 
| 300 | - db.execSQL("drop table if exists " + TABLE_TELEMATICS); | ||
| 301 | onCreate(db); | 143 | onCreate(db); | 
| 302 | } | 144 | } | 
| 303 | } | 145 | } | 
| ... | @@ -310,7 +152,6 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -310,7 +152,6 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 310 | db.execSQL("drop table if exists " + TABLE_TAGS); | 152 | db.execSQL("drop table if exists " + TABLE_TAGS); | 
| 311 | db.execSQL("drop table if exists " + TABLE_CLIENT); | 153 | db.execSQL("drop table if exists " + TABLE_CLIENT); | 
| 312 | db.execSQL("drop table if exists " + TABLE_AUTH); | 154 | db.execSQL("drop table if exists " + TABLE_AUTH); | 
| 313 | - db.execSQL("drop table if exists " + TABLE_TELEMATICS); | ||
| 314 | onCreate(db); | 155 | onCreate(db); | 
| 315 | } | 156 | } | 
| 316 | 157 | ||
| ... | @@ -337,45 +178,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -337,45 +178,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 337 | public synchronized void clearTable(String tableName) { | 178 | public synchronized void clearTable(String tableName) { | 
| 338 | SQLiteDatabase db = getDb(); | 179 | SQLiteDatabase db = getDb(); | 
| 339 | db.delete(tableName, null, null); | 180 | db.delete(tableName, null, null); | 
| 340 | - // Don't close the database here to improve performance | ||
| 341 | } | 181 | } | 
| 342 | 182 | ||
| 343 | public synchronized void insert(String tableName, ContentValues values) { | 183 | public synchronized void insert(String tableName, ContentValues values) { | 
| 344 | SQLiteDatabase db = getDb(); | 184 | SQLiteDatabase db = getDb(); | 
| 345 | db.insert(tableName, null, values); | 185 | db.insert(tableName, null, values); | 
| 346 | - // Don't close the database here to improve performance | ||
| 347 | } | 186 | } | 
| 348 | 187 | ||
| 349 | public synchronized void update(String tableName, ContentValues values) { | 188 | public synchronized void update(String tableName, ContentValues values) { | 
| 350 | SQLiteDatabase db = getDb(); | 189 | SQLiteDatabase db = getDb(); | 
| 351 | db.update(tableName, values, null, null); | 190 | db.update(tableName, values, null, null); | 
| 352 | - // Don't close the database here to improve performance | ||
| 353 | } | 191 | } | 
| 354 | 192 | ||
| 355 | public synchronized boolean isTableNotEmpty(String tableName) { | 193 | public synchronized boolean isTableNotEmpty(String tableName) { | 
| 356 | - boolean isNotEmpty = false; | 194 | + Cursor cursor = getDb().rawQuery("SELECT COUNT(*) FROM " + tableName, | 
| 357 | - Cursor cursor = null; | 195 | + null); | 
| 358 | - try { | 196 | + if (cursor != null && cursor.moveToFirst()) { | 
| 359 | - cursor = getReadableDb().rawQuery("SELECT COUNT(*) FROM " + tableName, null); | 197 | + boolean isNotEmpty = cursor.getInt(0) > 0; | 
| 360 | - if (cursor != null && cursor.moveToFirst()) { | 198 | + cursor.close(); | 
| 361 | - isNotEmpty = cursor.getInt(0) > 0; | 199 | + return isNotEmpty; | 
| 362 | - } | 200 | + } else | 
| 363 | - } finally { | 201 | + return false; | 
| 364 | - if (cursor != null) { | ||
| 365 | - cursor.close(); | ||
| 366 | - } | ||
| 367 | - // Don't close the database here to improve performance | ||
| 368 | - } | ||
| 369 | - return isNotEmpty; | ||
| 370 | } | 202 | } | 
| 371 | 203 | ||
| 372 | - //------------------------------ Auth -----------------------------// | 204 | + //------------------------------ Auth (with field-level encryption) -----------------------------// | 
| 373 | public synchronized void saveClientAccess(String clientId, String clientSecret) { | 205 | public synchronized void saveClientAccess(String clientId, String clientSecret) { | 
| 374 | ContentValues values = new ContentValues(); | 206 | ContentValues values = new ContentValues(); | 
| 375 | if (!TextUtils.isEmpty(clientId)) | 207 | if (!TextUtils.isEmpty(clientId)) | 
| 376 | - values.put(KEY_CLIENT_ID, clientId); | 208 | + values.put(KEY_CLIENT_ID, CryptoUtils.encrypt(clientId)); | 
| 377 | if (!TextUtils.isEmpty(clientSecret)) | 209 | if (!TextUtils.isEmpty(clientSecret)) | 
| 378 | - values.put(KEY_CLIENT_SECRET, clientSecret); | 210 | + values.put(KEY_CLIENT_SECRET, CryptoUtils.encrypt(clientSecret)); | 
| 379 | if (isTableNotEmpty(TABLE_CLIENT)) | 211 | if (isTableNotEmpty(TABLE_CLIENT)) | 
| 380 | update(TABLE_CLIENT, values); | 212 | update(TABLE_CLIENT, values); | 
| 381 | else | 213 | else | 
| ... | @@ -385,9 +217,9 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -385,9 +217,9 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 385 | public synchronized void saveAuthAccess(String accessToken, String refreshToken) { | 217 | public synchronized void saveAuthAccess(String accessToken, String refreshToken) { | 
| 386 | ContentValues values = new ContentValues(); | 218 | ContentValues values = new ContentValues(); | 
| 387 | if (!TextUtils.isEmpty(accessToken)) | 219 | if (!TextUtils.isEmpty(accessToken)) | 
| 388 | - values.put(KEY_ACCESS_TOKEN, accessToken); | 220 | + values.put(KEY_ACCESS_TOKEN, CryptoUtils.encrypt(accessToken)); | 
| 389 | if (!TextUtils.isEmpty(refreshToken)) | 221 | if (!TextUtils.isEmpty(refreshToken)) | 
| 390 | - values.put(KEY_REFRESH_TOKEN, refreshToken); | 222 | + values.put(KEY_REFRESH_TOKEN, CryptoUtils.encrypt(refreshToken)); | 
| 391 | if (isTableNotEmpty(TABLE_AUTH)) | 223 | if (isTableNotEmpty(TABLE_AUTH)) | 
| 392 | update(TABLE_AUTH, values); | 224 | update(TABLE_AUTH, values); | 
| 393 | else | 225 | else | 
| ... | @@ -397,17 +229,11 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -397,17 +229,11 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 397 | @Nullable | 229 | @Nullable | 
| 398 | public synchronized String getAuthValue(String columnName) { | 230 | public synchronized String getAuthValue(String columnName) { | 
| 399 | String columnValue = ""; | 231 | String columnValue = ""; | 
| 400 | - Cursor cursor = null; | 232 | + Cursor cursor = getDb().query(TABLE_AUTH, new String[]{columnName}, null, null, null, null, null); | 
| 401 | - try { | 233 | + if (cursor != null && cursor.moveToFirst()) { | 
| 402 | - cursor = getReadableDb().query(TABLE_AUTH, new String[]{columnName}, null, null, null, null, null); | 234 | + String encryptedValue = cursor.getString(cursor.getColumnIndex(columnName)); | 
| 403 | - if (cursor != null && cursor.moveToFirst()) { | 235 | + columnValue = CryptoUtils.decrypt(encryptedValue); | 
| 404 | - columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 236 | + cursor.close(); | 
| 405 | - } | ||
| 406 | - } finally { | ||
| 407 | - if (cursor != null) { | ||
| 408 | - cursor.close(); | ||
| 409 | - } | ||
| 410 | - // Don't close the database here to improve performance | ||
| 411 | } | 237 | } | 
| 412 | return columnValue; | 238 | return columnValue; | 
| 413 | } | 239 | } | 
| ... | @@ -415,17 +241,11 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -415,17 +241,11 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 415 | @Nullable | 241 | @Nullable | 
| 416 | public synchronized String getClientValue(String columnName) { | 242 | public synchronized String getClientValue(String columnName) { | 
| 417 | String columnValue = ""; | 243 | String columnValue = ""; | 
| 418 | - Cursor cursor = null; | 244 | + Cursor cursor = getDb().query(TABLE_CLIENT, new String[]{columnName}, null, null, null, null, null); | 
| 419 | - try { | 245 | + if (cursor != null && cursor.moveToFirst()) { | 
| 420 | - cursor = getReadableDb().query(TABLE_CLIENT, new String[]{columnName}, null, null, null, null, null); | 246 | + String encryptedValue = cursor.getString(cursor.getColumnIndex(columnName)); | 
| 421 | - if (cursor != null && cursor.moveToFirst()) { | 247 | + columnValue = CryptoUtils.decrypt(encryptedValue); | 
| 422 | - columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 248 | + cursor.close(); | 
| 423 | - } | ||
| 424 | - } finally { | ||
| 425 | - if (cursor != null) { | ||
| 426 | - cursor.close(); | ||
| 427 | - } | ||
| 428 | - // Don't close the database here to improve performance | ||
| 429 | } | 249 | } | 
| 430 | return columnValue; | 250 | return columnValue; | 
| 431 | } | 251 | } | 
| ... | @@ -439,37 +259,25 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -439,37 +259,25 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 439 | } | 259 | } | 
| 440 | 260 | ||
| 441 | //------------------------------ Api requests -----------------------------// | 261 | //------------------------------ Api requests -----------------------------// | 
| 442 | - /** | ||
| 443 | - * Gets all requests from the database. | ||
| 444 | - * NOTE: The caller is responsible for closing the returned Cursor when done with it. | ||
| 445 | - */ | ||
| 446 | public synchronized Cursor getAllRequests() { | 262 | public synchronized Cursor getAllRequests() { | 
| 447 | - // We don't close the database here because the cursor needs it to remain open | 263 | + | 
| 448 | - return getReadableDb().query(TABLE_REQUESTS, | 264 | + return getDb().query(TABLE_REQUESTS, | 
| 449 | new String[]{KEY_REQUESTS_ID, | 265 | new String[]{KEY_REQUESTS_ID, | 
| 450 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 266 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 
| 451 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 267 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 
| 452 | } | 268 | } | 
| 453 | 269 | ||
| 454 | - /** | ||
| 455 | - * Gets all push requests from the database. | ||
| 456 | - * NOTE: The caller is responsible for closing the returned Cursor when done with it. | ||
| 457 | - */ | ||
| 458 | public synchronized Cursor getAllPushRequests() { | 270 | public synchronized Cursor getAllPushRequests() { | 
| 459 | - // We don't close the database here because the cursor needs it to remain open | 271 | + | 
| 460 | - return getReadableDb().query(TABLE_PUSH_REQUESTS, | 272 | + return getDb().query(TABLE_PUSH_REQUESTS, | 
| 461 | new String[]{KEY_REQUESTS_ID, | 273 | new String[]{KEY_REQUESTS_ID, | 
| 462 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 274 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 
| 463 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 275 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 
| 464 | } | 276 | } | 
| 465 | 277 | ||
| 466 | - /** | ||
| 467 | - * Gets all push acknowledgment requests from the database. | ||
| 468 | - * NOTE: The caller is responsible for closing the returned Cursor when done with it. | ||
| 469 | - */ | ||
| 470 | public synchronized Cursor getAllPushAckRequests() { | 278 | public synchronized Cursor getAllPushAckRequests() { | 
| 471 | - // We don't close the database here because the cursor needs it to remain open | 279 | + | 
| 472 | - return getReadableDb().query(TABLE_PUSH_ACK_REQUESTS, | 280 | + return getDb().query(TABLE_PUSH_ACK_REQUESTS, | 
| 473 | new String[]{KEY_REQUESTS_ID, | 281 | new String[]{KEY_REQUESTS_ID, | 
| 474 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 282 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 
| 475 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 283 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 
| ... | @@ -488,6 +296,7 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -488,6 +296,7 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 488 | } | 296 | } | 
| 489 | 297 | ||
| 490 | public synchronized long addRequest(String microapp, String entity, boolean force) { | 298 | public synchronized long addRequest(String microapp, String entity, boolean force) { | 
| 299 | + | ||
| 491 | ContentValues values = new ContentValues(); | 300 | ContentValues values = new ContentValues(); | 
| 492 | values.put(KEY_REQUESTS_MICROAPP, microapp); | 301 | values.put(KEY_REQUESTS_MICROAPP, microapp); | 
| 493 | values.put(KEY_REQUESTS_ENTITY, entity); | 302 | values.put(KEY_REQUESTS_ENTITY, entity); | 
| ... | @@ -498,6 +307,7 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -498,6 +307,7 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 498 | } | 307 | } | 
| 499 | 308 | ||
| 500 | public synchronized long addPushRequest(String microapp, String entity, boolean force) { | 309 | public synchronized long addPushRequest(String microapp, String entity, boolean force) { | 
| 310 | + | ||
| 501 | ContentValues values = new ContentValues(); | 311 | ContentValues values = new ContentValues(); | 
| 502 | values.put(KEY_REQUESTS_MICROAPP, microapp); | 312 | values.put(KEY_REQUESTS_MICROAPP, microapp); | 
| 503 | values.put(KEY_REQUESTS_ENTITY, entity); | 313 | values.put(KEY_REQUESTS_ENTITY, entity); | 
| ... | @@ -508,6 +318,7 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -508,6 +318,7 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 508 | } | 318 | } | 
| 509 | 319 | ||
| 510 | public synchronized long addPushAckRequest(String microapp, String entity, boolean force) { | 320 | public synchronized long addPushAckRequest(String microapp, String entity, boolean force) { | 
| 321 | + | ||
| 511 | ContentValues values = new ContentValues(); | 322 | ContentValues values = new ContentValues(); | 
| 512 | values.put(KEY_REQUESTS_MICROAPP, microapp); | 323 | values.put(KEY_REQUESTS_MICROAPP, microapp); | 
| 513 | values.put(KEY_REQUESTS_ENTITY, entity); | 324 | values.put(KEY_REQUESTS_ENTITY, entity); | 
| ... | @@ -518,225 +329,131 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -518,225 +329,131 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 518 | } | 329 | } | 
| 519 | 330 | ||
| 520 | public synchronized long getRequestsInQueueCount() { | 331 | public synchronized long getRequestsInQueueCount() { | 
| 521 | - SQLiteDatabase db = getReadableDb(); | 332 | + return DatabaseUtils.queryNumEntries(getReadableDatabase(), TABLE_REQUESTS); | 
| 522 | - long count = DatabaseUtils.queryNumEntries(db, TABLE_REQUESTS); | ||
| 523 | - // Don't close the database here to improve performance | ||
| 524 | - return count; | ||
| 525 | } | 333 | } | 
| 526 | 334 | ||
| 527 | public synchronized long getPushRequestsInQueueCount() { | 335 | public synchronized long getPushRequestsInQueueCount() { | 
| 528 | - SQLiteDatabase db = getReadableDb(); | 336 | + return DatabaseUtils.queryNumEntries(getReadableDatabase(), TABLE_PUSH_REQUESTS); | 
| 529 | - long count = DatabaseUtils.queryNumEntries(db, TABLE_PUSH_REQUESTS); | ||
| 530 | - // Don't close the database here to improve performance | ||
| 531 | - return count; | ||
| 532 | } | 337 | } | 
| 533 | 338 | ||
| 534 | public synchronized long getPushAckRequestsInQueueCount() { | 339 | public synchronized long getPushAckRequestsInQueueCount() { | 
| 535 | - SQLiteDatabase db = getReadableDb(); | 340 | + return DatabaseUtils.queryNumEntries(getReadableDatabase(), TABLE_PUSH_ACK_REQUESTS); | 
| 536 | - long count = DatabaseUtils.queryNumEntries(db, TABLE_PUSH_ACK_REQUESTS); | ||
| 537 | - // Don't close the database here to improve performance | ||
| 538 | - return count; | ||
| 539 | } | 341 | } | 
| 540 | 342 | ||
| 541 | public synchronized void deleteRequests(Long... ids) { | 343 | public synchronized void deleteRequests(Long... ids) { | 
| 542 | - if (ids.length == 0) return; | ||
| 543 | 344 | ||
| 544 | - SQLiteDatabase db = getDb(); | 345 | + StringBuilder strFilter = new StringBuilder(); | 
| 545 | - try { | 346 | + for (int i = 0; i < ids.length; i++) { | 
| 546 | - db.beginTransaction(); | 347 | + if (i > 0) { | 
| 547 | - StringBuilder strFilter = new StringBuilder(); | 348 | + strFilter.append(" OR "); | 
| 548 | - for (int i = 0; i < ids.length; i++) { | ||
| 549 | - if (i > 0) { | ||
| 550 | - strFilter.append(" OR "); | ||
| 551 | - } | ||
| 552 | - strFilter.append(KEY_REQUESTS_ID); | ||
| 553 | - strFilter.append("="); | ||
| 554 | - strFilter.append(ids[i]); | ||
| 555 | } | 349 | } | 
| 556 | - db.delete(TABLE_REQUESTS, strFilter.toString(), null); | 350 | + strFilter.append(KEY_REQUESTS_ID); | 
| 557 | - db.setTransactionSuccessful(); | 351 | + strFilter.append("="); | 
| 558 | - } finally { | 352 | + strFilter.append(ids[i]); | 
| 559 | - db.endTransaction(); | ||
| 560 | - // Don't close the database here to improve performance | ||
| 561 | } | 353 | } | 
| 354 | + getDb().delete(TABLE_REQUESTS, strFilter.toString(), null); | ||
| 562 | } | 355 | } | 
| 563 | 356 | ||
| 564 | public synchronized void deletePushRequests(Long... ids) { | 357 | public synchronized void deletePushRequests(Long... ids) { | 
| 565 | - if (ids.length == 0) return; | ||
| 566 | 358 | ||
| 567 | - SQLiteDatabase db = getDb(); | 359 | + StringBuilder strFilter = new StringBuilder(); | 
| 568 | - try { | 360 | + for (int i = 0; i < ids.length; i++) { | 
| 569 | - db.beginTransaction(); | 361 | + if (i > 0) { | 
| 570 | - StringBuilder strFilter = new StringBuilder(); | 362 | + strFilter.append(" OR "); | 
| 571 | - for (int i = 0; i < ids.length; i++) { | ||
| 572 | - if (i > 0) { | ||
| 573 | - strFilter.append(" OR "); | ||
| 574 | - } | ||
| 575 | - strFilter.append(KEY_REQUESTS_ID); | ||
| 576 | - strFilter.append("="); | ||
| 577 | - strFilter.append(ids[i]); | ||
| 578 | } | 363 | } | 
| 579 | - db.delete(TABLE_PUSH_REQUESTS, strFilter.toString(), null); | 364 | + strFilter.append(KEY_REQUESTS_ID); | 
| 580 | - db.setTransactionSuccessful(); | 365 | + strFilter.append("="); | 
| 581 | - } finally { | 366 | + strFilter.append(ids[i]); | 
| 582 | - db.endTransaction(); | ||
| 583 | - // Don't close the database here to improve performance | ||
| 584 | } | 367 | } | 
| 368 | + getDb().delete(TABLE_PUSH_REQUESTS, strFilter.toString(), null); | ||
| 585 | } | 369 | } | 
| 586 | 370 | ||
| 587 | public synchronized void deletePushAckRequests(Long... ids) { | 371 | public synchronized void deletePushAckRequests(Long... ids) { | 
| 588 | - if (ids.length == 0) return; | ||
| 589 | 372 | ||
| 590 | - SQLiteDatabase db = getDb(); | 373 | + StringBuilder strFilter = new StringBuilder(); | 
| 591 | - try { | 374 | + for (int i = 0; i < ids.length; i++) { | 
| 592 | - db.beginTransaction(); | 375 | + if (i > 0) { | 
| 593 | - StringBuilder strFilter = new StringBuilder(); | 376 | + strFilter.append(" OR "); | 
| 594 | - for (int i = 0; i < ids.length; i++) { | ||
| 595 | - if (i > 0) { | ||
| 596 | - strFilter.append(" OR "); | ||
| 597 | - } | ||
| 598 | - strFilter.append(KEY_REQUESTS_ID); | ||
| 599 | - strFilter.append("="); | ||
| 600 | - strFilter.append(ids[i]); | ||
| 601 | } | 377 | } | 
| 602 | - db.delete(TABLE_PUSH_ACK_REQUESTS, strFilter.toString(), null); | 378 | + strFilter.append(KEY_REQUESTS_ID); | 
| 603 | - db.setTransactionSuccessful(); | 379 | + strFilter.append("="); | 
| 604 | - } finally { | 380 | + strFilter.append(ids[i]); | 
| 605 | - db.endTransaction(); | ||
| 606 | - // Don't close the database here to improve performance | ||
| 607 | } | 381 | } | 
| 382 | + getDb().delete(TABLE_PUSH_ACK_REQUESTS, strFilter.toString(), null); | ||
| 608 | } | 383 | } | 
| 609 | 384 | ||
| 610 | public synchronized boolean isForceRequestsExist() { | 385 | public synchronized boolean isForceRequestsExist() { | 
| 386 | + Cursor cursor = getDb().query(TABLE_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
| 387 | + null, null, null, null); | ||
| 611 | boolean result = false; | 388 | boolean result = false; | 
| 612 | - Cursor cursor = null; | 389 | + if (cursor != null) { | 
| 613 | - try { | 390 | + result = cursor.getCount() > 0; | 
| 614 | - cursor = getReadableDb().query(TABLE_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | 391 | + cursor.close(); | 
| 615 | - null, null, null, null); | ||
| 616 | - if (cursor != null) { | ||
| 617 | - result = cursor.getCount() > 0; | ||
| 618 | - } | ||
| 619 | - } finally { | ||
| 620 | - if (cursor != null) { | ||
| 621 | - cursor.close(); | ||
| 622 | - } | ||
| 623 | - // Don't close the database here to improve performance | ||
| 624 | } | 392 | } | 
| 625 | return result; | 393 | return result; | 
| 626 | } | 394 | } | 
| 627 | 395 | ||
| 628 | public synchronized boolean isForcePushRequestsExist() { | 396 | public synchronized boolean isForcePushRequestsExist() { | 
| 397 | + Cursor cursor = getDb().query(TABLE_PUSH_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
| 398 | + null, null, null, null); | ||
| 629 | boolean result = false; | 399 | boolean result = false; | 
| 630 | - Cursor cursor = null; | 400 | + if (cursor != null) { | 
| 631 | - try { | 401 | + result = cursor.getCount() > 0; | 
| 632 | - cursor = getReadableDb().query(TABLE_PUSH_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | 402 | + cursor.close(); | 
| 633 | - null, null, null, null); | ||
| 634 | - if (cursor != null) { | ||
| 635 | - result = cursor.getCount() > 0; | ||
| 636 | - } | ||
| 637 | - } finally { | ||
| 638 | - if (cursor != null) { | ||
| 639 | - cursor.close(); | ||
| 640 | - } | ||
| 641 | - // Don't close the database here to improve performance | ||
| 642 | } | 403 | } | 
| 643 | return result; | 404 | return result; | 
| 644 | } | 405 | } | 
| 645 | 406 | ||
| 646 | public synchronized boolean isForcePushAckRequestsExist() { | 407 | public synchronized boolean isForcePushAckRequestsExist() { | 
| 408 | + Cursor cursor = getDb().query(TABLE_PUSH_ACK_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
| 409 | + null, null, null, null); | ||
| 647 | boolean result = false; | 410 | boolean result = false; | 
| 648 | - Cursor cursor = null; | 411 | + if (cursor != null) { | 
| 649 | - try { | 412 | + result = cursor.getCount() > 0; | 
| 650 | - cursor = getReadableDb().query(TABLE_PUSH_ACK_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | 413 | + cursor.close(); | 
| 651 | - null, null, null, null); | ||
| 652 | - if (cursor != null) { | ||
| 653 | - result = cursor.getCount() > 0; | ||
| 654 | - } | ||
| 655 | - } finally { | ||
| 656 | - if (cursor != null) { | ||
| 657 | - cursor.close(); | ||
| 658 | - } | ||
| 659 | - // Don't close the database here to improve performance | ||
| 660 | } | 414 | } | 
| 661 | return result; | 415 | return result; | 
| 662 | } | 416 | } | 
| 663 | 417 | ||
| 664 | //------------------------------ Tags -----------------------------// | 418 | //------------------------------ Tags -----------------------------// | 
| 665 | public synchronized void saveTags(String[] tags) { | 419 | public synchronized void saveTags(String[] tags) { | 
| 420 | + | ||
| 666 | if (tags != null && tags.length > 0) { | 421 | if (tags != null && tags.length > 0) { | 
| 667 | - SQLiteDatabase db = getDb(); | 422 | + | 
| 668 | try { | 423 | try { | 
| 669 | - db.beginTransaction(); | 424 | + getDb().beginTransaction(); | 
| 670 | ContentValues values = new ContentValues(); | 425 | ContentValues values = new ContentValues(); | 
| 671 | for (String tag : tags) { | 426 | for (String tag : tags) { | 
| 672 | - values.clear(); | ||
| 673 | values.put(KEY_TAG, tag); | 427 | values.put(KEY_TAG, tag); | 
| 674 | values.put(KEY_TAG_LAST_ADD_DATE, System.currentTimeMillis()); | 428 | values.put(KEY_TAG_LAST_ADD_DATE, System.currentTimeMillis()); | 
| 675 | - db.insert(TABLE_TAGS, null, values); | 429 | + insert(TABLE_TAGS, values); | 
| 676 | } | 430 | } | 
| 677 | - db.setTransactionSuccessful(); | 431 | + getDb().setTransactionSuccessful(); | 
| 432 | + | ||
| 678 | } catch (SQLException e) { | 433 | } catch (SQLException e) { | 
| 679 | if (WarpConstants.DEBUG) { | 434 | if (WarpConstants.DEBUG) { | 
| 680 | e.printStackTrace(); | 435 | e.printStackTrace(); | 
| 681 | } | 436 | } | 
| 682 | } finally { | 437 | } finally { | 
| 683 | - db.endTransaction(); | 438 | + getDb().endTransaction(); | 
| 684 | - // Don't close the database here to improve performance | ||
| 685 | - } | ||
| 686 | - } | ||
| 687 | - } | ||
| 688 | - | ||
| 689 | - public synchronized void saveTelematics(JSONArray jsonArray) { | ||
| 690 | - if (jsonArray != null && jsonArray.length() > 0) { | ||
| 691 | - SQLiteDatabase db = getDb(); | ||
| 692 | - try { | ||
| 693 | - db.beginTransaction(); | ||
| 694 | - ContentValues values = new ContentValues(); | ||
| 695 | - for (int i = 0; i < jsonArray.length(); i++) { | ||
| 696 | - JSONObject jsonobject = jsonArray.optJSONObject(i); | ||
| 697 | - if (jsonobject != null) { | ||
| 698 | - values.clear(); | ||
| 699 | - String timestamp = jsonobject.keys().next(); | ||
| 700 | - values.put(KEY_TIMESTAMP, timestamp); | ||
| 701 | - JSONObject jobjData = jsonobject.optJSONObject(timestamp); | ||
| 702 | - if (jobjData != null) { | ||
| 703 | - values.put(KEY_ACCELERATION, jobjData.optDouble(KEY_ACCELERATION)); | ||
| 704 | - values.put(KEY_SPEED, jobjData.optDouble(KEY_SPEED)); | ||
| 705 | - } | ||
| 706 | - db.insert(TABLE_TELEMATICS, null, values); | ||
| 707 | - } | ||
| 708 | - } | ||
| 709 | - db.setTransactionSuccessful(); | ||
| 710 | - } finally { | ||
| 711 | - db.endTransaction(); | ||
| 712 | - // Don't close the database here to improve performance | ||
| 713 | } | 439 | } | 
| 714 | } | 440 | } | 
| 715 | } | 441 | } | 
| 716 | 442 | ||
| 717 | public synchronized void removeTags(String[] tags) { | 443 | public synchronized void removeTags(String[] tags) { | 
| 718 | - if (tags.length == 0) return; | ||
| 719 | 444 | ||
| 720 | - SQLiteDatabase db = getDb(); | 445 | + StringBuilder strFilter = new StringBuilder(); | 
| 721 | - try { | 446 | + for (int i = 0; i < tags.length; i++) { | 
| 722 | - db.beginTransaction(); | 447 | + if (i > 0) { | 
| 723 | - StringBuilder strFilter = new StringBuilder(); | 448 | + strFilter.append(" OR "); | 
| 724 | - for (int i = 0; i < tags.length; i++) { | ||
| 725 | - if (i > 0) { | ||
| 726 | - strFilter.append(" OR "); | ||
| 727 | - } | ||
| 728 | - strFilter.append(KEY_TAG); | ||
| 729 | - strFilter.append("="); | ||
| 730 | - strFilter.append("'"); | ||
| 731 | - strFilter.append(tags[i]); | ||
| 732 | - strFilter.append("'"); | ||
| 733 | } | 449 | } | 
| 734 | - db.delete(TABLE_TAGS, strFilter.toString(), null); | 450 | + strFilter.append(KEY_TAG); | 
| 735 | - db.setTransactionSuccessful(); | 451 | + strFilter.append("="); | 
| 736 | - } finally { | 452 | + strFilter.append("'"); | 
| 737 | - db.endTransaction(); | 453 | + strFilter.append(tags[i]); | 
| 738 | - // Don't close the database here to improve performance | 454 | + strFilter.append("'"); | 
| 739 | } | 455 | } | 
| 456 | + getDb().delete(TABLE_TAGS, strFilter.toString(), null); | ||
| 740 | } | 457 | } | 
| 741 | 458 | ||
| 742 | public synchronized void removeAllTags() { | 459 | public synchronized void removeAllTags() { | 
| ... | @@ -745,84 +462,18 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -745,84 +462,18 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 745 | 462 | ||
| 746 | @Nullable | 463 | @Nullable | 
| 747 | public synchronized String[] getTags() { | 464 | public synchronized String[] getTags() { | 
| 748 | - List<String> tags = null; | ||
| 749 | - Cursor cursor = null; | ||
| 750 | - try { | ||
| 751 | - cursor = getReadableDb().query(TABLE_TAGS, null, null, null, null, null, null); | ||
| 752 | - if (cursor != null) { | ||
| 753 | - tags = new ArrayList<>(cursor.getCount()); | ||
| 754 | - while (cursor.moveToNext()) { | ||
| 755 | - tags.add(cursor.getString(cursor.getColumnIndex(KEY_TAG))); | ||
| 756 | - } | ||
| 757 | - } | ||
| 758 | - } finally { | ||
| 759 | - if (cursor != null) { | ||
| 760 | - cursor.close(); | ||
| 761 | - } | ||
| 762 | - // Don't close the database here to improve performance | ||
| 763 | - } | ||
| 764 | - return tags != null ? tags.toArray(new String[tags.size()]) : null; | ||
| 765 | - } | ||
| 766 | - | ||
| 767 | - private State getDatabaseState(Context context, String dbName) { | ||
| 768 | - SQLiteDatabase.loadLibs(context); | ||
| 769 | 465 | ||
| 770 | - return (getDatabaseState(context.getDatabasePath(dbName))); | 466 | + List<String> tags = null; | 
| 771 | - } | 467 | + Cursor cursor = getDb().query(TABLE_TAGS, null, null, null, null, null, null); | 
| 772 | - | 468 | + if (cursor != null) { | 
| 773 | - private static State getDatabaseState(File dbPath) { | ||
| 774 | - if (dbPath.exists()) { | ||
| 775 | - SQLiteDatabase db = null; | ||
| 776 | - try { | ||
| 777 | - db = SQLiteDatabase.openDatabase(dbPath.getAbsolutePath(), "", null, SQLiteDatabase.OPEN_READONLY); | ||
| 778 | - db.getVersion(); | ||
| 779 | 469 | ||
| 780 | - return (State.UNENCRYPTED); | 470 | + tags = new ArrayList<>(cursor.getCount()); | 
| 781 | - } catch (Exception e) { | 471 | + while (cursor.moveToNext()) { | 
| 782 | - return (State.ENCRYPTED); | 472 | + tags.add(cursor.getString(cursor.getColumnIndex(KEY_TAG))); | 
| 783 | - } finally { | ||
| 784 | - if (db != null) { | ||
| 785 | - db.close(); | ||
| 786 | - } | ||
| 787 | } | 473 | } | 
| 474 | + cursor.close(); | ||
| 788 | } | 475 | } | 
| 789 | - | 476 | + return tags != null ? tags.toArray(new String[tags.size()]) : null; | 
| 790 | - return (State.DOES_NOT_EXIST); | ||
| 791 | } | 477 | } | 
| 792 | 478 | ||
| 793 | - private void encrypt(Context context, File originalFile, byte[] passphrase) { | ||
| 794 | - SQLiteDatabase.loadLibs(context); | ||
| 795 | - | ||
| 796 | - try { | ||
| 797 | - if (originalFile.exists()) { | ||
| 798 | - File newFile = File.createTempFile("sqlcipherutils", "tmp", context.getCacheDir()); | ||
| 799 | - SQLiteDatabase db = SQLiteDatabase.openDatabase(originalFile.getAbsolutePath(), | ||
| 800 | - "", null, SQLiteDatabase.OPEN_READWRITE); | ||
| 801 | - int version = db.getVersion(); | ||
| 802 | - | ||
| 803 | - db.close(); | ||
| 804 | - | ||
| 805 | - db = SQLiteDatabase.openDatabase(newFile.getAbsolutePath(), passphrase, | ||
| 806 | - null, SQLiteDatabase.OPEN_READWRITE, null, null); | ||
| 807 | - | ||
| 808 | - final SQLiteStatement st = db.compileStatement("ATTACH DATABASE ? AS plaintext KEY ''"); | ||
| 809 | - | ||
| 810 | - st.bindString(1, originalFile.getAbsolutePath()); | ||
| 811 | - st.execute(); | ||
| 812 | - | ||
| 813 | - db.rawExecSQL("SELECT sqlcipher_export('main', 'plaintext')"); | ||
| 814 | - db.rawExecSQL("DETACH DATABASE plaintext"); | ||
| 815 | - db.setVersion(version); | ||
| 816 | - st.close(); | ||
| 817 | - db.close(); | ||
| 818 | - | ||
| 819 | - originalFile.delete(); | ||
| 820 | - newFile.renameTo(originalFile); | ||
| 821 | - } else { | ||
| 822 | - throw new FileNotFoundException(originalFile.getAbsolutePath() + " not found"); | ||
| 823 | - } | ||
| 824 | - } catch (IOException ex) { | ||
| 825 | - Log.v("WarplyDB Exception: ", ex.getMessage()); | ||
| 826 | - } | ||
| 827 | - } | ||
| 828 | } | 479 | } | ... | ... | 
| ... | @@ -14,26 +14,19 @@ import android.widget.Toast; | ... | @@ -14,26 +14,19 @@ import android.widget.Toast; | 
| 14 | 14 | ||
| 15 | import androidx.annotation.NonNull; | 15 | import androidx.annotation.NonNull; | 
| 16 | import androidx.fragment.app.Fragment; | 16 | import androidx.fragment.app.Fragment; | 
| 17 | -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | ||
| 18 | 17 | ||
| 19 | import org.json.JSONObject; | 18 | import org.json.JSONObject; | 
| 20 | 19 | ||
| 21 | -import java.util.ArrayList; | ||
| 22 | - | ||
| 23 | import ly.warp.sdk.R; | 20 | import ly.warp.sdk.R; | 
| 24 | import ly.warp.sdk.activities.HomeActivity; | 21 | import ly.warp.sdk.activities.HomeActivity; | 
| 25 | import ly.warp.sdk.db.WarplyDBHelper; | 22 | import ly.warp.sdk.db.WarplyDBHelper; | 
| 26 | import ly.warp.sdk.io.callbacks.CallbackReceiver; | 23 | import ly.warp.sdk.io.callbacks.CallbackReceiver; | 
| 27 | -import ly.warp.sdk.io.models.Campaign; | ||
| 28 | -import ly.warp.sdk.io.models.RedeemedSMHistoryModel; | ||
| 29 | import ly.warp.sdk.utils.WarplyManagerHelper; | 24 | import ly.warp.sdk.utils.WarplyManagerHelper; | 
| 30 | import ly.warp.sdk.utils.managers.WarplyManager; | 25 | import ly.warp.sdk.utils.managers.WarplyManager; | 
| 31 | 26 | ||
| 32 | -public class HomeFragment extends Fragment implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener { | 27 | +public class HomeFragment extends Fragment implements View.OnClickListener { | 
| 33 | - | ||
| 34 | private RelativeLayout mOptionOne, mOptionTwo, mOptionThree, mPbLoading; | 28 | private RelativeLayout mOptionOne, mOptionTwo, mOptionThree, mPbLoading; | 
| 35 | private TextView mTvUsername, mTvUser; | 29 | private TextView mTvUsername, mTvUser; | 
| 36 | - private SwipeRefreshLayout mSwipeRefresh; | ||
| 37 | private EditText mEtGuid; | 30 | private EditText mEtGuid; | 
| 38 | private LinearLayout mLlAuthLogin, mLlAuthLogout, mRlSmFlow, mRlSmMap; | 31 | private LinearLayout mLlAuthLogin, mLlAuthLogout, mRlSmFlow, mRlSmMap; | 
| 39 | 32 | ||
| ... | @@ -45,8 +38,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | ... | @@ -45,8 +38,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | 
| 45 | public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { | 38 | public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { | 
| 46 | super.onViewCreated(view, savedInstanceState); | 39 | super.onViewCreated(view, savedInstanceState); | 
| 47 | 40 | ||
| 48 | - mSwipeRefresh = view.findViewById(R.id.sw_refresh); | ||
| 49 | - mSwipeRefresh.setOnRefreshListener(this); | ||
| 50 | mOptionOne = view.findViewById(R.id.info_button); | 41 | mOptionOne = view.findViewById(R.id.info_button); | 
| 51 | TextView mOptionOneText = mOptionOne.findViewById(R.id.option_text); | 42 | TextView mOptionOneText = mOptionOne.findViewById(R.id.option_text); | 
| 52 | ImageView mOptionOneImage = mOptionOne.findViewById(R.id.option_icon); | 43 | ImageView mOptionOneImage = mOptionOne.findViewById(R.id.option_icon); | 
| ... | @@ -100,17 +91,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | ... | @@ -100,17 +91,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | 
| 100 | } | 91 | } | 
| 101 | 92 | ||
| 102 | @Override | 93 | @Override | 
| 103 | - public void onRefresh() { | ||
| 104 | - if (WarplyDBHelper.getInstance(getActivity()).isTableNotEmpty("auth")) { | ||
| 105 | - WarplyManager.getSupermarketCampaign(mCampaignsCallback); | ||
| 106 | - WarplyManager.getRedeemedSMHistory(mSMHistoryReceiver); | ||
| 107 | - mSwipeRefresh.setRefreshing(false); | ||
| 108 | - } else { | ||
| 109 | - mSwipeRefresh.setRefreshing(false); | ||
| 110 | - } | ||
| 111 | - } | ||
| 112 | - | ||
| 113 | - @Override | ||
| 114 | public void onClick(View view) { | 94 | public void onClick(View view) { | 
| 115 | if (view.getId() == R.id.ll_auth_login) { | 95 | if (view.getId() == R.id.ll_auth_login) { | 
| 116 | //6012049321, 6012049322, 6012049323, 7000000831 history, 7000000826, 7000000831 shared coupons | 96 | //6012049321, 6012049322, 6012049323, 7000000831 history, 7000000826, 7000000831 shared coupons | 
| ... | @@ -141,18 +121,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | ... | @@ -141,18 +121,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | 
| 141 | return homeFragment; | 121 | return homeFragment; | 
| 142 | } | 122 | } | 
| 143 | 123 | ||
| 144 | - private final CallbackReceiver<ArrayList<Campaign>> mCampaignsCallback = new CallbackReceiver<ArrayList<Campaign>>() { | ||
| 145 | - @Override | ||
| 146 | - public void onSuccess(ArrayList<Campaign> result) { | ||
| 147 | - Toast.makeText(getActivity(), "Campaigns Success", Toast.LENGTH_SHORT).show(); | ||
| 148 | - } | ||
| 149 | - | ||
| 150 | - @Override | ||
| 151 | - public void onFailure(int errorCode) { | ||
| 152 | - Toast.makeText(getActivity(), "Campaigns Error", Toast.LENGTH_SHORT).show(); | ||
| 153 | - } | ||
| 154 | - }; | ||
| 155 | - | ||
| 156 | private final CallbackReceiver<JSONObject> mLogoutReceiver = new CallbackReceiver<JSONObject>() { | 124 | private final CallbackReceiver<JSONObject> mLogoutReceiver = new CallbackReceiver<JSONObject>() { | 
| 157 | @Override | 125 | @Override | 
| 158 | public void onSuccess(JSONObject result) { | 126 | public void onSuccess(JSONObject result) { | 
| ... | @@ -180,16 +148,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | ... | @@ -180,16 +148,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | 
| 180 | mLlAuthLogout.setVisibility(View.VISIBLE); | 148 | mLlAuthLogout.setVisibility(View.VISIBLE); | 
| 181 | mTvUser.setVisibility(View.VISIBLE); | 149 | mTvUser.setVisibility(View.VISIBLE); | 
| 182 | mTvUser.setText(mEtGuid.getText().toString()); | 150 | mTvUser.setText(mEtGuid.getText().toString()); | 
| 183 | -// if (WarplyManagerHelper.getConsumerInternal() != null) { | ||
| 184 | -// JSONObject profMetadata = WarpJSONParser.getJSONFromString(WarplyManagerHelper.getConsumerInternal().getProfileMetadata()); | ||
| 185 | -// if (profMetadata != null && profMetadata.has("guid")) { | ||
| 186 | -// String userGuid = profMetadata.optString("guid", ""); | ||
| 187 | -// mTvUser.setText(userGuid); | ||
| 188 | -// } | ||
| 189 | -// } | ||
| 190 | - | ||
| 191 | - WarplyManager.getSupermarketCampaign(mCampaignsCallback); | ||
| 192 | - WarplyManager.getRedeemedSMHistory(mSMHistoryReceiver); | ||
| 193 | } | 151 | } | 
| 194 | 152 | ||
| 195 | @Override | 153 | @Override | 
| ... | @@ -198,16 +156,4 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | ... | @@ -198,16 +156,4 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip | 
| 198 | Toast.makeText(getActivity(), "LOGIN ERROR", Toast.LENGTH_SHORT).show(); | 156 | Toast.makeText(getActivity(), "LOGIN ERROR", Toast.LENGTH_SHORT).show(); | 
| 199 | } | 157 | } | 
| 200 | }; | 158 | }; | 
| 201 | - | ||
| 202 | - private final CallbackReceiver<RedeemedSMHistoryModel> mSMHistoryReceiver = new CallbackReceiver<RedeemedSMHistoryModel>() { | ||
| 203 | - @Override | ||
| 204 | - public void onSuccess(RedeemedSMHistoryModel result) { | ||
| 205 | - Toast.makeText(getActivity(), "SM HISTORY SUCCESS", Toast.LENGTH_SHORT).show(); | ||
| 206 | - } | ||
| 207 | - | ||
| 208 | - @Override | ||
| 209 | - public void onFailure(int errorCode) { | ||
| 210 | - Toast.makeText(getActivity(), "SM HISTORY ERROR", Toast.LENGTH_SHORT).show(); | ||
| 211 | - } | ||
| 212 | - }; | ||
| 213 | } | 159 | } | 
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... | 
warply_android_sdk/src/main/java/ly/warp/sdk/io/models/MarketPassDetailsModel.java
deleted
100644 → 0
| 1 | -/* | ||
| 2 | - * Copyright 2010-2013 Warply Ltd. All rights reserved. | ||
| 3 | - * | ||
| 4 | - * Redistribution and use in source and binary forms, without modification, are | ||
| 5 | - * permitted provided that the following conditions are met: | ||
| 6 | - * | ||
| 7 | - * 1. Redistributions of source code must retain the above copyright notice, | ||
| 8 | - * this list of conditions and the following disclaimer. | ||
| 9 | - * | ||
| 10 | - * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
| 11 | - * this list of conditions and the following disclaimer in the documentation | ||
| 12 | - * and/or other materials provided with the distribution. | ||
| 13 | - * | ||
| 14 | - * THIS SOFTWARE IS PROVIDED BY THE WARPLY LTD ``AS IS'' AND ANY EXPRESS OR | ||
| 15 | - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
| 16 | - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | ||
| 17 | - * EVENT SHALL WARPLY LTD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 18 | - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 19 | - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | ||
| 20 | - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 21 | - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 22 | - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | ||
| 23 | - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 24 | - */ | ||
| 25 | - | ||
| 26 | -package ly.warp.sdk.io.models; | ||
| 27 | - | ||
| 28 | -import org.json.JSONArray; | ||
| 29 | -import org.json.JSONException; | ||
| 30 | -import org.json.JSONObject; | ||
| 31 | - | ||
| 32 | -import java.util.ArrayList; | ||
| 33 | - | ||
| 34 | -import ly.warp.sdk.utils.WarpUtils; | ||
| 35 | -import ly.warp.sdk.utils.constants.WarpConstants; | ||
| 36 | - | ||
| 37 | -/** | ||
| 38 | - * Created by Panagiotis Triantafyllou on 20-Jan-25. | ||
| 39 | - */ | ||
| 40 | - | ||
| 41 | -public class MarketPassDetailsModel { | ||
| 42 | - private static final String BARCODE = "barcode"; | ||
| 43 | - private static final String SUPERMARKETS = "supermarkets"; | ||
| 44 | - private static final String TOTAL_DISCOUNT = "total_available_discount"; | ||
| 45 | - private static final String NEW_OFFERS = "new_offers"; | ||
| 46 | - | ||
| 47 | - private ArrayList<Supermarkets> supermarkets = new ArrayList<Supermarkets>(); | ||
| 48 | - private String barcode = ""; | ||
| 49 | - private double totalDiscount = 0.0d; | ||
| 50 | - private int newOffers = 0; | ||
| 51 | - | ||
| 52 | - public MarketPassDetailsModel() { | ||
| 53 | - this.supermarkets = new ArrayList<Supermarkets>(); | ||
| 54 | - this.barcode = ""; | ||
| 55 | - this.totalDiscount = 0.0d; | ||
| 56 | - this.newOffers = 0; | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - /** | ||
| 60 | - * Basic constructor used to create an object from a String, representing a | ||
| 61 | - * JSON Object | ||
| 62 | - * | ||
| 63 | - * @param json The String, representing the JSON Object | ||
| 64 | - * @throws JSONException Thrown if the String cannot be converted to JSON | ||
| 65 | - */ | ||
| 66 | - public MarketPassDetailsModel(String json) throws JSONException { | ||
| 67 | - this(new JSONObject(json)); | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - /** | ||
| 71 | - * Constructor used to create an Object from a given JSON Object | ||
| 72 | - * | ||
| 73 | - * @param json JSON Object used to create the Campaign | ||
| 74 | - */ | ||
| 75 | - public MarketPassDetailsModel(JSONObject json) { | ||
| 76 | - if (json != null) { | ||
| 77 | - if (json.optJSONArray(SUPERMARKETS) != null) { | ||
| 78 | - JSONArray tempSupermarkets = json.optJSONArray(SUPERMARKETS); | ||
| 79 | - if (tempSupermarkets != null && tempSupermarkets.length() > 0) { | ||
| 80 | - for (int i = 0, lim = tempSupermarkets.length(); i < lim; ++i) { | ||
| 81 | - this.supermarkets.add(new Supermarkets(tempSupermarkets.optJSONObject(i))); | ||
| 82 | - } | ||
| 83 | - } | ||
| 84 | - } | ||
| 85 | - this.barcode = json.isNull(BARCODE) ? "" : json.optString(BARCODE); | ||
| 86 | - this.totalDiscount = json.optDouble(TOTAL_DISCOUNT); | ||
| 87 | - this.newOffers = json.optInt(NEW_OFFERS); | ||
| 88 | - } | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - /** | ||
| 92 | - * Converts the Campaign into a JSON Object | ||
| 93 | - * | ||
| 94 | - * @return The JSON Object created from this campaign | ||
| 95 | - */ | ||
| 96 | - public JSONObject toJSONObject() { | ||
| 97 | - JSONObject jObj = new JSONObject(); | ||
| 98 | - try { | ||
| 99 | - jObj.putOpt(BARCODE, this.barcode); | ||
| 100 | - jObj.putOpt(TOTAL_DISCOUNT, this.totalDiscount); | ||
| 101 | - jObj.putOpt(SUPERMARKETS, this.supermarkets); | ||
| 102 | - jObj.putOpt(NEW_OFFERS, this.newOffers); | ||
| 103 | - } catch (JSONException e) { | ||
| 104 | - if (WarpConstants.DEBUG) { | ||
| 105 | - e.printStackTrace(); | ||
| 106 | - } | ||
| 107 | - } | ||
| 108 | - return jObj; | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | - /** | ||
| 112 | - * String representation of the Campaign, as a JSON object | ||
| 113 | - * | ||
| 114 | - * @return A String representation of JSON object | ||
| 115 | - */ | ||
| 116 | - public String toString() { | ||
| 117 | - if (toJSONObject() != null) | ||
| 118 | - return toJSONObject().toString(); | ||
| 119 | - return null; | ||
| 120 | - } | ||
| 121 | - | ||
| 122 | - /** | ||
| 123 | - * String representation of the Campaign, as a human readable JSON object | ||
| 124 | - * | ||
| 125 | - * @return A human readable String representation of JSON object | ||
| 126 | - */ | ||
| 127 | - public String toHumanReadableString() { | ||
| 128 | - String humanReadableString = null; | ||
| 129 | - try { | ||
| 130 | - humanReadableString = toJSONObject().toString(2); | ||
| 131 | - } catch (JSONException e) { | ||
| 132 | - WarpUtils.warn("Failed converting Campaign JSON object to String", | ||
| 133 | - e); | ||
| 134 | - } | ||
| 135 | - return humanReadableString; | ||
| 136 | - } | ||
| 137 | - | ||
| 138 | - public class Supermarkets { | ||
| 139 | - private static final String LOGO = "logo"; | ||
| 140 | - private static final String NAME = "name"; | ||
| 141 | - private static final String UUID = "uuid"; | ||
| 142 | - | ||
| 143 | - | ||
| 144 | - private String logo = ""; | ||
| 145 | - private String name = ""; | ||
| 146 | - private String uuid = ""; | ||
| 147 | - | ||
| 148 | - public Supermarkets() { | ||
| 149 | - this.logo = ""; | ||
| 150 | - this.name = ""; | ||
| 151 | - this.uuid = ""; | ||
| 152 | - } | ||
| 153 | - | ||
| 154 | - public Supermarkets(JSONObject json) { | ||
| 155 | - if (json != null) { | ||
| 156 | - this.logo = json.isNull(LOGO) ? "" : json.optString(LOGO); | ||
| 157 | - this.name = json.isNull(NAME) ? "" : json.optString(NAME); | ||
| 158 | - this.uuid = json.isNull(UUID) ? "" : json.optString(UUID); | ||
| 159 | - } | ||
| 160 | - } | ||
| 161 | - | ||
| 162 | - public String getLogo() { | ||
| 163 | - return logo; | ||
| 164 | - } | ||
| 165 | - | ||
| 166 | - public void setLogo(String logo) { | ||
| 167 | - this.logo = logo; | ||
| 168 | - } | ||
| 169 | - | ||
| 170 | - public String getName() { | ||
| 171 | - return name; | ||
| 172 | - } | ||
| 173 | - | ||
| 174 | - public void setName(String name) { | ||
| 175 | - this.name = name; | ||
| 176 | - } | ||
| 177 | - | ||
| 178 | - public String getUuid() { | ||
| 179 | - return uuid; | ||
| 180 | - } | ||
| 181 | - | ||
| 182 | - public void setUuid(String uuid) { | ||
| 183 | - this.uuid = uuid; | ||
| 184 | - } | ||
| 185 | - } | ||
| 186 | - | ||
| 187 | - // ================================================================================ | ||
| 188 | - // Getters | ||
| 189 | - // ================================================================================ | ||
| 190 | - | ||
| 191 | - | ||
| 192 | - public ArrayList<Supermarkets> getSupermarkets() { | ||
| 193 | - return supermarkets; | ||
| 194 | - } | ||
| 195 | - | ||
| 196 | - public void setSupermarkets(ArrayList<Supermarkets> supermarkets) { | ||
| 197 | - this.supermarkets = supermarkets; | ||
| 198 | - } | ||
| 199 | - | ||
| 200 | - public String getBarcode() { | ||
| 201 | - return barcode; | ||
| 202 | - } | ||
| 203 | - | ||
| 204 | - public void setBarcode(String barcode) { | ||
| 205 | - this.barcode = barcode; | ||
| 206 | - } | ||
| 207 | - | ||
| 208 | - public double getTotalDiscount() { | ||
| 209 | - return totalDiscount; | ||
| 210 | - } | ||
| 211 | - | ||
| 212 | - public void setTotalDiscount(double totalDiscount) { | ||
| 213 | - this.totalDiscount = totalDiscount; | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - public int getNewOffers() { | ||
| 217 | - return newOffers; | ||
| 218 | - } | ||
| 219 | - | ||
| 220 | - public void setNewOffers(int newOffers) { | ||
| 221 | - this.newOffers = newOffers; | ||
| 222 | - } | ||
| 223 | -} | 
| 1 | +package ly.warp.sdk.utils; | ||
| 2 | + | ||
| 3 | +import android.security.keystore.KeyGenParameterSpec; | ||
| 4 | +import android.security.keystore.KeyProperties; | ||
| 5 | +import android.util.Base64; | ||
| 6 | +import android.util.Log; | ||
| 7 | + | ||
| 8 | +import java.security.KeyStore; | ||
| 9 | + | ||
| 10 | +import javax.crypto.Cipher; | ||
| 11 | +import javax.crypto.KeyGenerator; | ||
| 12 | +import javax.crypto.SecretKey; | ||
| 13 | +import javax.crypto.spec.GCMParameterSpec; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * Utility class for encrypting and decrypting sensitive data using Android Keystore | ||
| 17 | + */ | ||
| 18 | +public class CryptoUtils { | ||
| 19 | + | ||
| 20 | + private static final String TAG = "CryptoUtils"; | ||
| 21 | + private static final String TRANSFORMATION = "AES/GCM/NoPadding"; | ||
| 22 | + private static final String ANDROID_KEYSTORE = "AndroidKeyStore"; | ||
| 23 | + private static final String KEY_ALIAS = "tn#mpOl3v3Dy1pr@W"; | ||
| 24 | + private static final int GCM_IV_LENGTH = 12; | ||
| 25 | + private static final int GCM_TAG_LENGTH = 16; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * Encrypt a plain text string | ||
| 29 | + * | ||
| 30 | + * @param plainText The text to encrypt | ||
| 31 | + * @return Base64 encoded encrypted string, or original text if encryption fails | ||
| 32 | + */ | ||
| 33 | + public static String encrypt(String plainText) { | ||
| 34 | + if (plainText == null || plainText.isEmpty()) { | ||
| 35 | + return plainText; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + try { | ||
| 39 | + SecretKey secretKey = getOrCreateSecretKey(); | ||
| 40 | + Cipher cipher = Cipher.getInstance(TRANSFORMATION); | ||
| 41 | + cipher.init(Cipher.ENCRYPT_MODE, secretKey); | ||
| 42 | + | ||
| 43 | + byte[] iv = cipher.getIV(); | ||
| 44 | + byte[] encryptedData = cipher.doFinal(plainText.getBytes("UTF-8")); | ||
| 45 | + | ||
| 46 | + // Combine IV + encrypted data | ||
| 47 | + byte[] combined = new byte[iv.length + encryptedData.length]; | ||
| 48 | + System.arraycopy(iv, 0, combined, 0, iv.length); | ||
| 49 | + System.arraycopy(encryptedData, 0, combined, iv.length, encryptedData.length); | ||
| 50 | + | ||
| 51 | + return Base64.encodeToString(combined, Base64.DEFAULT); | ||
| 52 | + } catch (Exception e) { | ||
| 53 | + Log.e(TAG, "Encryption failed, returning original text", e); | ||
| 54 | + // Return original text if encryption fails - graceful degradation | ||
| 55 | + return plainText; | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * Decrypt an encrypted string | ||
| 61 | + * | ||
| 62 | + * @param encryptedText The Base64 encoded encrypted text | ||
| 63 | + * @return Decrypted plain text, or original text if decryption fails | ||
| 64 | + */ | ||
| 65 | + public static String decrypt(String encryptedText) { | ||
| 66 | + if (encryptedText == null || encryptedText.isEmpty()) { | ||
| 67 | + return encryptedText; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + try { | ||
| 71 | + SecretKey secretKey = getOrCreateSecretKey(); | ||
| 72 | + byte[] combined = Base64.decode(encryptedText, Base64.DEFAULT); | ||
| 73 | + | ||
| 74 | + // Extract IV and encrypted data | ||
| 75 | + byte[] iv = new byte[GCM_IV_LENGTH]; | ||
| 76 | + byte[] encryptedData = new byte[combined.length - GCM_IV_LENGTH]; | ||
| 77 | + System.arraycopy(combined, 0, iv, 0, GCM_IV_LENGTH); | ||
| 78 | + System.arraycopy(combined, GCM_IV_LENGTH, encryptedData, 0, encryptedData.length); | ||
| 79 | + | ||
| 80 | + Cipher cipher = Cipher.getInstance(TRANSFORMATION); | ||
| 81 | + GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); | ||
| 82 | + cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); | ||
| 83 | + | ||
| 84 | + byte[] decryptedData = cipher.doFinal(encryptedData); | ||
| 85 | + return new String(decryptedData, "UTF-8"); | ||
| 86 | + } catch (Exception e) { | ||
| 87 | + Log.e(TAG, "Decryption failed, returning original text", e); | ||
| 88 | + // Return original text if decryption fails - might be unencrypted legacy data | ||
| 89 | + return encryptedText; | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * Get or create the secret key in Android Keystore | ||
| 95 | + */ | ||
| 96 | + private static SecretKey getOrCreateSecretKey() throws Exception { | ||
| 97 | + KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE); | ||
| 98 | + keyStore.load(null); | ||
| 99 | + | ||
| 100 | + if (!keyStore.containsAlias(KEY_ALIAS)) { | ||
| 101 | + KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE); | ||
| 102 | + KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEY_ALIAS, | ||
| 103 | + KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) | ||
| 104 | + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) | ||
| 105 | + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) | ||
| 106 | + .setRandomizedEncryptionRequired(true) | ||
| 107 | + .build(); | ||
| 108 | + keyGenerator.init(keyGenParameterSpec); | ||
| 109 | + keyGenerator.generateKey(); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + return ((KeyStore.SecretKeyEntry) keyStore.getEntry(KEY_ALIAS, null)).getSecretKey(); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + /** | ||
| 116 | + * Check if a string appears to be encrypted (Base64 format) | ||
| 117 | + * | ||
| 118 | + * @param text The text to check | ||
| 119 | + * @return true if text appears to be encrypted | ||
| 120 | + */ | ||
| 121 | + public static boolean isEncrypted(String text) { | ||
| 122 | + if (text == null || text.isEmpty()) { | ||
| 123 | + return false; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + try { | ||
| 127 | + byte[] decoded = Base64.decode(text, Base64.DEFAULT); | ||
| 128 | + // Check if decoded length is reasonable for encrypted data (IV + data + tag) | ||
| 129 | + return decoded.length > GCM_IV_LENGTH + GCM_TAG_LENGTH; | ||
| 130 | + } catch (Exception e) { | ||
| 131 | + return false; | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | +} | 
| ... | @@ -30,7 +30,7 @@ public class WarpConstants { | ... | @@ -30,7 +30,7 @@ public class WarpConstants { | 
| 30 | /** | 30 | /** | 
| 31 | * The version of the SDK installed in the device | 31 | * The version of the SDK installed in the device | 
| 32 | */ | 32 | */ | 
| 33 | - public static final String SDK_VERSION = "4.5.5.4"; | 33 | + public static final String SDK_VERSION = "4.5.5.5"; | 
| 34 | 34 | ||
| 35 | /** | 35 | /** | 
| 36 | * The URL of the server where it should ping | 36 | * The URL of the server where it should ping | ... | ... | 
| ... | @@ -63,7 +63,6 @@ import ly.warp.sdk.io.models.Campaign; | ... | @@ -63,7 +63,6 @@ import ly.warp.sdk.io.models.Campaign; | 
| 63 | import ly.warp.sdk.io.models.Coupon; | 63 | import ly.warp.sdk.io.models.Coupon; | 
| 64 | import ly.warp.sdk.io.models.CouponList; | 64 | import ly.warp.sdk.io.models.CouponList; | 
| 65 | import ly.warp.sdk.io.models.LoyaltySDKDynatraceEventModel; | 65 | import ly.warp.sdk.io.models.LoyaltySDKDynatraceEventModel; | 
| 66 | -import ly.warp.sdk.io.models.MarketPassDetailsModel; | ||
| 67 | import ly.warp.sdk.io.models.NewCampaign; | 66 | import ly.warp.sdk.io.models.NewCampaign; | 
| 68 | import ly.warp.sdk.io.models.RedeemedSMHistoryModel; | 67 | import ly.warp.sdk.io.models.RedeemedSMHistoryModel; | 
| 69 | import ly.warp.sdk.io.request.WarplyRefreshTokenRequest; | 68 | import ly.warp.sdk.io.request.WarplyRefreshTokenRequest; | 
| ... | @@ -227,7 +226,7 @@ public class WarplyManager { | ... | @@ -227,7 +226,7 @@ public class WarplyManager { | 
| 227 | }); | 226 | }); | 
| 228 | } | 227 | } | 
| 229 | 228 | ||
| 230 | - public static void getCosmoteUser(String guid, final CallbackReceiver<JSONObject> receiver) { | 229 | + public static void getDehUser(String guid, final CallbackReceiver<JSONObject> receiver) { | 
| 231 | WarpUtils.log("************* WARPLY Cosmote User Request ********************"); | 230 | WarpUtils.log("************* WARPLY Cosmote User Request ********************"); | 
| 232 | WarpUtils.log("[WARP Trace] WARPLY Cosmote User Request is active"); | 231 | WarpUtils.log("[WARP Trace] WARPLY Cosmote User Request is active"); | 
| 233 | WarpUtils.log("**************************************************"); | 232 | WarpUtils.log("**************************************************"); | 
| ... | @@ -930,88 +929,6 @@ public class WarplyManager { | ... | @@ -930,88 +929,6 @@ public class WarplyManager { | 
| 930 | return future; | 929 | return future; | 
| 931 | } | 930 | } | 
| 932 | 931 | ||
| 933 | - private static ListenableFuture<MarketPassDetailsModel> getMarketPassDetails(ApiService service) { | ||
| 934 | - SettableFuture<MarketPassDetailsModel> future = SettableFuture.create(); | ||
| 935 | - | ||
| 936 | - String timeStamp = DateFormat.format("yyyy-MM-dd hh:mm:ss", System.currentTimeMillis()).toString(); | ||
| 937 | - String apiKey = WarpUtils.getApiKey(Warply.getWarplyContext()); | ||
| 938 | - String webId = WarpUtils.getWebId(Warply.getWarplyContext()); | ||
| 939 | - | ||
| 940 | - Map<String, Object> jsonParamsMarketPassDetails = new ArrayMap<>(); | ||
| 941 | - Map<String, Object> jsonParams = new ArrayMap<>(); | ||
| 942 | - jsonParams.put("action", "integration"); | ||
| 943 | - jsonParams.put("method", "supermarket_profile"); | ||
| 944 | - | ||
| 945 | - jsonParamsMarketPassDetails.put("consumer_data", jsonParams); | ||
| 946 | - RequestBody marketPassDetailsRequest = RequestBody.create(MediaType.get("application/json; charset=utf-8"), (new JSONObject(jsonParamsMarketPassDetails)).toString()); | ||
| 947 | - | ||
| 948 | - Call<ResponseBody> marketPassDetailsCall = service.getMarketPassDetails(WarplyProperty.getAppUuid(Warply.getWarplyContext()), marketPassDetailsRequest, timeStamp, "android:" + Warply.getWarplyContext().getPackageName(), new WarplyDeviceInfoCollector(Warply.getWarplyContext()).getUniqueDeviceId(), "mobile", webId, WarpUtils.produceSignature(apiKey + timeStamp), "Bearer " + WarplyDBHelper.getInstance(Warply.getWarplyContext()).getAuthValue("access_token")); | ||
| 949 | - | ||
| 950 | - marketPassDetailsCall.enqueue(new Callback<ResponseBody>() { | ||
| 951 | - @Override | ||
| 952 | - public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) { | ||
| 953 | - if (response.code() == 200 && response.body() != null) { | ||
| 954 | - JSONObject marketPassDetailsResponse = null; | ||
| 955 | - try { | ||
| 956 | - marketPassDetailsResponse = new JSONObject(response.body().string()); | ||
| 957 | - } catch (Exception e) { | ||
| 958 | - e.printStackTrace(); | ||
| 959 | - } | ||
| 960 | - | ||
| 961 | - if (marketPassDetailsResponse != null && marketPassDetailsResponse.has("status") && marketPassDetailsResponse.optString("status", "2").equals("1")) { | ||
| 962 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 963 | - dynatraceEvent.setEventName("custom_success_market_pass_details"); | ||
| 964 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 965 | - | ||
| 966 | - final ExecutorService executorMarketPassDetails = Executors.newFixedThreadPool(1); | ||
| 967 | - final JSONObject finalMarketPassDetailsResponse = marketPassDetailsResponse; | ||
| 968 | - executorMarketPassDetails.submit(() -> { | ||
| 969 | - JSONObject marketPassDetailsBody = null; | ||
| 970 | - try { | ||
| 971 | - marketPassDetailsBody = finalMarketPassDetailsResponse.optJSONObject("result"); | ||
| 972 | - } catch (Exception e) { | ||
| 973 | - e.printStackTrace(); | ||
| 974 | - } | ||
| 975 | - | ||
| 976 | - if (marketPassDetailsBody != null) { | ||
| 977 | - MarketPassDetailsModel marketPassDetailsModel = new MarketPassDetailsModel(marketPassDetailsBody); | ||
| 978 | - executorMarketPassDetails.shutdownNow(); | ||
| 979 | - future.set(marketPassDetailsModel); | ||
| 980 | - } else { | ||
| 981 | - LoyaltySDKDynatraceEventModel dynatraceEvent2 = new LoyaltySDKDynatraceEventModel(); | ||
| 982 | - dynatraceEvent2.setEventName("custom_error_market_pass_details"); | ||
| 983 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent2)); | ||
| 984 | - future.set(new MarketPassDetailsModel()); | ||
| 985 | - } | ||
| 986 | - }); | ||
| 987 | - } else { | ||
| 988 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 989 | - dynatraceEvent.setEventName("custom_error_market_pass_details"); | ||
| 990 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 991 | - future.set(new MarketPassDetailsModel()); | ||
| 992 | - } | ||
| 993 | - } else { | ||
| 994 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 995 | - dynatraceEvent.setEventName("custom_error_market_pass_details"); | ||
| 996 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 997 | -// future.set(new JSONObject()); | ||
| 998 | - future.setException(new Throwable()); | ||
| 999 | - } | ||
| 1000 | - } | ||
| 1001 | - | ||
| 1002 | - @Override | ||
| 1003 | - public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) { | ||
| 1004 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 1005 | - dynatraceEvent.setEventName("custom_error_market_pass_details"); | ||
| 1006 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 1007 | -// future.set(new JSONObject()); | ||
| 1008 | - future.setException(new Throwable()); | ||
| 1009 | - } | ||
| 1010 | - }); | ||
| 1011 | - | ||
| 1012 | - return future; | ||
| 1013 | - } | ||
| 1014 | - | ||
| 1015 | private static ListenableFuture<RedeemedSMHistoryModel> getSMCouponsUniversalRetro(ApiService service, int tries, SettableFuture<RedeemedSMHistoryModel> future) { | 932 | private static ListenableFuture<RedeemedSMHistoryModel> getSMCouponsUniversalRetro(ApiService service, int tries, SettableFuture<RedeemedSMHistoryModel> future) { | 
| 1016 | String timeStamp = DateFormat.format("yyyy-MM-dd hh:mm:ss", System.currentTimeMillis()).toString(); | 933 | String timeStamp = DateFormat.format("yyyy-MM-dd hh:mm:ss", System.currentTimeMillis()).toString(); | 
| 1017 | String apiKey = WarpUtils.getApiKey(Warply.getWarplyContext()); | 934 | String apiKey = WarpUtils.getApiKey(Warply.getWarplyContext()); | 
| ... | @@ -1301,220 +1218,6 @@ public class WarplyManager { | ... | @@ -1301,220 +1218,6 @@ public class WarplyManager { | 
| 1301 | }, null); | 1218 | }, null); | 
| 1302 | } | 1219 | } | 
| 1303 | 1220 | ||
| 1304 | - public static void getMarketPassDetails(final CallbackReceiver<MarketPassDetailsModel> receiver) { | ||
| 1305 | - WarpUtils.log("************* WARPLY Market Pass Details Request ********************"); | ||
| 1306 | - WarpUtils.log("[WARP Trace] WARPLY Market Pass Details is active"); | ||
| 1307 | - WarpUtils.log("**************************************************"); | ||
| 1308 | - | ||
| 1309 | - ApiService service = ApiClient.getRetrofitInstance().create(ApiService.class); | ||
| 1310 | - ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1)); | ||
| 1311 | - | ||
| 1312 | - ListenableFuture<MarketPassDetailsModel> futureMarketPassDetails = getMarketPassDetails(service); | ||
| 1313 | - | ||
| 1314 | - ListenableFuture<List<Object>> allResultsFuture = Futures.allAsList(futureMarketPassDetails); | ||
| 1315 | - ListenableFuture<MarketPassDetailsModel> mergedResultFuture = Futures.transformAsync(allResultsFuture, results -> { | ||
| 1316 | - MarketPassDetailsModel resultMarketPassDetails = (MarketPassDetailsModel) results.get(0); | ||
| 1317 | - return executorService.submit(() -> resultMarketPassDetails); | ||
| 1318 | - }, executorService); | ||
| 1319 | - | ||
| 1320 | - Futures.addCallback(mergedResultFuture, new FutureCallback<MarketPassDetailsModel>() { | ||
| 1321 | - @Override | ||
| 1322 | - public void onSuccess(MarketPassDetailsModel mergedResult) { | ||
| 1323 | - executorService.shutdownNow(); | ||
| 1324 | - new Handler(Looper.getMainLooper()).post(() -> receiver.onSuccess(mergedResult)); | ||
| 1325 | - } | ||
| 1326 | - | ||
| 1327 | - @Override | ||
| 1328 | - public void onFailure(Throwable throwable) { | ||
| 1329 | - executorService.shutdownNow(); | ||
| 1330 | - new Handler(Looper.getMainLooper()).post(() -> receiver.onFailure(2)); | ||
| 1331 | - } | ||
| 1332 | - }, executorService); | ||
| 1333 | - } | ||
| 1334 | - | ||
| 1335 | - private static /*void*/ ListenableFuture<ArrayList<Campaign>> getSupermarketCampaignRetro(ApiService service/*, final CallbackReceiver<ArrayList<Campaign>> receiver*/) { | ||
| 1336 | - SettableFuture<ArrayList<Campaign>> future = SettableFuture.create(); | ||
| 1337 | - | ||
| 1338 | - String timeStamp = DateFormat.format("yyyy-MM-dd hh:mm:ss", System.currentTimeMillis()).toString(); | ||
| 1339 | - String apiKey = WarpUtils.getApiKey(Warply.getWarplyContext()); | ||
| 1340 | - String webId = WarpUtils.getWebId(Warply.getWarplyContext()); | ||
| 1341 | - | ||
| 1342 | - Map<String, Object> jsonParamsCampaigns = new ArrayMap<>(); | ||
| 1343 | - Map<String, Object> jsonParams = new ArrayMap<>(); | ||
| 1344 | - JSONObject jFilters = new JSONObject(); | ||
| 1345 | - JSONObject jExtra = new JSONObject(); | ||
| 1346 | - try { | ||
| 1347 | - jFilters.putOpt("communication_category", "more_for_you"); | ||
| 1348 | - jExtra.putOpt("filter", "supermarket"); | ||
| 1349 | - jExtra.putOpt("version", "magenta"); | ||
| 1350 | - jFilters.putOpt("extra_fields", jExtra); | ||
| 1351 | - } catch (JSONException e) { | ||
| 1352 | - throw new RuntimeException(e); | ||
| 1353 | - } | ||
| 1354 | - jsonParams.put("action", "retrieve"); | ||
| 1355 | - jsonParams.put("filters", jFilters); | ||
| 1356 | - jsonParams.put("language", WarpUtils.getApplicationLocale(Warply.getWarplyContext())); | ||
| 1357 | - | ||
| 1358 | - jsonParamsCampaigns.put("campaigns", jsonParams); | ||
| 1359 | - RequestBody campaignsRequest = RequestBody.create(MediaType.get("application/json; charset=utf-8"), (new JSONObject(jsonParamsCampaigns)).toString()); | ||
| 1360 | - | ||
| 1361 | - Call<ResponseBody> campaignsCall = service.getCampaigns(WarplyProperty.getAppUuid(Warply.getWarplyContext()), campaignsRequest, timeStamp, "android:" + Warply.getWarplyContext().getPackageName(), new WarplyDeviceInfoCollector(Warply.getWarplyContext()).getUniqueDeviceId(), "mobile", webId, WarpUtils.produceSignature(apiKey + timeStamp)); | ||
| 1362 | - | ||
| 1363 | - campaignsCall.enqueue(new Callback<ResponseBody>() { | ||
| 1364 | - @Override | ||
| 1365 | - public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) { | ||
| 1366 | - if (response.code() == 200 && response.body() != null) { | ||
| 1367 | - JSONObject jobjCampaignsResponse = null; | ||
| 1368 | - try { | ||
| 1369 | - jobjCampaignsResponse = new JSONObject(response.body().string()); | ||
| 1370 | - } catch (Exception e) { | ||
| 1371 | - e.printStackTrace(); | ||
| 1372 | - } | ||
| 1373 | - | ||
| 1374 | - if (jobjCampaignsResponse != null && jobjCampaignsResponse.has("status") && jobjCampaignsResponse.optString("status", "2").equals("1")) { | ||
| 1375 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 1376 | - dynatraceEvent.setEventName("custom_success_supermarket_campaign_loyalty"); | ||
| 1377 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 1378 | - | ||
| 1379 | - JSONArray jCampaignsBody = null; | ||
| 1380 | - try { | ||
| 1381 | - jCampaignsBody = jobjCampaignsResponse.optJSONObject("context").optJSONObject("MAPP_CAMPAIGNING").optJSONArray("campaigns"); | ||
| 1382 | - } catch (Exception e) { | ||
| 1383 | - e.printStackTrace(); | ||
| 1384 | - } | ||
| 1385 | - | ||
| 1386 | - if (jCampaignsBody != null) { | ||
| 1387 | - ArrayList<NewCampaign> tempCampaigns = new ArrayList<>(); | ||
| 1388 | - ArrayList<Campaign> mCampaignsList = new ArrayList<>(); | ||
| 1389 | - | ||
| 1390 | - final ExecutorService executorCampaigns = Executors.newFixedThreadPool(1); | ||
| 1391 | - JSONArray finalCampaignsJBody = jCampaignsBody; | ||
| 1392 | - executorCampaigns.submit(() -> { | ||
| 1393 | - for (int i = 0; i < finalCampaignsJBody.length(); ++i) { | ||
| 1394 | - tempCampaigns.add(new NewCampaign(finalCampaignsJBody.optJSONObject(i))); | ||
| 1395 | - } | ||
| 1396 | - for (NewCampaign newCamp : tempCampaigns) { | ||
| 1397 | - Campaign camp = new Campaign(); | ||
| 1398 | - camp.setIndexUrl(newCamp.getIndexUrl()); | ||
| 1399 | - camp.setLogoUrl(newCamp.getLogoUrl()); | ||
| 1400 | - camp.setMessage(newCamp.getMessage()); | ||
| 1401 | - camp.setOfferCategory(newCamp.getCommunicationCategory()); | ||
| 1402 | - camp.setSessionUUID(newCamp.getCommunicationUUID()); | ||
| 1403 | - camp.setTitle(newCamp.getTitle()); | ||
| 1404 | - camp.setSubtitle(newCamp.getSubtitle()); | ||
| 1405 | - camp.setSorting(newCamp.getSorting()); | ||
| 1406 | - camp.setNew(newCamp.getIsNew()); | ||
| 1407 | - camp.setType(newCamp.getCampaignType()); | ||
| 1408 | - camp.setEndDate(newCamp.getEndDate()); | ||
| 1409 | - camp.setStartDate(newCamp.getStartDate()); | ||
| 1410 | - camp.setShowExpiration(newCamp.isShowExpiration()); | ||
| 1411 | - camp.setCouponImg(newCamp.getCouponImg()); | ||
| 1412 | - camp.setFilter(newCamp.getFilter()); | ||
| 1413 | - try { | ||
| 1414 | - camp.setExtraFields(newCamp.getExtraFields().toString()); | ||
| 1415 | - if (!TextUtils.isEmpty(newCamp.getExtraFields().toString())) { | ||
| 1416 | - JSONObject extraFieldsResp = WarpJSONParser.getJSONFromString(newCamp.getExtraFields().toString()); | ||
| 1417 | - if (extraFieldsResp != null) { | ||
| 1418 | - if (extraFieldsResp.has("Banner_title")) { | ||
| 1419 | - camp.setBannerTitle(extraFieldsResp.optString("Banner_title", "")); | ||
| 1420 | - } | ||
| 1421 | - if (extraFieldsResp.has("Banner_img")) { | ||
| 1422 | - camp.setBannerImage(extraFieldsResp.optString("Banner_img", "")); | ||
| 1423 | - } | ||
| 1424 | - if (extraFieldsResp.has("category_id")) { | ||
| 1425 | - camp.setCategoryId(extraFieldsResp.optString("category_id", "")); | ||
| 1426 | - } | ||
| 1427 | - } | ||
| 1428 | - } else { | ||
| 1429 | - camp.setBannerImage(""); | ||
| 1430 | - camp.setBannerTitle(""); | ||
| 1431 | - camp.setCategoryId(""); | ||
| 1432 | - } | ||
| 1433 | - } catch (NullPointerException e) { | ||
| 1434 | - camp.setExtraFields(""); | ||
| 1435 | - camp.setBannerImage(""); | ||
| 1436 | - camp.setBannerTitle(""); | ||
| 1437 | - camp.setCategoryId(""); | ||
| 1438 | - e.printStackTrace(); | ||
| 1439 | - } | ||
| 1440 | - | ||
| 1441 | - try { | ||
| 1442 | - camp.setCampaignTypeSettings(newCamp.getSettings().toString()); | ||
| 1443 | - } catch (NullPointerException e) { | ||
| 1444 | - camp.setCampaignTypeSettings(""); | ||
| 1445 | - e.printStackTrace(); | ||
| 1446 | - } | ||
| 1447 | - mCampaignsList.add(camp); | ||
| 1448 | - } | ||
| 1449 | - | ||
| 1450 | - executorCampaigns.shutdownNow(); | ||
| 1451 | -// receiver.onSuccess(mCampaignsList); | ||
| 1452 | - future.set(mCampaignsList); | ||
| 1453 | - }); | ||
| 1454 | - } | ||
| 1455 | - } else { | ||
| 1456 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 1457 | - dynatraceEvent.setEventName("custom_error_supermarket_campaign_loyalty"); | ||
| 1458 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 1459 | -// receiver.onFailure(2); | ||
| 1460 | - future.set(new ArrayList<Campaign>()); | ||
| 1461 | - } | ||
| 1462 | - } else { | ||
| 1463 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 1464 | - dynatraceEvent.setEventName("custom_error_supermarket_campaign_loyalty"); | ||
| 1465 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 1466 | -// receiver.onFailure(response.code()); | ||
| 1467 | -// future.set(new ArrayList<Campaign>()); | ||
| 1468 | - future.setException(new Throwable()); | ||
| 1469 | - } | ||
| 1470 | - } | ||
| 1471 | - | ||
| 1472 | - @Override | ||
| 1473 | - public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) { | ||
| 1474 | - LoyaltySDKDynatraceEventModel dynatraceEvent = new LoyaltySDKDynatraceEventModel(); | ||
| 1475 | - dynatraceEvent.setEventName("custom_error_supermarket_campaign_loyalty"); | ||
| 1476 | - EventBus.getDefault().post(new WarplyEventBusManager(dynatraceEvent)); | ||
| 1477 | -// receiver.onFailure(2); | ||
| 1478 | -// future.set(new ArrayList<Campaign>()); | ||
| 1479 | - future.setException(new Throwable()); | ||
| 1480 | - } | ||
| 1481 | - }); | ||
| 1482 | - | ||
| 1483 | - return future; | ||
| 1484 | - } | ||
| 1485 | - | ||
| 1486 | - public static void getSupermarketCampaign(final CallbackReceiver<ArrayList<Campaign>> receiver) { | ||
| 1487 | - WarpUtils.log("************* WARPLY Get Supermarket Campaigns Request ********************"); | ||
| 1488 | - WarpUtils.log("[WARP Trace] WARPLY Get Supermarket Campaigns Request is active"); | ||
| 1489 | - WarpUtils.log("**************************************************"); | ||
| 1490 | - | ||
| 1491 | - ApiService service = ApiClient.getRetrofitInstance().create(ApiService.class); | ||
| 1492 | - ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1)); | ||
| 1493 | - | ||
| 1494 | - ListenableFuture<ArrayList<Campaign>> futureCampaigns = getSupermarketCampaignRetro(service); | ||
| 1495 | - | ||
| 1496 | - ListenableFuture<List<Object>> allResultsFuture = Futures.allAsList(futureCampaigns); | ||
| 1497 | - ListenableFuture<ArrayList<Campaign>> mergedResultFuture = Futures.transformAsync(allResultsFuture, results -> { | ||
| 1498 | - ArrayList<Campaign> resultCampaigns = (ArrayList<Campaign>) results.get(0); | ||
| 1499 | - return executorService.submit(() -> resultCampaigns); | ||
| 1500 | - }, executorService); | ||
| 1501 | - | ||
| 1502 | - Futures.addCallback(mergedResultFuture, new FutureCallback<ArrayList<Campaign>>() { | ||
| 1503 | - @Override | ||
| 1504 | - public void onSuccess(ArrayList<Campaign> mergedResult) { | ||
| 1505 | - WarplyManagerHelper.setSupermarketCampaigns(mergedResult); | ||
| 1506 | - executorService.shutdownNow(); | ||
| 1507 | - new Handler(Looper.getMainLooper()).post(() -> receiver.onSuccess(mergedResult)); | ||
| 1508 | - } | ||
| 1509 | - | ||
| 1510 | - @Override | ||
| 1511 | - public void onFailure(Throwable throwable) { | ||
| 1512 | - executorService.shutdownNow(); | ||
| 1513 | - new Handler(Looper.getMainLooper()).post(() -> receiver.onFailure(2)); | ||
| 1514 | - } | ||
| 1515 | - }, executorService); | ||
| 1516 | - } | ||
| 1517 | - | ||
| 1518 | public static void getRedeemedSMHistory(final CallbackReceiver<RedeemedSMHistoryModel> receiver) { | 1221 | public static void getRedeemedSMHistory(final CallbackReceiver<RedeemedSMHistoryModel> receiver) { | 
| 1519 | WarpUtils.log("************* WARPLY User Redeemed History Request ********************"); | 1222 | WarpUtils.log("************* WARPLY User Redeemed History Request ********************"); | 
| 1520 | WarpUtils.log("[WARP Trace] WARPLY User Redeemed History Request is active"); | 1223 | WarpUtils.log("[WARP Trace] WARPLY User Redeemed History Request is active"); | ... | ... | 
| ... | @@ -568,8 +568,8 @@ public class WarpView extends WebView implements DefaultLifecycleObserver { | ... | @@ -568,8 +568,8 @@ public class WarpView extends WebView implements DefaultLifecycleObserver { | 
| 568 | public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { | 568 | public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { | 
| 569 | if (WarpActivity != null && !WarpActivity.isFinishing()) { | 569 | if (WarpActivity != null && !WarpActivity.isFinishing()) { | 
| 570 | AlertDialog.Builder builder = new AlertDialog.Builder(WarpActivity); | 570 | AlertDialog.Builder builder = new AlertDialog.Builder(WarpActivity); | 
| 571 | - builder.setTitle(getContext().getString(R.string.lbl_cosmote_webview_permission_title)); | 571 | + builder.setTitle(getContext().getString(R.string.webview_permission_title)); | 
| 572 | - builder.setMessage(getContext().getString(R.string.lbl_cosmote_webview_permission_message)) | 572 | + builder.setMessage(getContext().getString(R.string.webview_permission_message)) | 
| 573 | .setCancelable(false) | 573 | .setCancelable(false) | 
| 574 | .setPositiveButton(getContext().getString(R.string.lbl_take_photo_accept), (dialog, id) -> checkForPermissions(origin, callback)) | 574 | .setPositiveButton(getContext().getString(R.string.lbl_take_photo_accept), (dialog, id) -> checkForPermissions(origin, callback)) | 
| 575 | .setNegativeButton(getContext().getString(R.string.lbl_take_photo_decline), (dialog, id) -> callback.invoke(origin, false, false)); | 575 | .setNegativeButton(getContext().getString(R.string.lbl_take_photo_decline), (dialog, id) -> callback.invoke(origin, false, false)); | ... | ... | 
| 1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> | 
| 2 | - | 2 | +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" | 
| 3 | -<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 4 | xmlns:app="http://schemas.android.com/apk/res-auto" | 3 | xmlns:app="http://schemas.android.com/apk/res-auto" | 
| 5 | xmlns:tools="http://schemas.android.com/tools" | 4 | xmlns:tools="http://schemas.android.com/tools" | 
| 6 | - android:id="@+id/sw_refresh" | ||
| 7 | android:layout_width="match_parent" | 5 | android:layout_width="match_parent" | 
| 8 | android:layout_height="match_parent" | 6 | android:layout_height="match_parent" | 
| 9 | android:background="@color/cos_skyblue2"> | 7 | android:background="@color/cos_skyblue2"> | 
| 10 | 8 | ||
| 11 | - <ScrollView | 9 | + <RelativeLayout | 
| 12 | android:layout_width="match_parent" | 10 | android:layout_width="match_parent" | 
| 13 | - android:layout_height="match_parent" | 11 | + android:layout_height="wrap_content"> | 
| 14 | - android:background="@color/cos_skyblue2"> | ||
| 15 | 12 | ||
| 16 | - <RelativeLayout | 13 | + <androidx.constraintlayout.widget.ConstraintLayout | 
| 14 | + android:id="@+id/rl_header" | ||
| 17 | android:layout_width="match_parent" | 15 | android:layout_width="match_parent" | 
| 18 | - android:layout_height="wrap_content"> | 16 | + android:layout_height="wrap_content" | 
| 19 | - | 17 | + android:background="@android:color/white" | 
| 20 | - <androidx.constraintlayout.widget.ConstraintLayout | 18 | + android:paddingHorizontal="16dp" | 
| 21 | - android:id="@+id/rl_header" | 19 | + android:paddingTop="8dp"> | 
| 22 | - android:layout_width="match_parent" | ||
| 23 | - android:layout_height="wrap_content" | ||
| 24 | - android:background="@android:color/white" | ||
| 25 | - android:paddingHorizontal="16dp" | ||
| 26 | - android:paddingTop="8dp"> | ||
| 27 | - | ||
| 28 | - <ImageView | ||
| 29 | - android:id="@+id/user_img" | ||
| 30 | - android:layout_width="60dp" | ||
| 31 | - android:layout_height="60dp" | ||
| 32 | - android:src="@drawable/profile_photo" | ||
| 33 | - app:layout_constraintStart_toStartOf="parent" | ||
| 34 | - app:layout_constraintTop_toTopOf="parent" /> | ||
| 35 | - | ||
| 36 | - <RelativeLayout | ||
| 37 | - android:id="@+id/rl_user_info" | ||
| 38 | - android:layout_width="0dp" | ||
| 39 | - android:layout_height="match_parent" | ||
| 40 | - android:orientation="vertical" | ||
| 41 | - android:paddingLeft="10dp" | ||
| 42 | - app:layout_constraintEnd_toStartOf="@+id/iv_settings" | ||
| 43 | - app:layout_constraintStart_toEndOf="@+id/user_img" | ||
| 44 | - app:layout_constraintTop_toTopOf="@+id/user_img"> | ||
| 45 | - | ||
| 46 | - <TextView | ||
| 47 | - android:id="@+id/welcome_user_txt" | ||
| 48 | - android:layout_width="match_parent" | ||
| 49 | - android:layout_height="wrap_content" | ||
| 50 | - android:layout_marginBottom="8dp" | ||
| 51 | - android:maxLines="1" | ||
| 52 | - android:scrollHorizontally="true" | ||
| 53 | - android:textColor="#415564" | ||
| 54 | - tools:text="@string/welcome_user" /> | ||
| 55 | - | ||
| 56 | - <ImageView | ||
| 57 | - android:id="@+id/cosmote_one" | ||
| 58 | - android:layout_width="100dp" | ||
| 59 | - android:layout_height="30dp" | ||
| 60 | - android:layout_below="@+id/welcome_user_txt" | ||
| 61 | - android:layout_marginTop="0dp" | ||
| 62 | - android:src="@drawable/cosmote_one" /> | ||
| 63 | - | ||
| 64 | - <LinearLayout | ||
| 65 | - android:layout_width="wrap_content" | ||
| 66 | - android:layout_height="wrap_content" | ||
| 67 | - android:layout_below="@+id/cosmote_one"> | ||
| 68 | 20 | ||
| 69 | - <include | 21 | + <ImageView | 
| 70 | - android:id="@+id/info_button" | 22 | + android:id="@+id/user_img" | 
| 71 | - layout="@layout/button_with_image" | 23 | + android:layout_width="60dp" | 
| 72 | - android:layout_width="wrap_content" | 24 | + android:layout_height="60dp" | 
| 73 | - android:layout_height="wrap_content" /> | 25 | + android:src="@drawable/profile_photo" | 
| 26 | + app:layout_constraintStart_toStartOf="parent" | ||
| 27 | + app:layout_constraintTop_toTopOf="parent" /> | ||
| 74 | 28 | ||
| 75 | - <include | 29 | + <RelativeLayout | 
| 76 | - android:id="@+id/info_button2" | 30 | + android:id="@+id/rl_user_info" | 
| 77 | - layout="@layout/button_with_image" | 31 | + android:layout_width="0dp" | 
| 78 | - android:layout_width="wrap_content" | 32 | + android:layout_height="match_parent" | 
| 79 | - android:layout_height="wrap_content" | 33 | + android:orientation="vertical" | 
| 80 | - android:layout_marginLeft="5dp" /> | 34 | + android:paddingLeft="10dp" | 
| 35 | + app:layout_constraintEnd_toStartOf="@+id/iv_settings" | ||
| 36 | + app:layout_constraintStart_toEndOf="@+id/user_img" | ||
| 37 | + app:layout_constraintTop_toTopOf="@+id/user_img"> | ||
| 81 | 38 | ||
| 82 | - <include | 39 | + <TextView | 
| 83 | - android:id="@+id/info_button3" | 40 | + android:id="@+id/welcome_user_txt" | 
| 84 | - layout="@layout/button_with_image" | 41 | + android:layout_width="match_parent" | 
| 85 | - android:layout_width="wrap_content" | 42 | + android:layout_height="wrap_content" | 
| 86 | - android:layout_height="wrap_content" | 43 | + android:layout_marginBottom="8dp" | 
| 87 | - android:layout_marginLeft="5dp" /> | 44 | + android:maxLines="1" | 
| 88 | - </LinearLayout> | 45 | + android:scrollHorizontally="true" | 
| 89 | - </RelativeLayout> | 46 | + android:textColor="#415564" | 
| 47 | + tools:text="@string/welcome_user" /> | ||
| 90 | 48 | ||
| 91 | <ImageView | 49 | <ImageView | 
| 92 | - android:id="@+id/iv_settings" | 50 | + android:id="@+id/cosmote_one" | 
| 93 | - android:layout_width="25dp" | 51 | + android:layout_width="100dp" | 
| 94 | - android:layout_height="25dp" | 52 | + android:layout_height="30dp" | 
| 95 | - android:src="@drawable/filters_icon" | 53 | + android:layout_below="@+id/welcome_user_txt" | 
| 96 | - app:layout_constraintEnd_toEndOf="parent" | 54 | + android:layout_marginTop="0dp" | 
| 97 | - app:layout_constraintTop_toTopOf="@+id/user_img" /> | 55 | + android:src="@drawable/cosmote_one" /> | 
| 98 | - </androidx.constraintlayout.widget.ConstraintLayout> | ||
| 99 | 56 | ||
| 100 | - <RelativeLayout | 57 | + <LinearLayout | 
| 101 | - android:id="@+id/rl_auth" | 58 | + android:layout_width="wrap_content" | 
| 102 | - android:layout_width="wrap_content" | 59 | + android:layout_height="wrap_content" | 
| 103 | - android:layout_height="wrap_content" | 60 | + android:layout_below="@+id/cosmote_one"> | 
| 104 | - android:layout_below="@+id/rl_header" | ||
| 105 | - android:background="@color/cos_skyblue2" | ||
| 106 | - android:paddingVertical="16dp"> | ||
| 107 | 61 | ||
| 108 | - <RelativeLayout | 62 | + <include | 
| 109 | - android:id="@+id/rl_auth_view" | 63 | + android:id="@+id/info_button" | 
| 110 | - android:layout_width="match_parent" | 64 | + layout="@layout/button_with_image" | 
| 111 | - android:layout_height="70dp" | 65 | + android:layout_width="wrap_content" | 
| 112 | - android:layout_marginHorizontal="8dp" | 66 | + android:layout_height="wrap_content" /> | 
| 113 | - android:layout_marginTop="24dp" | ||
| 114 | - android:layout_marginBottom="16dp" | ||
| 115 | - android:background="@drawable/shape_cos_white"> | ||
| 116 | 67 | ||
| 117 | - <EditText | 68 | + <include | 
| 118 | - android:id="@+id/et_login" | 69 | + android:id="@+id/info_button2" | 
| 119 | - android:layout_width="180dp" | 70 | + layout="@layout/button_with_image" | 
| 71 | + android:layout_width="wrap_content" | ||
| 120 | android:layout_height="wrap_content" | 72 | android:layout_height="wrap_content" | 
| 121 | - android:layout_alignParentStart="true" | 73 | + android:layout_marginLeft="5dp" /> | 
| 122 | - android:layout_centerVertical="true" | ||
| 123 | - android:layout_marginStart="16dp" | ||
| 124 | - android:hint="@string/cos_hint" | ||
| 125 | - android:inputType="number" | ||
| 126 | - android:textColor="@color/blue_dark" | ||
| 127 | - android:textSize="20sp" | ||
| 128 | - android:textStyle="bold" | ||
| 129 | - android:visibility="gone" | ||
| 130 | - tools:visibility="visible" /> | ||
| 131 | 74 | ||
| 132 | - <TextView | 75 | + <include | 
| 133 | - android:id="@+id/tv_login" | 76 | + android:id="@+id/info_button3" | 
| 77 | + layout="@layout/button_with_image" | ||
| 134 | android:layout_width="wrap_content" | 78 | android:layout_width="wrap_content" | 
| 135 | android:layout_height="wrap_content" | 79 | android:layout_height="wrap_content" | 
| 136 | - android:layout_alignParentStart="true" | 80 | + android:layout_marginLeft="5dp" /> | 
| 137 | - android:layout_centerVertical="true" | 81 | + </LinearLayout> | 
| 138 | - android:layout_marginStart="16dp" | 82 | + </RelativeLayout> | 
| 139 | - android:textColor="@color/blue_dark" | ||
| 140 | - android:textSize="20sp" | ||
| 141 | - android:visibility="gone" /> | ||
| 142 | - | ||
| 143 | - <LinearLayout | ||
| 144 | - android:id="@+id/ll_auth_login" | ||
| 145 | - android:layout_width="140dp" | ||
| 146 | - android:layout_height="45dp" | ||
| 147 | - android:layout_alignParentEnd="true" | ||
| 148 | - android:layout_centerVertical="true" | ||
| 149 | - android:layout_marginEnd="16dp" | ||
| 150 | - android:background="@drawable/selector_button_green" | ||
| 151 | - android:gravity="center" | ||
| 152 | - android:orientation="horizontal" | ||
| 153 | - android:visibility="gone"> | ||
| 154 | - | ||
| 155 | - <TextView | ||
| 156 | - android:id="@+id/button_login" | ||
| 157 | - android:layout_width="wrap_content" | ||
| 158 | - android:layout_height="wrap_content" | ||
| 159 | - android:gravity="center" | ||
| 160 | - android:includeFontPadding="false" | ||
| 161 | - android:text="@string/cos_login_text" | ||
| 162 | - android:textColor="@color/white" | ||
| 163 | - android:textSize="16sp" /> | ||
| 164 | - </LinearLayout> | ||
| 165 | - | ||
| 166 | - <LinearLayout | ||
| 167 | - android:id="@+id/ll_auth_logout" | ||
| 168 | - android:layout_width="140dp" | ||
| 169 | - android:layout_height="45dp" | ||
| 170 | - android:layout_alignParentEnd="true" | ||
| 171 | - android:layout_centerVertical="true" | ||
| 172 | - android:layout_marginEnd="16dp" | ||
| 173 | - android:background="@drawable/selector_button_green" | ||
| 174 | - android:gravity="center" | ||
| 175 | - android:orientation="horizontal" | ||
| 176 | - android:visibility="gone"> | ||
| 177 | - | ||
| 178 | - <TextView | ||
| 179 | - android:id="@+id/button_logout" | ||
| 180 | - android:layout_width="wrap_content" | ||
| 181 | - android:layout_height="wrap_content" | ||
| 182 | - android:gravity="center" | ||
| 183 | - android:includeFontPadding="false" | ||
| 184 | - android:text="@string/cos_logout_text" | ||
| 185 | - android:textColor="@color/white" | ||
| 186 | - android:textSize="16sp" /> | ||
| 187 | - </LinearLayout> | ||
| 188 | - </RelativeLayout> | ||
| 189 | 83 | ||
| 190 | - <RelativeLayout | 84 | + <ImageView | 
| 191 | - android:id="@+id/pb_loading" | 85 | + android:id="@+id/iv_settings" | 
| 192 | - android:layout_width="match_parent" | 86 | + android:layout_width="25dp" | 
| 193 | - android:layout_height="match_parent" | 87 | + android:layout_height="25dp" | 
| 194 | - android:layout_centerInParent="true" | 88 | + android:src="@drawable/filters_icon" | 
| 195 | - android:background="@android:color/transparent" | 89 | + app:layout_constraintEnd_toEndOf="parent" | 
| 196 | - android:translationZ="100dp" | 90 | + app:layout_constraintTop_toTopOf="@+id/user_img" /> | 
| 197 | - android:visibility="gone" | 91 | + </androidx.constraintlayout.widget.ConstraintLayout> | 
| 198 | - tools:visibility="visible"> | ||
| 199 | 92 | ||
| 200 | - <ProgressBar | 93 | + <RelativeLayout | 
| 201 | - android:layout_width="48dp" | 94 | + android:id="@+id/rl_auth" | 
| 202 | - android:layout_height="48dp" | 95 | + android:layout_width="wrap_content" | 
| 203 | - android:layout_centerInParent="true" | 96 | + android:layout_height="wrap_content" | 
| 204 | - android:indeterminate="true" | 97 | + android:layout_below="@+id/rl_header" | 
| 205 | - android:indeterminateTint="@color/cos_green5" | 98 | + android:background="@color/cos_skyblue2" | 
| 206 | - android:indeterminateTintMode="src_atop" /> | 99 | + android:paddingVertical="16dp"> | 
| 207 | - </RelativeLayout> | ||
| 208 | - </RelativeLayout> | ||
| 209 | 100 | ||
| 210 | <RelativeLayout | 101 | <RelativeLayout | 
| 211 | - android:id="@+id/rl_sm_view" | 102 | + android:id="@+id/rl_auth_view" | 
| 212 | android:layout_width="match_parent" | 103 | android:layout_width="match_parent" | 
| 213 | android:layout_height="70dp" | 104 | android:layout_height="70dp" | 
| 214 | - android:layout_below="@+id/rl_auth" | ||
| 215 | android:layout_marginHorizontal="8dp" | 105 | android:layout_marginHorizontal="8dp" | 
| 216 | android:layout_marginTop="24dp" | 106 | android:layout_marginTop="24dp" | 
| 217 | android:layout_marginBottom="16dp" | 107 | android:layout_marginBottom="16dp" | 
| 218 | android:background="@drawable/shape_cos_white"> | 108 | android:background="@drawable/shape_cos_white"> | 
| 219 | 109 | ||
| 110 | + <EditText | ||
| 111 | + android:id="@+id/et_login" | ||
| 112 | + android:layout_width="180dp" | ||
| 113 | + android:layout_height="wrap_content" | ||
| 114 | + android:layout_alignParentStart="true" | ||
| 115 | + android:layout_centerVertical="true" | ||
| 116 | + android:layout_marginStart="16dp" | ||
| 117 | + android:hint="@string/cos_hint" | ||
| 118 | + android:inputType="number" | ||
| 119 | + android:textColor="@color/blue_dark" | ||
| 120 | + android:textSize="20sp" | ||
| 121 | + android:textStyle="bold" | ||
| 122 | + android:visibility="gone" | ||
| 123 | + tools:visibility="visible" /> | ||
| 124 | + | ||
| 125 | + <TextView | ||
| 126 | + android:id="@+id/tv_login" | ||
| 127 | + android:layout_width="wrap_content" | ||
| 128 | + android:layout_height="wrap_content" | ||
| 129 | + android:layout_alignParentStart="true" | ||
| 130 | + android:layout_centerVertical="true" | ||
| 131 | + android:layout_marginStart="16dp" | ||
| 132 | + android:textColor="@color/blue_dark" | ||
| 133 | + android:textSize="20sp" | ||
| 134 | + android:visibility="gone" /> | ||
| 135 | + | ||
| 220 | <LinearLayout | 136 | <LinearLayout | 
| 221 | - android:id="@+id/ll_sm_flow" | 137 | + android:id="@+id/ll_auth_login" | 
| 222 | android:layout_width="140dp" | 138 | android:layout_width="140dp" | 
| 223 | android:layout_height="45dp" | 139 | android:layout_height="45dp" | 
| 224 | - android:layout_alignParentStart="true" | 140 | + android:layout_alignParentEnd="true" | 
| 225 | android:layout_centerVertical="true" | 141 | android:layout_centerVertical="true" | 
| 226 | - android:layout_marginStart="16dp" | 142 | + android:layout_marginEnd="16dp" | 
| 227 | android:background="@drawable/selector_button_green" | 143 | android:background="@drawable/selector_button_green" | 
| 228 | android:gravity="center" | 144 | android:gravity="center" | 
| 229 | - android:orientation="horizontal"> | 145 | + android:orientation="horizontal" | 
| 146 | + android:visibility="gone"> | ||
| 230 | 147 | ||
| 231 | <TextView | 148 | <TextView | 
| 149 | + android:id="@+id/button_login" | ||
| 232 | android:layout_width="wrap_content" | 150 | android:layout_width="wrap_content" | 
| 233 | android:layout_height="wrap_content" | 151 | android:layout_height="wrap_content" | 
| 234 | android:gravity="center" | 152 | android:gravity="center" | 
| 235 | android:includeFontPadding="false" | 153 | android:includeFontPadding="false" | 
| 236 | - android:text="@string/demo_sm_flow" | 154 | + android:text="@string/cos_login_text" | 
| 237 | android:textColor="@color/white" | 155 | android:textColor="@color/white" | 
| 238 | android:textSize="16sp" /> | 156 | android:textSize="16sp" /> | 
| 239 | </LinearLayout> | 157 | </LinearLayout> | 
| 240 | 158 | ||
| 241 | <LinearLayout | 159 | <LinearLayout | 
| 242 | - android:id="@+id/ll_sm_map" | 160 | + android:id="@+id/ll_auth_logout" | 
| 243 | android:layout_width="140dp" | 161 | android:layout_width="140dp" | 
| 244 | android:layout_height="45dp" | 162 | android:layout_height="45dp" | 
| 245 | android:layout_alignParentEnd="true" | 163 | android:layout_alignParentEnd="true" | 
| ... | @@ -247,19 +165,93 @@ | ... | @@ -247,19 +165,93 @@ | 
| 247 | android:layout_marginEnd="16dp" | 165 | android:layout_marginEnd="16dp" | 
| 248 | android:background="@drawable/selector_button_green" | 166 | android:background="@drawable/selector_button_green" | 
| 249 | android:gravity="center" | 167 | android:gravity="center" | 
| 250 | - android:orientation="horizontal"> | 168 | + android:orientation="horizontal" | 
| 169 | + android:visibility="gone"> | ||
| 251 | 170 | ||
| 252 | <TextView | 171 | <TextView | 
| 172 | + android:id="@+id/button_logout" | ||
| 253 | android:layout_width="wrap_content" | 173 | android:layout_width="wrap_content" | 
| 254 | android:layout_height="wrap_content" | 174 | android:layout_height="wrap_content" | 
| 255 | android:gravity="center" | 175 | android:gravity="center" | 
| 256 | android:includeFontPadding="false" | 176 | android:includeFontPadding="false" | 
| 257 | - android:text="@string/demo_sm_map" | 177 | + android:text="@string/cos_logout_text" | 
| 258 | android:textColor="@color/white" | 178 | android:textColor="@color/white" | 
| 259 | android:textSize="16sp" /> | 179 | android:textSize="16sp" /> | 
| 260 | </LinearLayout> | 180 | </LinearLayout> | 
| 261 | </RelativeLayout> | 181 | </RelativeLayout> | 
| 262 | 182 | ||
| 183 | + <RelativeLayout | ||
| 184 | + android:id="@+id/pb_loading" | ||
| 185 | + android:layout_width="match_parent" | ||
| 186 | + android:layout_height="match_parent" | ||
| 187 | + android:layout_centerInParent="true" | ||
| 188 | + android:background="@android:color/transparent" | ||
| 189 | + android:translationZ="100dp" | ||
| 190 | + android:visibility="gone" | ||
| 191 | + tools:visibility="visible"> | ||
| 192 | + | ||
| 193 | + <ProgressBar | ||
| 194 | + android:layout_width="48dp" | ||
| 195 | + android:layout_height="48dp" | ||
| 196 | + android:layout_centerInParent="true" | ||
| 197 | + android:indeterminate="true" | ||
| 198 | + android:indeterminateTint="@color/cos_green5" | ||
| 199 | + android:indeterminateTintMode="src_atop" /> | ||
| 200 | + </RelativeLayout> | ||
| 201 | + </RelativeLayout> | ||
| 202 | + | ||
| 203 | + <RelativeLayout | ||
| 204 | + android:id="@+id/rl_sm_view" | ||
| 205 | + android:layout_width="match_parent" | ||
| 206 | + android:layout_height="70dp" | ||
| 207 | + android:layout_below="@+id/rl_auth" | ||
| 208 | + android:layout_marginHorizontal="8dp" | ||
| 209 | + android:layout_marginTop="24dp" | ||
| 210 | + android:layout_marginBottom="16dp" | ||
| 211 | + android:background="@drawable/shape_cos_white"> | ||
| 212 | + | ||
| 213 | + <LinearLayout | ||
| 214 | + android:id="@+id/ll_sm_flow" | ||
| 215 | + android:layout_width="140dp" | ||
| 216 | + android:layout_height="45dp" | ||
| 217 | + android:layout_alignParentStart="true" | ||
| 218 | + android:layout_centerVertical="true" | ||
| 219 | + android:layout_marginStart="16dp" | ||
| 220 | + android:background="@drawable/selector_button_green" | ||
| 221 | + android:gravity="center" | ||
| 222 | + android:orientation="horizontal"> | ||
| 223 | + | ||
| 224 | + <TextView | ||
| 225 | + android:layout_width="wrap_content" | ||
| 226 | + android:layout_height="wrap_content" | ||
| 227 | + android:gravity="center" | ||
| 228 | + android:includeFontPadding="false" | ||
| 229 | + android:text="@string/demo_sm_flow" | ||
| 230 | + android:textColor="@color/white" | ||
| 231 | + android:textSize="16sp" /> | ||
| 232 | + </LinearLayout> | ||
| 233 | + | ||
| 234 | + <LinearLayout | ||
| 235 | + android:id="@+id/ll_sm_map" | ||
| 236 | + android:layout_width="140dp" | ||
| 237 | + android:layout_height="45dp" | ||
| 238 | + android:layout_alignParentEnd="true" | ||
| 239 | + android:layout_centerVertical="true" | ||
| 240 | + android:layout_marginEnd="16dp" | ||
| 241 | + android:background="@drawable/selector_button_green" | ||
| 242 | + android:gravity="center" | ||
| 243 | + android:orientation="horizontal"> | ||
| 244 | + | ||
| 245 | + <TextView | ||
| 246 | + android:layout_width="wrap_content" | ||
| 247 | + android:layout_height="wrap_content" | ||
| 248 | + android:gravity="center" | ||
| 249 | + android:includeFontPadding="false" | ||
| 250 | + android:text="@string/demo_sm_map" | ||
| 251 | + android:textColor="@color/white" | ||
| 252 | + android:textSize="16sp" /> | ||
| 253 | + </LinearLayout> | ||
| 263 | </RelativeLayout> | 254 | </RelativeLayout> | 
| 264 | - </ScrollView> | 255 | + | 
| 265 | -</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | 256 | + </RelativeLayout> | 
| 257 | +</ScrollView> | ... | ... | 
| 1 | <resources> | 1 | <resources> | 
| 2 | - <string name="lbl_cosmote_webview_permission_title">Demo App</string> | 2 | + <string name="webview_permission_title">Demo App</string> | 
| 3 | - <string name="lbl_cosmote_webview_permission_message">Το Demo App ζητάει πρόσβαση στην τοποθεσία σας.</string> | 3 | + <string name="webview_permission_message">Το Demo App ζητάει πρόσβαση στην τοποθεσία σας.</string> | 
| 4 | <string name="lbl_take_photo_accept">Οκ</string> | 4 | <string name="lbl_take_photo_accept">Οκ</string> | 
| 5 | <string name="lbl_take_photo_decline">Άκυρο</string> | 5 | <string name="lbl_take_photo_decline">Άκυρο</string> | 
| 6 | <string name="welcome_user">Γεια σου %1$s !</string> | 6 | <string name="welcome_user">Γεια σου %1$s !</string> | ... | ... | 
- 
Please register or login to post a comment
