Created
November 12, 2018 13:55
-
-
Save cliffgr/2f2c8f0f17f0dff3f3d19d14ef7e4ca3 to your computer and use it in GitHub Desktop.
Gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* 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