Skip to content

Instantly share code, notes, and snippets.

@cliffgr
Created November 12, 2018 13:55
Show Gist options
  • Save cliffgr/2f2c8f0f17f0dff3f3d19d14ef7e4ca3 to your computer and use it in GitHub Desktop.
Save cliffgr/2f2c8f0f17f0dff3f3d19d14ef7e4ca3 to your computer and use it in GitHub Desktop.
Gist
/*
*
* Created by wappier on 13/02/2018
* Copyright (c) 2018 . All rights reserved.
* Author : ka
* Company e-mail : info@wappier.com
*
*/
package com.wappier.wappierSDK;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import com.wappier.wappierSDK.api.NetworkManager;
import com.wappier.wappierSDK.api.PurchaseStatusListener;
import com.wappier.wappierSDK.data.database.DatabaseLayer;
import com.wappier.wappierSDK.data.network.networkrequest.OnNetworkRequestResponseListener;
import com.wappier.wappierSDK.data.preferences.SessionHandler;
import com.wappier.wappierSDK.model.NetworkResponse;
import com.wappier.wappierSDK.utils.Constants;
import com.wappier.wappierSDK.utils.Logger;
import com.wappier.wappierSDK.loyalty.Loyalty;
import com.wappier.wappierSDK.loyalty.ui.Orientation;
import com.wappier.wappierSDK.data.network.networkrequest.NetworkRequest;
import com.wappier.wappierSDK.model.SkuMap;
import com.wappier.wappierSDK.utils.GoogleAdvertisingHelper;
import com.wappier.wappierSDK.utils.OpenEventHelper;
import com.wappier.wappierSDK.utils.Utils;
import com.wappier.wappierSDK.xnEvent.XNEventBuilder;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import static com.wappier.wappierSDK.utils.Constants.LOG_TAG;
public class Repository {
private NetworkRequest mNetworkRequest;
private SessionHandler mSessionHandler;
private SessionHandler mSkuMapHandler;
private DatabaseLayer mDatabaseLayer;
private DataManager mDataManager;
private Loyalty mLoyalty;
private NetworkManager networkManager;
private Context mContext;
private XNEventBuilder xnEventBuilder;
private GoogleAdvertisingHelper googleAdvertisingHelper;
@VisibleForTesting
private CountDownLatch latch;
// Thread pool for public method execution
private static final ThreadGroup API_THREAD_GROUP = new ThreadGroup("wp_api");
private ScheduledThreadPoolExecutor sPubQueue;
// Thread pool for running the request Runnables
private static final ThreadGroup OUTGOING_THREAD_GROUP = new ThreadGroup("wp_outgoing");
private ScheduledThreadPoolExecutor pool;
private GoogleAdvertisingHelper.AdvCallBack googleAdvCallback = new GoogleAdvertisingHelper.AdvCallBack() {
@Override
public void onSuccess(String googleAdvertisingId) {
mDataManager.setsGoogleAdvertisingID(googleAdvertisingId);
sendStartRequest();
}
};
public CountDownLatch getLatch() {
return latch;
}
public void setLatch(CountDownLatch latch) {
this.latch = latch;
}
public ScheduledThreadPoolExecutor getExecutor() {
return sPubQueue;
}
public Repository(Context context, NetworkRequest networkRequest, SessionHandler sessionHandler,
SessionHandler skuMapHandler, DatabaseLayer databaseLayer, String appToken) {
this.mContext = context;
this.mNetworkRequest = networkRequest;
this.mSessionHandler = sessionHandler;
this.mSkuMapHandler = skuMapHandler;
this.mDatabaseLayer = databaseLayer;
mDataManager = new DataManager(context, mSessionHandler, appToken);
googleAdvertisingHelper = new GoogleAdvertisingHelper(context, googleAdvCallback);
sPubQueue = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
return new Thread(API_THREAD_GROUP, runnable);
}
});
if (android.os.Build.VERSION.SDK_INT >= 21) {
sPubQueue.setRemoveOnCancelPolicy(true);
}
pool = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
return new Thread(OUTGOING_THREAD_GROUP, runnable);
}
});
if (android.os.Build.VERSION.SDK_INT >= 21) {
pool.setRemoveOnCancelPolicy(true);
}
mLoyalty = Loyalty.getInstance();
mLoyalty.setSessionHandler(mSessionHandler);
networkManager = new NetworkManager(mNetworkRequest);
xnEventBuilder = new XNEventBuilder();
}
public Repository init() {
googleAdvertisingHelper.getAdvertisingId();
firstRun();
forceTrackOpen();
return this;
}
public void setNetworkHeaders() {
if (mNetworkRequest != null)
mNetworkRequest.headers(mDataManager.getNetworkHeaders());
}
public void dumpEvents() {
if (!isOnline(mContext)) {
return;
}
if (pool.isShutdown()) {
return;
}
pool.execute(new Runnable() {
public void run() {
if (latch != null)
networkManager.setLatch(latch);
if (TextUtils.isEmpty(mSessionHandler.getStringPreference(SessionHandler.WAPPIER_ID))) {
Logger.d("** Wappier Id has not been set yet, will not flush events. **");
return;
}
networkManager.flushAll(mDatabaseLayer.getEvents(), new OnNetworkRequestResponseListener() {
@Override
public void onSuccessResponse(NetworkResponse response) {
List<String> resultIds = new ArrayList<>();
try {
JSONObject jsonObject = new JSONObject(response.getResponse());
JSONArray eventsJsonArray = jsonObject.getJSONArray("events");
for (int i = 0; i < eventsJsonArray.length(); i++) {
JSONObject responseJSONObject = eventsJsonArray.getJSONObject(i);
if (responseJSONObject.has("success") || responseJSONObject.has("error")) {
JSONObject successJSONObject = responseJSONObject.getJSONObject("success");
if (successJSONObject.has("clientId")) {
resultIds.add(successJSONObject.getString("clientId"));
}
}
if (jsonObject.has("notifications")) {
Loyalty loyalty = Loyalty.getInstance();
if (loyalty != null && loyalty.isLoyaltyEnabled())
loyalty.setNotificationJson(jsonObject.getJSONObject("notifications"));
}
}
mDatabaseLayer.deleteSentEvents(resultIds);
} catch (JSONException e) {
e.printStackTrace();
}
if (latch != null)
latch.countDown();
}
@Override
public void onErrorResponse(NetworkResponse errorResponse) {
Logger.d("/events" + ": Error :" + errorResponse.toString());
if (latch != null)
latch.countDown();
}
});
}
});
}
public DataManager getDataManager() {
return mDataManager;
}
public SessionHandler getSkuMapHandler() {
return mSkuMapHandler;
}
public SessionHandler getSessionHandler() {
return mSessionHandler;
}
public DatabaseLayer getDatabaseLayer() {
return mDatabaseLayer;
}
public NetworkRequest getNetworkManager() {
return mNetworkRequest;
}
/**
* Returns true if an Internet connection is detected.
*
* @param context the app context to check connectivity from
* @return whether Internet connection exists
*/
private synchronized boolean isOnline(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
public void sendStartRequest() {
JSONObject payload = xnEventBuilder.buildStartEvent(mDataManager.getsGoogleAdvertisingID(), mDataManager.createBuildObject());
networkManager.requestStart(xnEventBuilder.appendHeaderToMessage(getMessageHeader(), payload));
}
public int getOrientation() {
return mDataManager.getOrientation();
}
private void firstRun() {
sPubQueue.execute(new Runnable() {
public void run() {
if (firstRunChecker()) {
Logger.i("******* Tracking FIRST_RUN *******");
String downloadTimeStamp = mSessionHandler.getStringPreference(SessionHandler.DOWNLOADED_TIMESTAMP);
if (downloadTimeStamp == null) {
downloadTimeStamp = String.valueOf(System.currentTimeMillis());
mSessionHandler.saveStringPreference(SessionHandler.DOWNLOADED_TIMESTAMP, downloadTimeStamp);
}
String firstRunTimestamp = String.valueOf(System.currentTimeMillis());
Logger.i("Download TimeStamp: " + downloadTimeStamp);
Logger.i("First run Timestamp: " + firstRunTimestamp);
JSONObject payload = xnEventBuilder.buildTrackFirstRunEvent(downloadTimeStamp, firstRunTimestamp);
mSessionHandler.saveBooleanPreference(SessionHandler.IS_FIRST_RUN, false);
transmitMessage(payload);
if (latch != null)
latch.countDown();
} else {
Logger.i("FIRST_RUN already tracked. No FIRST_RUN is stored.");
}
}
});
}
/**
* This method returns true/false depending on whether the starts first time
*
* @return a boolean
*/
private boolean firstRunChecker() {
return mSessionHandler.getBooleanPreference(SessionHandler.IS_FIRST_RUN, true);
}
public void trackAction(final String action) {
sPubQueue.execute(new Runnable() {
public void run() {
Logger.i("******* Tracking INAPP_ACTION *******");
transmitMessage(xnEventBuilder.buildTrackActionEvent(action));
if (latch != null)
latch.countDown();
}
});
}
public void trackTime(final long time) {
sPubQueue.execute(new Runnable() {
public void run() {
Logger.i("******* Tracking TIME_SPENT *******");
Logger.i("Tracked time: " + String.valueOf(time));
transmitMessage(xnEventBuilder.buildTrackTimeEvent(String.valueOf(time)));
if (latch != null)
latch.countDown();
}
});
}
public void trackPurchase(final double revenue, final String currencyCode, final String googleOrderId, final String productId, final String purchaseToken, final String purchaseType) {
sPubQueue.execute(new Runnable() {
public void run() {
Logger.i("******* Tracking PURCHASE *******");
if (revenue == 0 || TextUtils.isEmpty(currencyCode) || TextUtils.isEmpty(googleOrderId) || TextUtils.isEmpty(productId) || TextUtils.isEmpty(purchaseToken)) {
if (revenue <= 0) {
Logger.i("Revenue should be a positive int value.");
}
if (TextUtils.isEmpty(currencyCode)) {
Logger.i("Currency code is empty.");
}
if (TextUtils.isEmpty(googleOrderId)) {
Logger.i("Google order id is empty.");
}
if (TextUtils.isEmpty(productId)) {
Logger.i("ProductId(SKU id) is empty.");
}
if (TextUtils.isEmpty(purchaseToken)) {
Logger.i("PurchaseToken is empty.");
}
} else if (!Utils.isCurrencyCode(currencyCode)) {
Logger.i("Currency code is not valid.");
} else {
SkuMap skuMap = fetchPricingDpData(productId);
transmitMessage(xnEventBuilder.buildTrackPurchaseEvent(revenue, currencyCode, googleOrderId, productId, purchaseToken, purchaseType, skuMap));
}
if (latch != null)
latch.countDown();
}
});
}
public void trackOpen() {
if (OpenEventHelper.shouldTrackOpenEvent(mSessionHandler.getDatePreference(SessionHandler.LAST_OPEN_DATE))) {
forceTrackOpen();
}
}
public void forceTrackOpen() {
sPubQueue.execute(new Runnable() {
public void run() {
Logger.i("******* Tracking OPEN *******");
mSessionHandler.saveDatePreference(SessionHandler.LAST_OPEN_DATE);
transmitMessage(xnEventBuilder.buildTrackOpenEvent(mDataManager.createBuildObject()));
if (latch != null)
latch.countDown();
}
});
}
public void trackUserProfile(final HashMap<String, String> payloadMap) {
sPubQueue.execute(new Runnable() {
public void run() {
Logger.i("******* Tracking USER PROFILE *******");
transmitMessage(xnEventBuilder.buildTrackUserProfileEvent(payloadMap));
if (latch != null)
latch.countDown();
}
});
}
public void setUserName(String userName) {
mDataManager.setUserName(userName);
}
/**
* based on current skumap in shared prefs returns the mapped sku to the original sku
*
* @param originalSku the original sku
* @return String with fake/original sku
*/
public String getSku(String originalSku) {
String skuData = mSkuMapHandler.getStringPreference(originalSku, null);
JSONObject payload = xnEventBuilder.measureDPFetchEvent(originalSku);
JSONObject header = getMessageHeader();
mDatabaseLayer.saveEvent(xnEventBuilder.appendHeaderToMessage(header, payload));
if (skuData != null) {
SkuMap skuMapEntry = Utils.getSkuMap(originalSku, skuData);
Logger.d(Logger.TAG, "fetchSku skuData: " + skuData);
if (Utils.isValidDPT(skuMapEntry)) {
Logger.d(Logger.TAG, "fetchSku return mapSku: " + skuMapEntry.getTestSku());
return skuMapEntry.getTestSku();
} else {
clearSkuMapEntry(skuMapEntry);
}
}
Logger.d(Logger.TAG, "fetchSku return original sku: " + originalSku);
return originalSku;
}
public void getPurchaseStatus(String orderId, PurchaseStatusListener cb) {
try {
JSONObject jSONObject = new JSONObject();
jSONObject.put("transactionId", orderId);
if (networkManager != null)
networkManager.makePurchaseStatusRequest(jSONObject, cb);
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* clears sku map from shared prefs totally
*/
public void clearSkuMap() {
mSkuMapHandler.clearSharedPreferences();
}
/**
* clear from shared prefs a map entry for a specific sku
*
* @param skuMap
*/
public void clearSkuMapEntry(SkuMap skuMap) {
Logger.d(LOG_TAG, "clear DPT for SKU " + skuMap.getOriginalSku());
mSkuMapHandler.clearSharedPreferenceKey(skuMap.getOriginalSku());
JSONObject payload = getMeasureDPEvent(Constants.DPT_OFF, skuMap);
JSONObject header = getMessageHeader();
mDatabaseLayer.saveEvent(xnEventBuilder.appendHeaderToMessage(header, payload));
}
public JSONObject getMeasureDPEvent(String action, SkuMap skuMap) {
return xnEventBuilder.measureDPEvent(action, skuMap);
}
/**
* function to return if exists any pricing test id for the parameter sku
*
* @param sku get original sku
* @return SkuMap
*/
public SkuMap fetchPricingDpData(String sku) {
Logger.d(LOG_TAG, "fetch DPT id: " + sku);
Map<String, ?> allEntries = mSkuMapHandler.getAll();
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
String skuData = entry.getValue().toString();
SkuMap skuMap = Utils.getSkuMap(entry.getKey(), skuData);
if (skuMap.getTestSku().equals(sku) && skuMap.getStatus().equals("active")) {
Logger.d(LOG_TAG + "fetch DPT id found: " + skuMap.getPricingTestId());
return skuMap;
}
}
return new SkuMap();
}
/**
* On every refresh from server check for any existing pricing tests that have been expired
*
* @param mapSkuValues
*/
public void checkForExpiredPricingTests(Map<String, String> mapSkuValues) {
Map<String, ?> allEntries = mSkuMapHandler.getAll();
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
if (mapSkuValues.get(entry.getKey()) == null) {
SkuMap skuMap = Utils.getSkuMap(entry.getKey(), (String) entry.getValue());
clearSkuMapEntry(skuMap);
}
}
}
/**
* create or update an existing dpt in shared prefs
*
* @param originalSku
* @param skuMapValue
*/
public void updateDPT(String originalSku, String skuMapValue) {
mSkuMapHandler.saveStringPreference(originalSku, skuMapValue);
}
public JSONObject getMessageHeader() {
return xnEventBuilder.buildMessageHeader(
mDataManager.getUserName(),
mDataManager.getWappierId(),
mDataManager.getAppToken(),
mDataManager.getMotherPackageName(),
mDataManager.getsSdkVersion(),
mDataManager.getsTimezone(),
mDataManager.getMotherAppVersion(), String.valueOf(getSequence()));
}
public void transmitMessage(JSONObject payload) {
mDatabaseLayer.saveEvent(xnEventBuilder.appendHeaderToMessage(getMessageHeader(), payload));
dumpEvents();
}
/**
* Get number value, which is a <code>long</code> variable that will always increases by 1
* each time use it. This variable can be used to keep track of the sequence of the in app events
*
* @return <code>long</code> variable
*/
public long getSequence() {
long sequenceCounter = mSessionHandler.getLongPreference(SessionHandler.SEQUENCE, 0);
mSessionHandler.saveLongPreference(SessionHandler.SEQUENCE, sequenceCounter + 1);
return sequenceCounter;
}
public void setLOYOrientation(Orientation orientation) {
mDataManager.setOrientation(orientation.toInt());
}
public boolean getControlGroup() {
return mSessionHandler.getBooleanPreference(SessionHandler.CONTROL_GROUP, false);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment