Code Monkey home page Code Monkey logo

countly-sdk-android's People

Contributors

ar2rsawseen avatar arifburakdemiray avatar arturskadikis avatar atilimcetin avatar busify avatar derekmoorecountly avatar ffleandro avatar foooorsyth avatar gokselpirnal avatar gorkem-cetin avatar ianko avatar iartem avatar ijunaid avatar intrications avatar jboehle avatar lalongooo avatar osiris86 avatar osoner avatar pembeci avatar peterbrxwn avatar qq157755587 avatar shisheng-1 avatar turtledreams avatar vishalraut20 avatar zahidzafar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

countly-sdk-android's Issues

event coalescing can cause data loss

There are several problems in the following method in the CountlyStore class:

    public void addEvent(String key, Map<String, String> segmentation, int count, double sum) {
        List<Event> 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);
    }
  1. If a "matching" event is found, since matching is only done against the key name, the new segmentation values are lost (data loss).
  2. If a "matching" event is found, the timestamp is adjusted to be the mean of the new event and the old event, leading to loss of actual event timestamps (data loss). The server would have no idea if an event was repeated one second apart or 59 seconds apart.

I don't think that event coalescing is necessary. I think data accuracy is more important than coalescing events. If the desire is to potentially reduce the network traffic, a more compact Event JSON format could be used (for instance, keep an array of {timestamp,count,sum} per unique combo of event key/segmentation).

provide jar without OpenUDID

It would be nice to provide a jar with each release that does not have OpenUDID. This would be helpful to developers that already have OpenUDID elsewhere in their project, and also to developers that don't use OpenUDID. Right now both of those cases would have to build from source.

too many sessions

I hosted a countly server on EC2, and I integrated client in my apk, it's just one page app, but there are 3000+ users, but it creates millions of sessions, is it wrong or can I reduce it?

no JavaDoc

Being an open-source project, Countly would benefit a lot from having a complete set of JavaDoc for both the public API and the internal implementation classes.

Having JavaDoc for the public API helps SDK users, and having JavaDoc for the internal implementation classes can help anyone that is trying to change code in the SDK.

Change GCM registration ID whenever sender ID changed

From @hupptech: I mentioned wrong implementation when you get registerId from GCM server. What I mean: when you send register request to GCM server, it returns you some unical register id. This register id is persistent and you save it in prefs. For future calls you check prefs, and if that register id exists in prefs, you return it. Trouble is next: when you change GCM application number (from 12345678 to 54543543, for example), you don’t register again. You use old register id. I found this trouble during debugging. I entered wrong project id, after it changed it to right. But app didn’t work, server returns me MismatchSenderId. Code example below:

public static void init(Activity activity, Class<? extends Activity> activityClass, String sender, String[] buttonNames) {
        ...    
        if (checkPlayServices(activity) ) {
            gcm = GoogleCloudMessaging.getInstance(activity);
            String registrationId = getRegistrationId(activity);
            if (registrationId.isEmpty()) {
                registerInBackground(activity, sender);
            } else {
        //In this place you send obsolete register id, because in getRegistrationId you return previously saved register id
                Countly.sharedInstance().onRegistrationId(registrationId);
            }
        } else {
            ...    
    }

My suggestion for this case - always call send registerInBackground() method, don’t check if register id exists. From other side you can check if project number was changed, but it’s harder.

android.content.res.Resources$NotFoundException

In CountlyMessaging.java

String label = context.getString(context.getApplicationInfo().labelRes);

Throws android.content.res.Resources$NotFoundException if the string is not found

It would be great to add a catch in there to catch that exception and maybe log something like below.
I think that will be very helpful to the user.

Log.w(TAG, "Application name not found - Set android:label='@string/app_name' in AndroidManifest.xml`s <application> section");

Incorrect handling of empty review message

You incorrect handle empty review message. I mean case when “c.r” exists, but has empty value. Your code:

    …
public String getReview() { return data.getString("c.r"); }
…
private int setType() {
        int t = CountlyMessaging.NOTIFICATION_TYPE_UNKNOWN;
    …
    //Sometimes getReview() can return empty value. In this case you will not handle this situation properly, you code will think that current message in plain text. Now you can’t set custom Review Package. It means you send empty “c.r”. It means you can’t send review push request at all
        if (getReview() != null && !"".equals(getReview())) {
            t |= CountlyMessaging.NOTIFICATION_TYPE_REVIEW;
        }
    ...
        return t;
    }
public Intent getIntent(Context context, Class <? extends Activity> activityClass) {
        …
        } else if (hasReview()) {
    //You always send current package. But we should send package from “c.r” also
            return new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + context.getPackageName()));
        } 
