Panagiotis Triantafyllou

android target api 35, changed sdk version in constants

......@@ -3,13 +3,14 @@ apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'
android {
compileSdkVersion 34
buildToolsVersion "34.0.0"
compileSdkVersion 35
buildToolsVersion "35.0.0"
namespace "warp.ly.android_sdk"
defaultConfig {
applicationId "warp.ly.android_sdk"
minSdkVersion 31
targetSdkVersion 34
targetSdkVersion 35
versionCode 100
versionName "1.0.0"
}
......
......@@ -8,9 +8,9 @@ buildscript {
maven { url 'https://plugins.gradle.org/m2/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:8.8.0'
classpath 'com.google.gms:google-services:4.4.2'
classpath 'com.huawei.agconnect:agcp:1.9.1.300'
classpath 'com.android.tools.build:gradle:8.7.3'
classpath 'com.google.gms:google-services:4.4.3'
classpath 'com.huawei.agconnect:agcp:1.9.1.301'
classpath 'io.github.gradle-nexus:publish-plugin:1.1.0'
// NOTE: Do not place your application dependencies here; they belong
......@@ -18,6 +18,10 @@ buildscript {
}
}
plugins {
id 'maven-publish'
}
allprojects {
repositories {
mavenCentral()
......@@ -27,5 +31,4 @@ allprojects {
}
}
apply plugin: 'io.github.gradle-nexus.publish-plugin'
apply from: "${rootDir}/scripts/publish-root.gradle"
\ No newline at end of file
......
#Fri Jul 26 17:08:44 EEST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
......
This diff is collapsed. Click to expand it.
// Create variables with empty default values
// Central Portal credentials
ext["centralPortalUsername"] = ''
ext["centralPortalPassword"] = ''
// keyId is the last 8 characters of the GPG key
ext["signing.keyId"] = ''
// password is the passphrase of the GPG key
ext["signing.password"] = ''
// key is the base64 private GPG key
ext["signing.key"] = ''
// osshrUsername and ossrhPassword are the account details for MavenCentral
// which we’ve chosen at the Jira registration step (Sonatype site))
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''
ext["sonatypeStagingProfileId"] = ''
File secretPropsFile = project.rootProject.file('local.properties')
if (secretPropsFile.exists()) {
......@@ -19,24 +18,11 @@ if (secretPropsFile.exists()) {
new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
p.each { name, value -> ext[name] = value }
} else {
// Use system environment variables
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID')
// Use system environment variables for signing
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
ext["signing.key"] = System.getenv('SIGNING_KEY')
}
// Set up Sonatype repository
nexusPublishing {
repositories {
sonatype {
stagingProfileId = sonatypeStagingProfileId
username = ossrhUsername
password = ossrhPassword
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
}
}
// Central Portal credentials can also come from environment
ext["centralPortalUsername"] = System.getenv('CENTRAL_PORTAL_USERNAME')
ext["centralPortalPassword"] = System.getenv('CENTRAL_PORTAL_PASSWORD')
}
......
......@@ -5,15 +5,15 @@ android.buildFeatures.buildConfig = true
ext {
PUBLISH_GROUP_ID = 'ly.warp'
PUBLISH_VERSION = '4.5.5.4deh2'
PUBLISH_VERSION = '4.5.5.4deh3'
PUBLISH_ARTIFACT_ID = 'warply-android-sdk'
}
apply from: "${rootProject.projectDir}/scripts/publish-module.gradle"
android {
compileSdkVersion 34
buildToolsVersion "34.0.0"
compileSdkVersion 35
buildToolsVersion "35.0.0"
useLibrary 'org.apache.http.legacy'
......@@ -27,7 +27,7 @@ android {
defaultConfig {
minSdkVersion 31
targetSdkVersion 34
targetSdkVersion 35
consumerProguardFiles 'proguard-rules.pro'
vectorDrawables.useSupportLibrary = true
}
......@@ -61,45 +61,42 @@ android {
dependencies {
//------------------------------ Support -----------------------------//
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
api "androidx.security:security-crypto:1.1.0-alpha03"
implementation 'androidx.appcompat:appcompat:1.7.1'
implementation "androidx.security:security-crypto:1.1.0"
// For minSDK 23 use 1.0.0, for minSDK 21 use 1.1.0 that is currently in alpha
api 'org.altbeacon:android-beacon-library:2.19.3'
api 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
api 'io.reactivex.rxjava3:rxjava:3.1.8'
api 'io.reactivex.rxjava3:rxandroid:3.0.2'
implementation 'com.google.android.material:material:1.5.0'
implementation 'org.altbeacon:android-beacon-library:2.19.3'
implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
implementation 'io.reactivex.rxjava3:rxjava:3.1.8'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
implementation 'com.google.android.material:material:1.12.0'
implementation 'org.greenrobot:eventbus:3.3.1'
api 'com.google.guava:guava:30.1-android'
implementation 'com.google.guava:guava:33.0.0-android'
//------------------------------ Firebase -----------------------------//
api platform('com.google.firebase:firebase-bom:29.0.3')
implementation platform('com.google.firebase:firebase-bom:34.2.0')
implementation('com.google.firebase:firebase-messaging') {
exclude group: 'com.google.android.gms', module: 'play-services-location'
}
//------------------------------ GMS -----------------------------//
api 'com.google.android.gms:play-services-base:18.1.0'
implementation 'com.google.android.gms:play-services-location:19.0.1'
implementation 'com.google.android.gms:play-services-base:18.7.2'
implementation 'com.google.android.gms:play-services-location:21.3.0'
//------------------------------ Work Manager -----------------------------//
api 'androidx.work:work-runtime:2.7.1'
implementation 'androidx.work:work-runtime:2.10.3'
//------------------------------ Glide -----------------------------//
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
//------------------------------ Huawei -----------------------------//
implementation 'com.huawei.agconnect:agconnect-core:1.7.2.300'
implementation 'com.huawei.hms:base:6.6.0.300'
implementation 'com.huawei.hms:push:6.7.0.300'
implementation 'com.huawei.hms:ads-identifier:3.4.56.300'
//------------------------------ SQLCipher -----------------------------//
api "net.zetetic:android-database-sqlcipher:4.5.2"
api "androidx.sqlite:sqlite:2.2.0"
api 'com.getkeepsafe.relinker:relinker:1.4.4'
implementation 'com.huawei.agconnect:agconnect-core:1.9.3.301'
implementation 'com.huawei.hms:base:6.13.0.303'
implementation 'com.huawei.hms:push:6.10.0.300'
implementation 'com.huawei.hms:ads-identifier:3.4.62.300'
//------------------------------ SQLite (Standard Android) -----------------------------//
implementation 'androidx.sqlite:sqlite:2.5.2'
//------------------------------ Retrofit -----------------------------//
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
......
......@@ -52,7 +52,6 @@ public class BaseFragmentActivity extends FragmentActivity implements Navigation
mBottomNavigationView = findViewById(R.id.bt_tabs);
if (WarplyDBHelper.getInstance(this).isTableNotEmpty("auth")) {
WarplyManager.getSupermarketCampaign(mCampaignsCallback);
WarplyManager.getRedeemedSMHistory(mSMHistoryReceiver);
}
......@@ -138,18 +137,6 @@ public class BaseFragmentActivity extends FragmentActivity implements Navigation
// Inner and Anonymous Classes
// ===========================================================
private final CallbackReceiver<ArrayList<Campaign>> mCampaignsCallback = new CallbackReceiver<ArrayList<Campaign>>() {
@Override
public void onSuccess(ArrayList<Campaign> result) {
Toast.makeText(BaseFragmentActivity.this, "Campaigns Success " + String.valueOf(result.size()), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int errorCode) {
Toast.makeText(BaseFragmentActivity.this, "Campaigns Error", Toast.LENGTH_SHORT).show();
}
};
private final CallbackReceiver<RedeemedSMHistoryModel> mSMHistoryReceiver = new CallbackReceiver<RedeemedSMHistoryModel>() {
@Override
public void onSuccess(RedeemedSMHistoryModel result) {
......
......@@ -14,26 +14,19 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.json.JSONObject;
import java.util.ArrayList;
import ly.warp.sdk.R;
import ly.warp.sdk.activities.HomeActivity;
import ly.warp.sdk.db.WarplyDBHelper;
import ly.warp.sdk.io.callbacks.CallbackReceiver;
import ly.warp.sdk.io.models.Campaign;
import ly.warp.sdk.io.models.RedeemedSMHistoryModel;
import ly.warp.sdk.utils.WarplyManagerHelper;
import ly.warp.sdk.utils.managers.WarplyManager;
public class HomeFragment extends Fragment implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener {
public class HomeFragment extends Fragment implements View.OnClickListener {
private RelativeLayout mOptionOne, mOptionTwo, mOptionThree, mPbLoading;
private TextView mTvUsername, mTvUser;
private SwipeRefreshLayout mSwipeRefresh;
private EditText mEtGuid;
private LinearLayout mLlAuthLogin, mLlAuthLogout, mRlSmFlow, mRlSmMap;
......@@ -45,8 +38,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSwipeRefresh = view.findViewById(R.id.sw_refresh);
mSwipeRefresh.setOnRefreshListener(this);
mOptionOne = view.findViewById(R.id.info_button);
TextView mOptionOneText = mOptionOne.findViewById(R.id.option_text);
ImageView mOptionOneImage = mOptionOne.findViewById(R.id.option_icon);
......@@ -100,17 +91,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip
}
@Override
public void onRefresh() {
if (WarplyDBHelper.getInstance(getActivity()).isTableNotEmpty("auth")) {
WarplyManager.getSupermarketCampaign(mCampaignsCallback);
WarplyManager.getRedeemedSMHistory(mSMHistoryReceiver);
mSwipeRefresh.setRefreshing(false);
} else {
mSwipeRefresh.setRefreshing(false);
}
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.ll_auth_login) {
//6012049321, 6012049322, 6012049323, 7000000831 history, 7000000826, 7000000831 shared coupons
......@@ -141,18 +121,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip
return homeFragment;
}
private final CallbackReceiver<ArrayList<Campaign>> mCampaignsCallback = new CallbackReceiver<ArrayList<Campaign>>() {
@Override
public void onSuccess(ArrayList<Campaign> result) {
Toast.makeText(getActivity(), "Campaigns Success", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int errorCode) {
Toast.makeText(getActivity(), "Campaigns Error", Toast.LENGTH_SHORT).show();
}
};
private final CallbackReceiver<JSONObject> mLogoutReceiver = new CallbackReceiver<JSONObject>() {
@Override
public void onSuccess(JSONObject result) {
......@@ -180,16 +148,6 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip
mLlAuthLogout.setVisibility(View.VISIBLE);
mTvUser.setVisibility(View.VISIBLE);
mTvUser.setText(mEtGuid.getText().toString());
// if (WarplyManagerHelper.getConsumerInternal() != null) {
// JSONObject profMetadata = WarpJSONParser.getJSONFromString(WarplyManagerHelper.getConsumerInternal().getProfileMetadata());
// if (profMetadata != null && profMetadata.has("guid")) {
// String userGuid = profMetadata.optString("guid", "");
// mTvUser.setText(userGuid);
// }
// }
WarplyManager.getSupermarketCampaign(mCampaignsCallback);
WarplyManager.getRedeemedSMHistory(mSMHistoryReceiver);
}
@Override
......@@ -198,16 +156,4 @@ public class HomeFragment extends Fragment implements View.OnClickListener, Swip
Toast.makeText(getActivity(), "LOGIN ERROR", Toast.LENGTH_SHORT).show();
}
};
private final CallbackReceiver<RedeemedSMHistoryModel> mSMHistoryReceiver = new CallbackReceiver<RedeemedSMHistoryModel>() {
@Override
public void onSuccess(RedeemedSMHistoryModel result) {
Toast.makeText(getActivity(), "SM HISTORY SUCCESS", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int errorCode) {
Toast.makeText(getActivity(), "SM HISTORY ERROR", Toast.LENGTH_SHORT).show();
}
};
}
\ No newline at end of file
......
/*
* Copyright 2010-2013 Warply Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE WARPLY LTD ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL WARPLY LTD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package ly.warp.sdk.io.models;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import ly.warp.sdk.utils.WarpUtils;
import ly.warp.sdk.utils.constants.WarpConstants;
/**
* Created by Panagiotis Triantafyllou on 20-Jan-25.
*/
public class MarketPassDetailsModel {
private static final String BARCODE = "barcode";
private static final String SUPERMARKETS = "supermarkets";
private static final String TOTAL_DISCOUNT = "total_available_discount";
private static final String NEW_OFFERS = "new_offers";
private ArrayList<Supermarkets> supermarkets = new ArrayList<Supermarkets>();
private String barcode = "";
private double totalDiscount = 0.0d;
private int newOffers = 0;
public MarketPassDetailsModel() {
this.supermarkets = new ArrayList<Supermarkets>();
this.barcode = "";
this.totalDiscount = 0.0d;
this.newOffers = 0;
}
/**
* Basic constructor used to create an object from a String, representing a
* JSON Object
*
* @param json The String, representing the JSON Object
* @throws JSONException Thrown if the String cannot be converted to JSON
*/
public MarketPassDetailsModel(String json) throws JSONException {
this(new JSONObject(json));
}
/**
* Constructor used to create an Object from a given JSON Object
*
* @param json JSON Object used to create the Campaign
*/
public MarketPassDetailsModel(JSONObject json) {
if (json != null) {
if (json.optJSONArray(SUPERMARKETS) != null) {
JSONArray tempSupermarkets = json.optJSONArray(SUPERMARKETS);
if (tempSupermarkets != null && tempSupermarkets.length() > 0) {
for (int i = 0, lim = tempSupermarkets.length(); i < lim; ++i) {
this.supermarkets.add(new Supermarkets(tempSupermarkets.optJSONObject(i)));
}
}
}
this.barcode = json.isNull(BARCODE) ? "" : json.optString(BARCODE);
this.totalDiscount = json.optDouble(TOTAL_DISCOUNT);
this.newOffers = json.optInt(NEW_OFFERS);
}
}
/**
* Converts the Campaign into a JSON Object
*
* @return The JSON Object created from this campaign
*/
public JSONObject toJSONObject() {
JSONObject jObj = new JSONObject();
try {
jObj.putOpt(BARCODE, this.barcode);
jObj.putOpt(TOTAL_DISCOUNT, this.totalDiscount);
jObj.putOpt(SUPERMARKETS, this.supermarkets);
jObj.putOpt(NEW_OFFERS, this.newOffers);
} catch (JSONException e) {
if (WarpConstants.DEBUG) {
e.printStackTrace();
}
}
return jObj;
}
/**
* String representation of the Campaign, as a JSON object
*
* @return A String representation of JSON object
*/
public String toString() {
if (toJSONObject() != null)
return toJSONObject().toString();
return null;
}
/**
* String representation of the Campaign, as a human readable JSON object
*
* @return A human readable String representation of JSON object
*/
public String toHumanReadableString() {
String humanReadableString = null;
try {
humanReadableString = toJSONObject().toString(2);
} catch (JSONException e) {
WarpUtils.warn("Failed converting Campaign JSON object to String",
e);
}
return humanReadableString;
}
public class Supermarkets {
private static final String LOGO = "logo";
private static final String NAME = "name";
private static final String UUID = "uuid";
private String logo = "";
private String name = "";
private String uuid = "";
public Supermarkets() {
this.logo = "";
this.name = "";
this.uuid = "";
}
public Supermarkets(JSONObject json) {
if (json != null) {
this.logo = json.isNull(LOGO) ? "" : json.optString(LOGO);
this.name = json.isNull(NAME) ? "" : json.optString(NAME);
this.uuid = json.isNull(UUID) ? "" : json.optString(UUID);
}
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
}
// ================================================================================
// Getters
// ================================================================================
public ArrayList<Supermarkets> getSupermarkets() {
return supermarkets;
}
public void setSupermarkets(ArrayList<Supermarkets> supermarkets) {
this.supermarkets = supermarkets;
}
public String getBarcode() {
return barcode;
}
public void setBarcode(String barcode) {
this.barcode = barcode;
}
public double getTotalDiscount() {
return totalDiscount;
}
public void setTotalDiscount(double totalDiscount) {
this.totalDiscount = totalDiscount;
}
public int getNewOffers() {
return newOffers;
}
public void setNewOffers(int newOffers) {
this.newOffers = newOffers;
}
}
package ly.warp.sdk.utils;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Base64;
import android.util.Log;
import java.security.KeyStore;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
/**
* Utility class for encrypting and decrypting sensitive data using Android Keystore
*/
public class CryptoUtils {
private static final String TAG = "CryptoUtils";
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final String ANDROID_KEYSTORE = "AndroidKeyStore";
private static final String KEY_ALIAS = "tn#mpOl3v3Dy1pr@W";
private static final int GCM_IV_LENGTH = 12;
private static final int GCM_TAG_LENGTH = 16;
/**
* Encrypt a plain text string
*
* @param plainText The text to encrypt
* @return Base64 encoded encrypted string, or original text if encryption fails
*/
public static String encrypt(String plainText) {
if (plainText == null || plainText.isEmpty()) {
return plainText;
}
try {
SecretKey secretKey = getOrCreateSecretKey();
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] iv = cipher.getIV();
byte[] encryptedData = cipher.doFinal(plainText.getBytes("UTF-8"));
// Combine IV + encrypted data
byte[] combined = new byte[iv.length + encryptedData.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encryptedData, 0, combined, iv.length, encryptedData.length);
return Base64.encodeToString(combined, Base64.DEFAULT);
} catch (Exception e) {
Log.e(TAG, "Encryption failed, returning original text", e);
// Return original text if encryption fails - graceful degradation
return plainText;
}
}
/**
* Decrypt an encrypted string
*
* @param encryptedText The Base64 encoded encrypted text
* @return Decrypted plain text, or original text if decryption fails
*/
public static String decrypt(String encryptedText) {
if (encryptedText == null || encryptedText.isEmpty()) {
return encryptedText;
}
try {
SecretKey secretKey = getOrCreateSecretKey();
byte[] combined = Base64.decode(encryptedText, Base64.DEFAULT);
// Extract IV and encrypted data
byte[] iv = new byte[GCM_IV_LENGTH];
byte[] encryptedData = new byte[combined.length - GCM_IV_LENGTH];
System.arraycopy(combined, 0, iv, 0, GCM_IV_LENGTH);
System.arraycopy(combined, GCM_IV_LENGTH, encryptedData, 0, encryptedData.length);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData, "UTF-8");
} catch (Exception e) {
Log.e(TAG, "Decryption failed, returning original text", e);
// Return original text if decryption fails - might be unencrypted legacy data
return encryptedText;
}
}
/**
* Get or create the secret key in Android Keystore
*/
private static SecretKey getOrCreateSecretKey() throws Exception {
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
if (!keyStore.containsAlias(KEY_ALIAS)) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE);
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(true)
.build();
keyGenerator.init(keyGenParameterSpec);
keyGenerator.generateKey();
}
return ((KeyStore.SecretKeyEntry) keyStore.getEntry(KEY_ALIAS, null)).getSecretKey();
}
/**
* Check if a string appears to be encrypted (Base64 format)
*
* @param text The text to check
* @return true if text appears to be encrypted
*/
public static boolean isEncrypted(String text) {
if (text == null || text.isEmpty()) {
return false;
}
try {
byte[] decoded = Base64.decode(text, Base64.DEFAULT);
// Check if decoded length is reasonable for encrypted data (IV + data + tag)
return decoded.length > GCM_IV_LENGTH + GCM_TAG_LENGTH;
} catch (Exception e) {
return false;
}
}
}
......@@ -30,7 +30,7 @@ public class WarpConstants {
/**
* The version of the SDK installed in the device
*/
public static final String SDK_VERSION = "4.5.5.4";
public static final String SDK_VERSION = "4.5.5.5";
/**
* The URL of the server where it should ping
......
......@@ -568,8 +568,8 @@ public class WarpView extends WebView implements DefaultLifecycleObserver {
public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
if (WarpActivity != null && !WarpActivity.isFinishing()) {
AlertDialog.Builder builder = new AlertDialog.Builder(WarpActivity);
builder.setTitle(getContext().getString(R.string.lbl_cosmote_webview_permission_title));
builder.setMessage(getContext().getString(R.string.lbl_cosmote_webview_permission_message))
builder.setTitle(getContext().getString(R.string.webview_permission_title));
builder.setMessage(getContext().getString(R.string.webview_permission_message))
.setCancelable(false)
.setPositiveButton(getContext().getString(R.string.lbl_take_photo_accept), (dialog, id) -> checkForPermissions(origin, callback))
.setNegativeButton(getContext().getString(R.string.lbl_take_photo_decline), (dialog, id) -> callback.invoke(origin, false, false));
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sw_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cos_skyblue2">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cos_skyblue2">
......@@ -261,5 +254,4 @@
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</ScrollView>
......
<resources>
<string name="lbl_cosmote_webview_permission_title">Demo App</string>
<string name="lbl_cosmote_webview_permission_message">Το Demo App ζητάει πρόσβαση στην τοποθεσία σας.</string>
<string name="webview_permission_title">Demo App</string>
<string name="webview_permission_message">Το Demo App ζητάει πρόσβαση στην τοποθεσία σας.</string>
<string name="lbl_take_photo_accept">Οκ</string>
<string name="lbl_take_photo_decline">Άκυρο</string>
<string name="welcome_user">Γεια σου %1$s !</string>
......