Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ly.count.android.api.Countly Maven / Gradle / Ivy
package ly.count.android.api;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import org.OpenUDID.OpenUDID_manager;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
public class Countly {
private static Countly sharedInstance_;
private Timer timer_;
private ConnectionQueue queue_;
private EventQueue eventQueue_;
private boolean isVisible_;
private double unsentSessionLength_;
private double lastTime_;
private int activityCount_;
private CountlyStore countlyStore_;
protected static final int SESSION_DURATION_WHEN_TIME_ADJUSTED = 15;
static public Countly sharedInstance() {
if (sharedInstance_ == null)
sharedInstance_ = new Countly();
return sharedInstance_;
}
private Countly() {
queue_ = new ConnectionQueue();
timer_ = new Timer();
timer_.schedule(new TimerTask() {
@Override
public void run() {
onTimer();
}
}, 60 * 1000, 60 * 1000);
isVisible_ = false;
unsentSessionLength_ = 0;
activityCount_ = 0;
}
public void init(Context context, String serverURL, String appKey) {
OpenUDID_manager.sync(context);
countlyStore_ = new CountlyStore(context);
queue_.setContext(context);
queue_.setServerURL(serverURL);
queue_.setAppKey(appKey);
queue_.setCountlyStore(countlyStore_);
eventQueue_ = new EventQueue(countlyStore_);
}
public void onStart() {
activityCount_++;
if (activityCount_ == 1)
onStartHelper();
}
public void onStop() {
activityCount_--;
if (activityCount_ == 0)
onStopHelper();
}
public void onStartHelper() {
lastTime_ = System.currentTimeMillis() / 1000.0;
queue_.beginSession();
isVisible_ = true;
}
public void onStopHelper() {
if (eventQueue_.size() > 0)
queue_.recordEvents(eventQueue_.events());
double currTime = System.currentTimeMillis() / 1000.0;
unsentSessionLength_ += currTime - lastTime_;
int duration = (int) unsentSessionLength_;
queue_.endSession(duration);
unsentSessionLength_ -= duration;
isVisible_ = false;
}
public void recordEvent(String key) {
eventQueue_.recordEvent(key);
if (eventQueue_.size() >= 10)
queue_.recordEvents(eventQueue_.events());
}
public void recordEvent(String key, int count) {
eventQueue_.recordEvent(key, count);
if (eventQueue_.size() >= 10)
queue_.recordEvents(eventQueue_.events());
}
public void recordEvent(String key, int count, double sum) {
eventQueue_.recordEvent(key, count, sum);
if (eventQueue_.size() >= 10)
queue_.recordEvents(eventQueue_.events());
}
public void recordEvent(String key, Map segmentation, int count) {
eventQueue_.recordEvent(key, segmentation, count);
if (eventQueue_.size() >= 10)
queue_.recordEvents(eventQueue_.events());
}
public void recordEvent(String key, Map segmentation, int count, double sum) {
eventQueue_.recordEvent(key, segmentation, count, sum);
if (eventQueue_.size() >= 10)
queue_.recordEvents(eventQueue_.events());
}
private void onTimer() {
if (isVisible_ == false)
return;
double currTime = System.currentTimeMillis() / 1000.0;
unsentSessionLength_ += currTime - lastTime_;
lastTime_ = currTime;
int duration = (int) unsentSessionLength_;
queue_.updateSession(duration);
unsentSessionLength_ -= duration;
if (eventQueue_.size() > 0)
queue_.recordEvents(eventQueue_.events());
}
}
class ConnectionQueue {
private CountlyStore store_;
private Thread thread_ = null;
private String appKey_;
private Context context_;
private String serverURL_;
public void setAppKey(String appKey) {
appKey_ = appKey;
}
public void setContext(Context context) {
context_ = context;
}
public void setServerURL(String serverURL) {
serverURL_ = serverURL;
}
public void setCountlyStore(CountlyStore countlyStore) {
store_ = countlyStore;
}
public void beginSession() {
String data;
data = "app_key=" + appKey_;
data += "&" + "device_id=" + DeviceInfo.getUDID();
data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
data += "&" + "sdk_version=" + "2.0";
data += "&" + "begin_session=" + "1";
data += "&" + "metrics=" + DeviceInfo.getMetrics(context_);
store_.addConnection(data);
tick();
}
public void updateSession(int duration) {
String data;
data = "app_key=" + appKey_;
data += "&" + "device_id=" + DeviceInfo.getUDID();
data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
data += "&" + "session_duration=" + (duration > 0 ? duration : Countly.SESSION_DURATION_WHEN_TIME_ADJUSTED);
store_.addConnection(data);
tick();
}
public void endSession(int duration) {
String data;
data = "app_key=" + appKey_;
data += "&" + "device_id=" + DeviceInfo.getUDID();
data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
data += "&" + "end_session=" + "1";
data += "&" + "session_duration=" + (duration > 0 ? duration : Countly.SESSION_DURATION_WHEN_TIME_ADJUSTED);
store_.addConnection(data);
tick();
}
public void recordEvents(String events) {
String data;
data = "app_key=" + appKey_;
data += "&" + "device_id=" + DeviceInfo.getUDID();
data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
data += "&" + "events=" + events;
store_.addConnection(data);
tick();
}
private void tick() {
if (thread_ != null && thread_.isAlive())
return;
if (store_.isEmptyConnections())
return;
thread_ = new Thread() {
@Override
public void run() {
while (true) {
String[] sessions = store_.connections();
if (sessions.length == 0)
break;
String initial = sessions[0], replaced = initial;
int index = replaced.indexOf("REPLACE_UDID");
if (index != -1) {
if (OpenUDID_manager.isInitialized() == false)
break;
replaced = replaced.replaceFirst("REPLACE_UDID", OpenUDID_manager.getOpenUDID());
}
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet method = new HttpGet(new URI(serverURL_ + "/i?" + replaced));
HttpResponse response = httpClient.execute(method);
InputStream input = response.getEntity().getContent();
while (input.read() != -1)
;
httpClient.getConnectionManager().shutdown();
Log.d("Countly", "ok ->" + replaced);
store_.removeConnection(initial);
} catch (Exception e) {
Log.d("Countly", e.toString());
Log.d("Countly", "error ->" + initial);
break;
}
}
}
};
thread_.start();
}
}
class DeviceInfo {
public static String getUDID() {
return OpenUDID_manager.isInitialized() == false ? "REPLACE_UDID" : OpenUDID_manager.getOpenUDID();
}
public static String getOS() {
return "Android";
}
public static String getOSVersion() {
return android.os.Build.VERSION.RELEASE;
}
public static String getDevice() {
return android.os.Build.MODEL;
}
public static String getResolution(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
return metrics.widthPixels + "x" + metrics.heightPixels;
}
public static String getDensity(Context context) {
int density = context.getResources().getDisplayMetrics().densityDpi;
switch (density) {
case DisplayMetrics.DENSITY_LOW:
return "LDPI";
case DisplayMetrics.DENSITY_MEDIUM:
return "MDPI";
case DisplayMetrics.DENSITY_TV:
return "TVDPI";
case DisplayMetrics.DENSITY_HIGH:
return "HDPI";
case DisplayMetrics.DENSITY_XHIGH:
return "XHDPI";
case DisplayMetrics.DENSITY_XXHIGH:
return "XXHDPI";
case DisplayMetrics.DENSITY_XXXHIGH:
return "XXXHDPI";
default:
return "";
}
}
public static String getCarrier(Context context) {
try {
TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return manager.getNetworkOperatorName();
} catch (NullPointerException npe) {
npe.printStackTrace();
Log.e("Countly", "No carrier found");
}
return "";
}
public static String getLocale() {
Locale locale = Locale.getDefault();
return locale.getLanguage() + "_" + locale.getCountry();
}
public static String appVersion(Context context) {
String result = "1.0";
try {
result = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
} catch (NameNotFoundException e) {
}
return result;
}
public static String getMetrics(Context context) {
String result = "";
JSONObject json = new JSONObject();
try {
json.put("_device", getDevice());
json.put("_os", getOS());
json.put("_os_version", getOSVersion());
json.put("_carrier", getCarrier(context));
json.put("_resolution", getResolution(context));
json.put("_density", getDensity(context));
json.put("_locale", getLocale());
json.put("_app_version", appVersion(context));
} catch (JSONException e) {
e.printStackTrace();
}
result = json.toString();
try {
result = java.net.URLEncoder.encode(result, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
return result;
}
}
class Event {
public String key = null;
public Map segmentation = null;
public int count = 0;
public double sum = 0;
public int timestamp = 0;
public boolean equals(Object o) {
if (o == null || !(o instanceof Event)) return false;
Event e = (Event) o;
return (key == null ? e.key == null : key.equals(e.key)) &&
timestamp == e.timestamp && (segmentation == null ? e.segmentation == null : segmentation.equals(e.segmentation));
}
}
class EventQueue {
private CountlyStore countlyStore_;
public EventQueue(CountlyStore countlyStore) {
countlyStore_ = countlyStore;
}
public int size() {
synchronized (this) {
return countlyStore_.events().length;
}
}
public String events() {
String result = "";
synchronized (this) {
List events = countlyStore_.eventsList();
JSONArray eventArray = new JSONArray();
for (Event e : events) eventArray.put(CountlyStore.eventToJSON(e));
result = eventArray.toString();
countlyStore_.removeEvents(events);
}
try {
result = java.net.URLEncoder.encode(result, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
return result;
}
public void recordEvent(String key) {
recordEvent(key, null, 1, 0);
}
public void recordEvent(String key, int count) {
recordEvent(key, null, count, 0);
}
public void recordEvent(String key, int count, double sum) {
recordEvent(key, null, count, sum);
}
public void recordEvent(String key, Map segmentation, int count) {
recordEvent(key, segmentation, count, 0);
}
public void recordEvent(String key, Map segmentation, int count, double sum) {
synchronized (this) {
countlyStore_.addEvent(key, segmentation, count, sum);
}
}
}
class CountlyStore {
private static final String TAG = "COUNTLY_STORE";
private static final String PREFERENCES = "COUNTLY_STORE";
private static final String DELIMITER = "===";
private static final String CONNECTIONS_PREFERENCE = "CONNECTIONS";
private static final String EVENTS_PREFERENCE = "EVENTS";
private SharedPreferences preferences;
protected CountlyStore(Context ctx) {
preferences = ctx.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
}
public String[] connections() {
String array = preferences.getString(CONNECTIONS_PREFERENCE, null);
return array == null || "".equals(array) ? new String[0] : array.split(DELIMITER);
}
public String[] events() {
String array = preferences.getString(EVENTS_PREFERENCE, null);
return array == null || "".equals(array) ? new String[0] : array.split(DELIMITER);
}
public List eventsList() {
String[] array = events();
if (array.length == 0) return new ArrayList();
else {
List events = new ArrayList();
for (String s : array) {
try {
events.add(jsonToEvent(new JSONObject(s)));
} catch (JSONException e) {
Log.e(TAG, "Cannot parse Event json", e);
}
}
Collections.sort(events, new Comparator() {
@Override
public int compare(Event e1, Event e2) {
return e2.timestamp - e1.timestamp;
}
});
return events;
}
}
public boolean isEmptyConnections() {
return connections().length == 0;
}
public boolean isEmptyEvents() {
return events().length == 0;
}
public void addConnection(String str) {
List connections = new ArrayList(Arrays.asList(connections()));
connections.add(str);
preferences.edit().putString(CONNECTIONS_PREFERENCE, join(connections, DELIMITER)).commit();
}
public void removeConnection(String str) {
List connections = new ArrayList(Arrays.asList(connections()));
connections.remove(str);
preferences.edit().putString(CONNECTIONS_PREFERENCE, join(connections, DELIMITER)).commit();
}
public void addEvent(Event event) {
List events = eventsList();
if (!events.contains(event)) events.add(event);
preferences.edit().putString(EVENTS_PREFERENCE, joinEvents(events, DELIMITER)).commit();
}
public void addEvent(String key, Map segmentation, int count, double sum) {
List events = eventsList();
Event event = null;
for (Event e : events) if (e.key != null && e.key.equals(key)) event = e;
if (event == null) {
event = new Event();
event.key = key;
event.segmentation = segmentation;
event.count = 0;
event.sum = 0;
event.timestamp = (int) (System.currentTimeMillis() / 1000);
} else {
removeEvent(event);
event.timestamp = Math.round((event.timestamp + (System.currentTimeMillis() / 1000)) / 2);
}
event.count += count;
event.sum += sum;
addEvent(event);
}
public void removeEvent(Event event) {
List events = eventsList();
events.remove(event);
preferences.edit().putString(EVENTS_PREFERENCE, joinEvents(events, DELIMITER)).commit();
}
public void removeEvents(Collection eventsToRemove) {
List events = eventsList();
for (Event e : eventsToRemove) events.remove(e);
preferences.edit().putString(EVENTS_PREFERENCE, joinEvents(events, DELIMITER)).commit();
}
protected static JSONObject eventToJSON(Event event) {
JSONObject json = new JSONObject();
try {
json.put("key", event.key);
json.put("count", event.count);
json.put("sum", event.sum);
json.put("timestamp", event.timestamp);
if (event.segmentation != null) {
json.put("segmentation", new JSONObject(event.segmentation));
}
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
protected static Event jsonToEvent(JSONObject json) {
Event event = new Event();
try {
event.key = json.get("key").toString();
event.count = Integer.valueOf(json.get("count").toString());
event.sum = Double.valueOf(json.get("sum").toString());
event.timestamp = Integer.valueOf(json.get("timestamp").toString());
if (json.has("segmentation")) {
JSONObject segm = json.getJSONObject("segmentation");
HashMap segmentation = new HashMap();
Iterator nameItr = segm.keys();
while (nameItr.hasNext()) {
Object obj = nameItr.next();
if (obj instanceof String) {
segmentation.put((String) obj, ((JSONObject) json.get("segmentation")).getString((String) obj));
}
}
event.segmentation = segmentation;
}
} catch (JSONException e) {
e.printStackTrace();
}
return event;
}
private static String joinEvents(Collection collection, String delimiter) {
List strings = new ArrayList();
for (Event e : collection) strings.add(eventToJSON(e).toString());
return join(strings, delimiter);
}
private static String join(Collection collection, String delimiter) {
StringBuilder builder = new StringBuilder();
int i = 0;
for (String s : collection) {
builder.append(s);
if (++i < collection.size()) builder.append(delimiter);
}
return builder.toString();
}
}