...
    }

no validation/sanitation of input data or internal state

Throughout the SDK API and the internal implementation, there is very little validation or sanitation of input data or internal state. For example:

  • in Countly.onStop, there is no protection against activityCount_ going negative
  • no validation that Countly.init has been called before proceeding in onStart/onStop/recordEvent/etc., resulting in NPE, a proper exception and error message would help new developers that make silly mistakes
  • Countly.recordEvent does not validate that key is null, empty, or contains other text that may cause problems on the server or in MongoDB

These are just a few examples, this is an area that really needs to be beefed up.

no unit tests

Being an open-source project, Countly would benefit a lot from having a complete set of unit tests.

Having such test suites would encourage the open-source community to actually add new features or refactor existing features knowing that they won't break any expected functionality.

use constants instead of magic values

There are several places in the SDK where magic values are used instead of a proper static constant variable. For example, in the Countly class, the magic value of 10 is used in several methods:

    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<String, String> segmentation, int count) {
        eventQueue_.recordEvent(key, segmentation, count);

        if (eventQueue_.size() >= 10)
            queue_.recordEvents(eventQueue_.events());
    }

    public void recordEvent(String key, Map<String, String> segmentation, int count, double sum) {
        eventQueue_.recordEvent(key, segmentation, count, sum);

        if (eventQueue_.size() >= 10)
            queue_.recordEvents(eventQueue_.events());
    }

It would be better to define a static final int in the Countly class with a descriptive name, like EVENT_QUEUE_SIZE_THRESHOLD.

Magic values are also used to initialize the timer, the default app version if one is not found, the SDK version, JSON field names, etc.

Update README.md

  • With Maven / Gradle Instructions.
  • Link directly to .jar file.
  • Licence

lack of synchronization in CountlyStore could cause data loss

Currently the CountlyStore class uses two String fields in a SharedPreferences object to persist queued events and connections on the local device. Right now there is no synchronization in the CountlyStore class (or at the right places above it in the call chain), which could potentially lead to data loss. I will provide a couple of examples where this could happen.

Example 1:
There are two threads, the timer background thread (TIMER) and a background thread (BG) created by ConnectionQueue to process connections. The following operations could occur:

  1. BG - finishes processing a connection and calls CountlyStore.removeConnection, which retrieves the connections, converts them into a List, removes one from the list, but before it can edit() and commit() the changed list, simultaneously on the TIMER thread...
  2. TIMER - the timer background thread is triggered, causing ConnectionQueue.updateSession to be called, which in turn calls CountlyStore.addConnection, which retrieves the connections, converts them into a List, adds to the list, and does edit() and commit() to commit the new connection to the SharedPreferences, then...
  3. BG - CountlyStore.removeConnection continues and does it's edit() and commit(), but the list that it is going to commit does not have the new connection added by the TIMER thread, because the BG thread retrieved the list of connections it is modifying before the TIMER thread added it's connection. Now when BG does edit() and commit(), it will have removed the connection that it was supposed to, but it will have overwritten the list of connections containing the new connection that TIMER thread added, resulting in data loss.

Example 2:
There are two threads, the MAIN app thread, and a background thread (BG) created by ConnectionQueue to process connections. The following operations could occur:

  1. BG - finishes processing a connection and calls CountlyStore.removeConnection, which retrieves the connections, converts them into a List, removes one from the list, calls edit() and putString(), but before commit() happens, simultaneously on the MAIN thread...
  2. MAIN - app calls recordEvent to record a custom event, which eventually results in CountlyStore.addEvent(Event) being called, which goes ahead and does an edit() and commit() to commit it's event to the SharedPrefs.
  3. BG - now finishes and does it's commit(), but since two editors were open at the same time, the last one to call commit wins, meaning the custom event that was added on the MAIN thread will actually be discarded, resulting in data loss.

These are just a couple of examples of race conditions that could occur in the CountlyStore class resulting in data loss.

Provide a way to supply your own UDID

To initialize Countly, there's this method
public void init(Context context, String serverURL, String appKey) {

Then Countly uses OpenUDID to get a UDID.

What do you think of letting user supply their own UDID?
overload init method to take an optional user supplied UDID.
public void init(Context context, String serverURL, String appKey, String udid) {

Details:
We have our own UDID implementation, and would like to use this instead of relying on OpenUDID.

Escape quote to avoid sql syntax error

We are hitting this kind of syntax error cause one of our data contains sometimes a simple quote.

near "Hospitalet": syntax error (code 1): , while compiling: INSERT 
OR REPLACE INTO EVENTS(ID, EVENT) VALUES(1, '{"events":
[{"timestamp":1395100544,"sum":0,"segmentation":{},"count":1,"key":"event_1"},
{"timestamp":1395100544,"sum":0,"segmentation":{},"count":1,"key":"event_2"},
{"timestamp":1395100544,"sum":0,"segmentation":{},"count":1,"key":"event_3"},{"timestamp":1395100544,"sum":0,"segmentation":
{"channel":"user_100000639993622"},"count":1,"key":"debug - User subscribed to Parse 
channel"},{"timestamp":1395100544,"sum":0,"segmentation":
{"os":"android","gender":"male","appVersion":"2.0.11","location":"L'Hospitalet De 
Llobregat, Cataluna, Spain","age":"33"},"count":1,"key":"user created"}]}');

Full backtrace here

android.database.sqlite.SQLiteConnection.nativePrepareStatement (SQLiteConnection.java)
android.database.sqlite.SQLiteDatabase.execSQL (SQLiteDatabase.java:1622)
ly.count.android.api.CountlyDB.saveEvents (Countly.java:646)
ly.count.android.api.EventQueue.recordEvent (Countly.java:496)
ly.count.android.api.Countly.recordEvent (Countly.java:127)

Could you escape quote in strings before insert in the sqlite table ?

Regards,

beef up error handling throughout SDK

Throughout the SDK, the error handling is often poor. Sometimes exceptions are ignored, sometimes they are logged, but very rarely is anything done to properly handle the error. For instance:

  • In CountlyStore.eventsList, a JSONException is caught and logged. If there is an event in the list that cannot be parsed into a JSONObject, shouldn't it be removed from the list? If this is not a possibility, put a comment in the throws that it can never happen.
  • In CountlyStore.eventToJSON, a JSONException is caught and the stack trace is printed. Elsewhere in the SDK, Log is used, it should be consistent, either Log or print stack trace. After the exception is caught, the JSONObject is returned anyways, even though it might not actually contain all of the event data. I did some more investigation on this and the only thing that can throw here would be putting the sum field in as NaN/infinity. Maybe that should be the last thing put in, so if it throws, at least the Event has the rest of the data.
  • In DeviceInfo.appVersion, an exception is just ignored. In this case it would be good to log a warning message that might help the SDK user figure out why their app is always being reported as version "1.0".
  • In DeviceInfo.getCarrier, the stack trace of the NPE is printed. This should not be printed as it is not an error, the app may not have asked for Telephony permission. Maybe a warning log message would be more helpful to the SDK user.
  • In the background thread created by ConnectionQueue, there is no finally clause to make sure that any open streams or connections are closed/shutdown.

These are just a few examples.

NullPointerException in ly.count.android.api.DeviceInfo.getResolution

I got some NullPointerException on certain devices.

Caused by: java.lang.NullPointerException
at ly.count.android.api.DeviceInfo.getResolution(Unknown Source)
at ly.count.android.api.DeviceInfo.getMetrics(Unknown Source)
at ly.count.android.api.ConnectionQueue.beginSession(Unknown Source)
at ly.count.android.api.Countly.onStartHelper(Unknown Source)
at ly.count.android.api.Countly.onStart(Unknown Source)
at br.com.verde.alarme.Alarme.onStart(Alarme.java:394)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1166)
at android.app.Activity.performStart(Activity.java:5285)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2058)

image

Too many sessions were created by each device.

Hello, contributers:

I have a problem, the part of devices create two many sessions.

Enveronment:
      countly:14.12
      compileSdkVersion 19
      buildToolsVersion '22'

This is the statisticcal content by countly server in a half day.
Device-------------Total Sessions-----Total Users----New Users
D5833-------------------9,600----------------1------------------0
A 9-----------------------8,741----------------1------------------0
HTC Incredible S------6,645----------------1------------------0
HTC M8w ---------------5,232----------------1------------------0

Cannot create Device ID.

Hi, I have an problem with Countly SDK. Cannot get device id on SamSung Galaxy Y, Android 2.3.3. Why?
No Device ID available yet, skipping request app_key=d63dd2c4e075961fa65e37674a109cfdb7d7eeab&timestamp=1420634252&sdk_version=14.11&begin_session=1&metrics=%7B%22_locale%22%3A%22vi_VN%22%2C%22_app_version%22%3A%224.4.7%22%2C%22_device%22%3A%22GT-S5360%22%2C%22_resolution%22%3A%22320x240%22%2C%22_os_version%22%3A%222.3.6%22%2C%22_os%22%3A%22Android%22%2C%22_carrier%22%3A%22VINAPHONE%22%2C%22_density%22%3A%22LDPI%22%7D

Crash Test

Hey,

It would be good to add some crash tests as in iOS SDK

Here are some I have used in my Titanium module..

public void stackOverflow() {
          this.stackOverflow();
}

        public void crashTest(int crashNumber) {

            if (crashNumber == 1){
                Log.d(LCAT, "Running crashTest 1");         

                stackOverflow();

            }else if (crashNumber == 2){

                Log.d(LCAT, "Running crashTest 2");

                int test = 10/0;

            }else if (crashNumber == 3){

                Log.d(LCAT, "Running crashTest 3");

                    Object[] o = null;
                    while (true) { o = new Object[] { o }; }


            }else{

                Log.d(LCAT, "Running crashTest 4");

                throw new RuntimeException("This is a crash");
            }


        }   

use braces around all conditional & loop statements

Throughout the SDK, many single-line conditionals and loops do not have braces around them, like:

if (activityCount_ == 0)
    onStopHelper();

Every conditional and loop should use braces, in order to help cause less maintenance issues when the code is modified in the future.

getting Google ADVERTISING_ID from countly android sdk

how can i get device Google ADVERTISING_ID from countly android sdk.
from the doc i found that :
You can rely on Google Advertising ID for device ID generation:
Countly.sharedInstance().init(this, "https://YOUR_SERVER", "YOUR_APP_KEY", null, DeviceId.Type.ADVERTISING_ID)

but when i tried to get ADVERTISING_ID in sdk i always get null:
DeviceId did= new DeviceId(DeviceId.Type.ADVERTISING_ID);
String Adid=did.getId();

what will be best way to get ADVERTISING_ID at runtime from sdk.

server response code/body is not checked for success before deleting connections

In the thread that ConnectionQueue starts, after submitting a connection to the server and reading the response, the HTTP response code is not checked for success (2xx), and the response body is not verified to have returned {"result":"Success"} before deleting the connection from the local connection queue, which may result in data loss.

While in some cases the HTTP client methods may throw on a non-2xx response code, that may not always be the case. With the potential for putting another server (nginx, etc.) in front of a Countly server, there certainly exists the possibility to get 2xx response code but not the correct JSON response indicating success (maybe the Countly server is down and the web server has not been configured to properly handle that case, etc.).

The fact that this could cause client-side data loss is a serious bug.

No such table: CONNECTIONS (code 1): , while compiling: INSERT INTO CONNECTIONS(CONNECTION)

I'm hitting this error:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp/com.myapp.activities.MainActivity_}: android.database.sqlite.SQLiteException: no such table: CONNECTIONS (code 1): , while compiling: INSERT INTO CONNECTIONS(CONNECTION) VALUES('values_hidden');
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2653)
       at android.app.ActivityThread.access$800(ActivityThread.java:156)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1355)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:157)
       at android.app.ActivityThread.main(ActivityThread.java:5872)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1069)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:885)
       at dalvik.system.NativeStart.main(NativeStart.java)
Caused by: android.database.sqlite.SQLiteException: no such table: CONNECTIONS (code 1): , while compiling: INSERT INTO CONNECTIONS(CONNECTION) VALUES('values_hidden');
       at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
       at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:917)
       at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:528)
       at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
       at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
       at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
       at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1728)
       at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1659)
       at ly.count.android.api.CountlyDB.offer(Countly.java:572)
       at ly.count.android.api.ConnectionQueue.beginSession(Countly.java:182)
       at ly.count.android.api.Countly.onStartHelper(Countly.java:86)
       at ly.count.android.api.Countly.onStart(Countly.java:74)
       at com.myapp.activities.MainActivity.onStart(MainActivity.java:173)

onCreate(SQLiteDatabase db) method sounds like not called so i checked this post : http://stackoverflow.com/questions/19266804/erro-sqlite-database-oncreate but found nothing wrong with your code.

public void offer(String data) {
    SQLiteDatabase db = this.getWritableDatabase();
    db.execSQL("INSERT INTO " + CONNECTIONS_TABLE_NAME + "(CONNECTION) VALUES('" + data + "');");
    Log.d("Countly", "Insert into " + CONNECTIONS_TABLE_NAME + ": " + data);
}

Any idea ?

Create Library JAR

You should add an ant script to generate a JAR and add each release generated jar to the downloads page, instead of giving the whole project to download (if I want the whole project I can checkout from github).

If I want to use the countly-android-sdk in my project, I shouldn't have to copy your classes to my project, or create a project with your code and add it as a dependency to my project. That's what JARs are for.

no timeout set for network operations

In the thread that uses DefaultHttpClient, no connect or read timeouts are set up. Unfortunately the default timeouts are set to 0, meaning that connect and read operations could potentially wait forever to complete. This could really be a problem particularly since the ConnectionQueue only allows one background thread at a time to run. If one never completes, data may not get sent until the app is restarted.

Fix update push notification

There is no support for Update push notification in Android right now. We'll need to make behavior more consistent between iOS & Android on this.

Ensure 14.07 branch tests are passed

There are some failing tests in ConnectionProcessorTests:
testRun_storeHasSingleConnection
testRun_storeHasSingleConnection_butHTTPResponseCodeWasNot2xx
testRun_storeHasSingleConnection_butResponseJSONWasNotSuccess
testRun_storeHasSingleConnection_butResponseWasNotJSON
testRun_storeHasSingleConnection_successCheckIsCaseInsensitive
testRun_storeHasTwoConnections
testRun_storeHasTwoConnections_butFirstOneThrowsWhenInputStreamIsRead

Null Pointer in getMetrics

A small percentage of our users are encountering a crash in the onStart calls. Below is a sample stack trace. Most of our users do not encounter this. For the activity in the trace below, it wouldn't have been the first Activity to call onStart either.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.alamode.totalmobile/com.alamode.totalmobile.fileeditor.FileEditorActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access$600(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at ly.count.android.api.DeviceInfo.getCarrier(Countly.java:331)
at ly.count.android.api.DeviceInfo.getMetrics(Countly.java:362)
at ly.count.android.api.ConnectionQueue.beginSession(Countly.java:191)
at ly.count.android.api.Countly.onStartHelper(Countly.java:90)
at ly.count.android.api.Countly.onStart(Countly.java:76)
at com.alamode.totalmobile.fileeditor.FileEditorActivity.onStart(FileEditorActivity.java:244)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
at android.app.Activity.performStart(Activity.java:5143)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
... 11 more

When is the 15.03 release out? Publish artifacts to jcenter?

Hi.
We have an enterprise license and I'm upgrading the countly library for our app to the latest version, but the documentation doesn't make it clear to build it from source or what else. (We can only use a released version instead of development tip so we keep track of dependencies)
http://resources.count.ly/v1.0/docs/downloading-sdks

The latest release on this github project is 14.11 released on Nov 7, 2014.
However in https://github.com/Countly/countly-sdk-android/blob/master/sdk/build.gradle
it mentions a newer version 15.03 but it is not available either on jcenter or maven central.

Question 1:
Are you planning to release 15.03 soon?
Question 2:
Are you going to publish artifacts to jcenter or maven central?

Thanks,
David.

Database Object Not Close Exception

When i exit and then re-enter my app, I get the following error in the stack. Do I need some Countly code when existing application? This is not mentionned in the small guide.

02-18 15:35:18.290 6645-6654/com.devrap.app E/SQLiteDatabase﹕ close() was never explicitly called on database '/data/data/com.devrap.app/databases/countly'
android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
at android.database.sqlite.SQLiteDatabase.(SQLiteDatabase.java:2072)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1126)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1083)
at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1170)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:844)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:228)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:157)
at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:231)
at ly.count.android.api.CountlyDB.getEvents(Countly.java:596)
at ly.count.android.api.EventQueue.(Countly.java:378)
at ly.count.android.api.Countly.init(Countly.java:75)
at com.devrap.app.analytix.AnalytixHelper.init(AnalytixHelper.java:39)
at com.devrap.app.FormActivity.onCreate(FormActivity.java:208)
at android.app.Activity.performCreate(Activity.java:4470)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1052)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1931)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1992)
at android.app.ActivityThread.access$600(ActivityThread.java:127)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1158)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4511)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:986)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:753)
at dalvik.system.NativeStart.main(Native Method)
02-18 15:35:18.290 6645-6654/com.devrap.app E/System﹕ Uncaught exception thrown by finalizer
02-18 15:35:18.300 6645-6654/com.devrap.app E/System﹕ java.lang.IllegalStateException: Don't have database lock!
at android.database.sqlite.SQLiteDatabase.verifyLockOwner(SQLiteDatabase.java:2230)
at android.database.sqlite.SQLiteDatabase$1.entryRemoved(SQLiteDatabase.java:2322)
at android.database.sqlite.SQLiteDatabase$1.entryRemoved(SQLiteDatabase.java:2318)
at android.util.LruCache.trimToSize(LruCache.java:197)
at android.util.LruCache.evictAll(LruCache.java:285)
at android.database.sqlite.SQLiteDatabase.deallocCachedSqlStatements(SQLiteDatabase.java:2283)
at android.database.sqlite.SQLiteDatabase.closeClosable(SQLiteDatabase.java:1255)
at android.database.sqlite.SQLiteDatabase.finalize(SQLiteDatabase.java:2043)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:185)
at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:168)
at java.lang.Thread.run(Thread.java:856)

lack of synchronization in session time tracking could cause corrupted session duration

In the Countly class, the onStartHelper/onTimer/onStopHelper methods all read and/or write the unsentSessionLength_ member variable (it's a double). Most likely, all calls to onStart & onStop will happen on the main app thread, but all calls to onTimer may happen on a background thread (the documentation is not completely clear on this). Additionally, there is no enforcement in any of these methods to guarantee they are all executed on the main thread. This can result in multiple threads modifying the unsentSessionLength_ member at the same time, with no locking/synchronization. I don't think the JVM makes any guarantees in this situation, which means it may end up that one thread reads a stale value, resulting in incorrect session length being calculated or sent to the server, or at the worst, the value in the variable is corrupted, again resulting in bad data sent to the server.

This may be a contributor to the negative session duration bug.

Simplify UDID/Device ID retrival

I tested that OpenUDID_manager.getOpenUDID() returns the same device id as the standard way to get device id:

import android.provider.Settings;
Settings.Secure.getString(ctx.getContentResolver(), Settings.Secure.ANDROID_ID)

Is there any good reason to use org.openudid.OpenUDID_service at all?

Can't recordEvent!

Hi,
Please check your recordEvent (), can not be recorded.

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Countly.sharedInstance().init(this, "http://192.168.2.114",
                "a2b84e7f652596904bba54e5199cc632d53f0d39");


        findViewById(R.id.button1).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
        findViewById(R.id.button3).setOnClickListener(this);
        findViewById(R.id.button4).setOnClickListener(this);
        findViewById(R.id.button5).setOnClickListener(this);


         segmentation = new HashMap<String, String>();
    }
@Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button1:
            Countly.sharedInstance().recordEvent("purchase1");
            startActivity(new Intent(this, CountlyActivity.class));
            break;
        case R.id.button2:
            Countly.sharedInstance().recordEvent("purchase2", count);
            break;
        case R.id.button3:
            Countly.sharedInstance().recordEvent("purchase3", count, 100);
            break;
        case R.id.button4:
            segmentation.put("btn4", "btn4");
            Countly.sharedInstance().recordEvent("purchase4", segmentation, count);
            break;
        case R.id.button5:
            Countly.sharedInstance().recordEvent("purchase5", segmentation, count,100);

            break;

        default:
            break;
        }
    }

SSL Certificate pinning broken for Android 5+

CertificateTrustManager.checkServerTrusted() expects authType to be RSA, but starting with Android 5+,

        if (!(null != authType && authType.equalsIgnoreCase("RSA"))) {
            throw new CertificateException("PublicKeyManager: AuthType is not RSA");
        }

See comment in: http://developer.android.com/about/versions/android-5.0-changes.html#ssl

App is making wrong assumptions about cipher suites used to connect to server
For example, some apps contain a custom X509TrustManager that breaks because it expects the authType parameter to be RSA but encounters ECDHE_RSA or DHE_RSA.

Exception stack trace:

01-05 14:18:08.777 22583 22600 W Countly : javax.net.ssl.SSLHandshakeException: PublicKeyManager: AuthType is not RSA
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:328)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:103)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.Connection.connect(Connection.java:143)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:185)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:433)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:114)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java)
01-05 14:18:08.777 22583 22600 W Countly :  at ly.count.android.sdk.ConnectionProcessor.run(ConnectionProcessor.java:175)
01-05 14:18:08.777 22583 22600 W Countly :  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
01-05 14:18:08.777 22583 22600 W Countly :  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
01-05 14:18:08.777 22583 22600 W Countly :  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
01-05 14:18:08.777 22583 22600 W Countly :  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
01-05 14:18:08.777 22583 22600 W Countly :  at java.lang.Thread.run(Thread.java:818)
01-05 14:18:08.777 22583 22600 W Countly : Caused by: java.security.cert.CertificateException: PublicKeyManager: AuthType is not RSA
01-05 14:18:08.777 22583 22600 W Countly :  at ly.count.android.sdk.CertificateTrustManager.checkServerTrusted(CertificateTrustManager.java:55)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:117)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:556)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
01-05 14:18:08.777 22583 22600 W Countly :  at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
01-05 14:18:08.777 22583 22600 W Countly :  ... 17 more

Not allowed to bind to service Intent

A small number of our users are encountering crash do to an " Not allowed to bind to service Intent" in Count.ly.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.alamode.totalmobile/com.alamode.totalmobile.landing.FilesActivity}: java.lang.SecurityException: Not allowed to bind to service Intent { cmp=com.drippler.android.updates/.utils.openudid.OpenUDIDService }
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2110)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135)
at android.app.ActivityThread.access$700(ActivityThread.java:143)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1241)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4950)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.SecurityException: Not allowed to bind to service Intent { cmp=com.drippler.android.updates/.utils.openudid.OpenUDIDService }
at android.app.ContextImpl.bindService(ContextImpl.java:1326)
at android.app.ContextImpl.bindService(ContextImpl.java:1300)
at android.content.ContextWrapper.bindService(ContextWrapper.java:401)
at org.OpenUDID.OpenUDID_manager.startService(OpenUDID_manager.java:107)
at org.OpenUDID.OpenUDID_manager.sync(OpenUDID_manager.java:170)
at ly.count.android.api.Countly.init(Countly.java:66)
at com.alamode.totalmobile.landing.FilesActivity.onCreate(FilesActivity.java:69)
at android.app.Activity.performCreate(Activity.java:5179)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2074)
... 11 more

Can't record Event!

Hi,
Please check your recordEvent (), can not be recorded.

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Countly.sharedInstance().init(this, "http://192.168.2.114",
                "a2b84e7f652596904bba54e5199cc632d53f0d39");


        findViewById(R.id.button1).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
        findViewById(R.id.button3).setOnClickListener(this);
        findViewById(R.id.button4).setOnClickListener(this);
        findViewById(R.id.button5).setOnClickListener(this);


         segmentation = new HashMap<String, String>();
    }
@Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button1:
            Countly.sharedInstance().recordEvent("purchase1");
            startActivity(new Intent(this, CountlyActivity.class));
            break;
        case R.id.button2:
            Countly.sharedInstance().recordEvent("purchase2", count);
            break;
        case R.id.button3:
            Countly.sharedInstance().recordEvent("purchase3", count, 100);
            break;
        case R.id.button4:
            segmentation.put("btn4", "btn4");
            Countly.sharedInstance().recordEvent("purchase4", segmentation, count);
            break;
        case R.id.button5:
            Countly.sharedInstance().recordEvent("purchase5", segmentation, count,100);

            break;

        default:
            break;
        }
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.