Coder Social home page Coder Social logo

atinternet-android-sdk's Introduction

AT Internet Android SDK

The AT Internet tag allows you to follow your users activity throughout your application’s lifecycle. To help you, the tag makes available classes (helpers) enabling the quick implementation of tracking for different application events (screen loads, gestures, video plays…)

Content

  • Tag Android

How to get started

  • Install our library on your project (see below)
  • Check out the documentation page for an overview of the functionalities and code examples

Manual integration

Find the integration information by following this link

Installation with Gradle

Gradle can restore 3rd-party libraries in your projects.

Dependency

In your build.gradle module, add in dependencies block :

implementation 'com.atinternet:Tracker:2.X.X' /// >= 2.14.0

License

MIT

atinternet-android-sdk's People

Contributors

nsagnett avatar piano-analytics avatar ubaggeler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

atinternet-android-sdk's Issues

NullPointerException

Hi,
We are using the latest version "2.21.0".
But we still have that issue

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.atinternet.tracker.Debugger$DebuggerEventListAdapter.notifyDataSetChanged()' on a null object reference at com.atinternet.tracker.Sender$2.run(Core.java:835) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Clearly that is an internal problem.

Hits are not being sent anymore but stored into database

We recently became aware of a problem where the AT Internet backend is receiving less and less traffic from our Android app. The traffic continuously decreased after upgrading to SDK version 2.12.1. Investigating this problem further revealed a serious issue regarding the implementation of the offline mode.

A change in version 2.12.0 (6e598ee) introduced a bug which resulted in hits being stored erroneously to the database, even for trackers configured with storage: never (which is the default case). This could happen once the network connectivity was determined to be offline while trying to send a hit. From then on, all future hits (View, Click,...) were never sent to the backend anymore but only stored to the local database (even if network connectivity was back online).

This issue was partially rectified in version 2.13.1 with commit 612c5fe, but unfortunately only for apps which did not have any hits stored in the database until then. For apps with offline hits stored in the database, all new hits are still being added to the database and not sent to the backend.

TLDR: From version 2.12.0 up to 2.13.1, trackers configured with storage: never are not sending hits anymore if the device was offline during the time when at least one hit was being sent. This was only fixed partially in 2.13.1, namely for apps without offline hits during the use of the previous SDK version.

setup Debugger for React Native

Hi @nsagnett ,

I'm using AtInternet Android for a react-native project (a jar file which I receive from my client). I want to use Debugger to log all taggings. I follow the instruction but in the react-native app, it doesn't use setContentView(R.layout.activity_main) method. And if I don't use setContentView method in onCreate() function, the app will crash. So I wonder how to use Debugger without using setContentView?
Could you have any solutions for me?

PS: I'm a frontend developer, I don't have experience with Android. So let me know if I have anything wrong.

Thanks.

ConcurrentModificationException

Just got this crash report in the console - any suggestions on this? Is this an internal problem or is there something wrong with the api call? Thanks.

java.util.ConcurrentModificationException:
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry (LinkedHashMap.java:346)
at java.util.LinkedHashMap$EntryIterator.next (LinkedHashMap.java:375)
at java.util.LinkedHashMap$EntryIterator.next (LinkedHashMap.java:375)
at java.util.HashMap.constructorPutAll (HashMap.java:208)
at java.util.LinkedHashMap. (LinkedHashMap.java:133)
at com.atinternet.tracker.Builder. (Core.java:280)
at com.atinternet.tracker.Dispatcher.dispatch (Core.java:969)
at com.atinternet.tracker.AbstractScreen.sendView (AbstractScreen.java:271)

Crash when initializing sdk using android 11 with mobile data on

We have integrated this sdk in our app. We recently updated targetSdk to 30 and we experience crashes for android 11 devices:
This is reproducible on android 11 emulator:

  • Only mobile data on (wifi off)
  • Initialize xiti
  • App crashes

Stacktrace

     Caused by: java.lang.SecurityException: getDataNetworkTypeForSubscriber
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2373)
        at android.os.Parcel.createException(Parcel.java:2357)
        at android.os.Parcel.readException(Parcel.java:2340)
        at android.os.Parcel.readException(Parcel.java:2282)
at com.android.internal.telephony.ITelephony$Stub$Proxy.getNetworkTypeForSubscriber(ITelephony.java:8762)
        at android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:3021)
        at android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:2985)
        at com.atinternet.tracker.TechnicalContext.getConnection(Core.java:1124)
        at com.atinternet.tracker.Sender.isNetworkOnline(Core.java:789)
        at com.atinternet.tracker.Sender.sendOfflineHits(Core.java:758)
        at com.atinternet.tracker.Offline.dispatch(Offline.java:107)
        .....

It seems that TelephonyManager.getNetworkType is deprecated and the suggestion is to use getDataNetworkType() instead.

Add a method to hide the debugger view

Hi,

This more a (small) feature request than an issue :
Could you add a method to your Debugger class singleton to hide the debugger view ?

Thank you !

Feature request: be able to specify localhost with port as endpoint using config

As a developer, I would like to be able to direct the ATI library's network requests to e.g. https://localhost:9000/endpoint so that I can write instrumented end-to-end tests that use a mock HTTP server on the device and verify that the right calls are made.

In the documentation for Configuration, it appears that we can set subdomain, domain and path in order to achieve this.

However:

  • It would be good to be able to omit subdomain, perhaps by specifiying an empty string as log or logSSL. Currently this seems to stop production of all requests, and it looks like the code in Builder will always add a period separator, so that's probably why. To send to localhost we would therefore have to use a workaround with a subdomain of 127 and a domain of 0.0.1.

  • It would be good to be able to specify a port. This is not currently a documented option in config.

Thanks!

Crash when sending video resume

We're getting this exception when a video is resumed after being paused:

Non-fatal Exception: java.lang.IllegalArgumentException
       at java.util.concurrent.ScheduledThreadPoolExecutor.scheduleWithFixedDelay(ScheduledThreadPoolExecutor.java:583)
       at java.util.concurrent.Executors$DelegatedScheduledExecutorService.scheduleWithFixedDelay(Executors.java:654)
       at com.atinternet.tracker.RichMedia.processSendPlayWithRefresh(RichMedia.java:436)
       at com.atinternet.tracker.RichMedia.sendResume(RichMedia.java:363)

Here's the issue:

// Démarrage du refresh avec le premier intervalle
int rd = refreshDurationsSparseIntArray.valueAt(currentRefreshDurationsSparseArrayIndex);
refreshHandler = scheduler.scheduleWithFixedDelay(refreshRunnable, rd, rd, TimeUnit.SECONDS);

currentRefreshDurationsSparseArrayIndex points to an invalid index for some reason

We have more than 42.000 non-fatal errors on all devices and had to wrap sendResume inside a try catch block to avoid crashing the app.

App crashes sometimes when onResume() is called

The app crashes sometimes because of a missing Null check:

Debugger.java

public static void setViewerVisibility(boolean visible) {
        if (bubbleImage != null) {
            bubbleVisibility = visible ? View.VISIBLE : View.GONE;
            bubbleImage.get().setVisibility(bubbleVisibility);
        }
 }

should be

if (bubbleImage != null && bubbleImage.get() != null) {
            bubbleVisibility = visible ? View.VISIBLE : View.GONE;
            bubbleImage.get().setVisibility(bubbleVisibility);
        }

Stacktrace:
java.lang.RuntimeException: Unable to resume activity: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.atinternet.tracker.ATImageView.setVisibility(int)' on a null object reference
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3403)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3434)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1493)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.atinternet.tracker.ATImageView.setVisibility(int)' on a null object reference
at com.atinternet.tracker.Debugger.setViewerVisibility(Debugger.java:171)
at com.atinternet.tracker.TrackerActivityLifeCycle.onActivityResumed(CoreFeatures.java:452)
at android.app.Application.dispatchActivityResumed(Application.java:232)
at android.app.Activity.onResume(Activity.java:1294)
at android.support.v4.app.FragmentActivity.onResume(FragmentActivity.java:485)
at roboguice.activity.RoboActionBarActivity.onResume(RoboActionBarActivity.java:112)
at ....activities.ABaseActivity.onResume(ABaseActivity.java:179)
at ....activities.MainActivity.onResume(MainActivity.java:215)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1255)
at android.app.Activity.performResume(Activity.java:6412)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3392)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3434)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1493)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)

'A connection was leaked' warning

We're getting warnings about connection leaks in OkHttpClient when using this SDK.

2020-01-06 14:25:42.309 8131-8616/com.atinternet W/OkHttpClient: A connection to https://logs.xiti.com/ was leaked. Did you forget to close a response body?

  • Warning occurs in the TestApp and our own apps
  • Warning seems to occur on certain devices (not all)

Tested with

  • Version 2.12.0 and 2.14.0
  • Huawei P20 Lite (ANE-LX1, Android 8.0)

Documentation

Links for documentation and integration instructions are 403 Forbidden pages.

AAR contains unnecessary resources

Hi, the AAR artifact you provide through maven contains a lot of useless resources (around half of its size):

  • 270K of fonts that appears to be unused
  • ~50K of res/layout for debug purposes

Could you do some cleanup and/or provide release & debug variants containing only the necessary bits?

🙏 Thanks


FYI: here is a dump of Tracker-2.21.2.aar:

[603K]  .
├── [ 331]  AndroidManifest.xml
├── [ 524]  META-INF
│   └── [ 428]  com
│       └── [ 332]  android
│           └── [ 236]  build
│               └── [ 140]  gradle
│                   └── [  44]  aar-metadata.properties
├── [ 11K]  R.txt
├── [270K]  assets
│   └── [270K]  fonts
│       ├── [ 29K]  Montserrat-Bold.ttf
│       ├── [ 28K]  Montserrat-Regular.ttf
│       └── [212K]  OpenSans-Regular.ttf
├── [282K]  classes.jar
├── [  64]  drawable
├── [  64]  fonts
├── [  64]  layout
├── [  67]  proguard.txt
├── [ 39K]  res
│   ├── [ 25K]  drawable
│   │   ├── [1.4K]  adtracking48.png
│   │   ├── [4.3K]  atinternet_logo.png
│   │   ├── [ 564]  audio.png
│   │   ├── [1.8K]  back64.png
│   │   ├── [1.6K]  database64.png
│   │   ├── [ 638]  error48.png
│   │   ├── [ 399]  header_background.xml
│   │   ├── [2.0K]  info48.png
│   │   ├── [ 316]  layout_background.xml
│   │   ├── [ 322]  no_event_background.xml
│   │   ├── [1.3K]  product.png
│   │   ├── [1.8K]  refresh64.png
│   │   ├── [ 323]  save48.png
│   │   ├── [ 603]  sent48.png
│   │   ├── [1.2K]  smartphone48.png
│   │   ├── [ 842]  touch48.png
│   │   ├── [2.4K]  trash48.png
│   │   ├── [1.8K]  trash64.png
│   │   └── [ 607]  video.png
│   ├── [ 13K]  layout
│   │   ├── [ 548]  debugger_layout.xml
│   │   ├── [1.6K]  event_holder.xml
│   │   ├── [2.7K]  event_viewer_layout.xml
│   │   ├── [1.9K]  hit_detail_viewer_layout.xml
│   │   ├── [1.9K]  offline_hits_holder.xml
│   │   ├── [3.1K]  offline_hits_viewer_layout.xml
│   │   └── [ 997]  parameter_holder.xml
│   └── [ 654]  values
│       └── [ 558]  values.xml
└── [  64]  values

can't get tracking working in a react-native native component

Here is my implementation using the react-native android bridge abilities, unfortunately it is not sending any hits, it is compiling fine but nothing gets sent, any help would be much appreciated :)

TrackerModule.java

package com.gallicadabra.tracker;

import android.app.Activity;
import android.util.Log;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;

import com.atinternet.tracker.ATInternet;
import com.atinternet.tracker.Tracker;
import com.atinternet.tracker.CustomVar;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;

public class TrackerModule extends ReactContextBaseJavaModule {

    private Tracker tracker;

    public TrackerModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "Xiti";
    }

    @ReactMethod
    public void initTracker(String trackerName) {
        //final Activity activity = getCurrentActivity();

        tracker = new Tracker(this.getReactApplicationContext(), new HashMap<String, Object>() {{
            put("log","logp");
            put("logSSL", "logs");
            put("domain", "xiti.com");
            put("pixelPath", "/hit.xiti");
            put("site", 18798);
            put("secure", true);
            put("identifier", "uuid");
            put("enableCrashDetection", true);
            put("plugins", "tvtracking");
            put("storage", "required");
            put("hashUserId", false);
            put("persistIdentifiedVisitor", true);
            put("tvtURL", "");
            put("tvtVisitDuration", 10);
            put("campaignLastPersistence", false);
            put("campaignLifetime", 30);
            put("sessionBackgroundDuration", 60);
        }});
    }

    @ReactMethod
    public void sendView(String viewName, ReadableArray customVars, ReadableMap chapters) {

        tracker.Context().setLevel2(73);

        for (int i = 0; i < customVars.size(); i++) {
            ReadableMap customVar = customVars.getMap(i);
            int id = customVar.hasKey("id") ? customVar.getInt("id") : 0;
            String value = customVar.hasKey("value") ? customVar.getString("value") : "";
            tracker.CustomVars().add(id, value, CustomVar.CustomVarType.App);
        }

        String chapter1 = chapters.hasKey("chapter1") ? chapters.getString("chapter1") : null;
        String chapter2 = chapters.hasKey("chapter2") ? chapters.getString("chapter2") : null;
        String chapter3 = chapters.hasKey("chapter3") ? chapters.getString("chapter3") : null;

        Log.v("chapter1", chapter1 + "");
        Log.v("chapter2", chapter2 + "");
        Log.v("chapter3", chapter3 + "");


        tracker.Screens()
                .add(viewName, chapter1, chapter2, chapter3)
                .setLevel2(73);
        tracker.dispatch();
    }

    @ReactMethod
    public void sendTouch(String touchName, ReadableMap chapters) {

        tracker.Context().setLevel2(73);

        String chapter1 = chapters.hasKey("chapter1") ? chapters.getString("chapter1") : null;
        String chapter2 = chapters.hasKey("chapter2") ? chapters.getString("chapter2") : null;
        String chapter3 = chapters.hasKey("chapter3") ? chapters.getString("chapter3") : null;


        tracker.Gestures()
                .add(touchName, chapter1, chapter2, chapter3)
                .setLevel2(73)
                .sendTouch();
    }

    @ReactMethod
    public void sendNavigation(String eventName, ReadableMap chapters) {

        tracker.Context().setLevel2(73);

        String chapter1 = chapters.hasKey("chapter1") ? chapters.getString("chapter1") : null;
        String chapter2 = chapters.hasKey("chapter2") ? chapters.getString("chapter2") : null;
        String chapter3 = chapters.hasKey("chapter3") ? chapters.getString("chapter3") : null;


        tracker.Gestures()
                .add(eventName, chapter1, chapter2, chapter3)
                .setLevel2(73)
                .sendNavigation();
    }

    @ReactMethod
    public void sendOfflineHits() {

        int nbHit = tracker.Offline().count();

        if (nbHit > 0) {
            tracker.Offline().dispatch();
        }
    }
}

TrackerPackage.java

package com.gallicadabra.tracker;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TrackerPackage implements ReactPackage {

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new TrackerModule(reactContext));

        return modules;
    }
}

MainActivity.java

package com.gallicadabra;

import com.facebook.react.ReactActivity;

// react-native-orientation
import android.content.Intent;
import android.content.res.Configuration;

public class MainActivity extends ReactActivity {

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
    @Override
    protected String getMainComponentName() {
        return "Gallicadabra";
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Intent intent = new Intent("onConfigurationChanged");
        intent.putExtra("newConfig", newConfig);
        this.sendBroadcast(intent);
    }
}

MainApplication.java

package com.gallicadabra;

import android.app.Application;
import android.util.Log;

import com.facebook.react.ReactApplication;
import com.gallicadabra.tracker.TrackerPackage;
import com.github.yamill.orientation.OrientationPackage;
import com.reactnative.photoview.PhotoViewPackage;
import com.zmxv.RNSound.RNSoundPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

    @Override
    protected boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          new OrientationPackage(),
          new PhotoViewPackage(),
          new RNSoundPackage(),
          new TrackerPackage()
      );
    }
  };

  @Override
  public ReactNativeHost getReactNativeHost() {
      return mReactNativeHost;
  }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gallicadabra"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="22" />

    <application
      android:name=".MainApplication"
      android:allowBackup="true"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

StrictMode violation in 2.16.0

Database access in Core.java is not safe. All Closeable objects should always be wrapped in a try-finally or even better try-with-resources block.
Example of violation:

 ArrayList<Hit> getOfflineHits() {
        SQLiteDatabase db = getReadableDatabase();
        if (db == null) {
            return new ArrayList<>();
        }
        ArrayList<Hit> hits = new ArrayList<>();
        Cursor c = db.rawQuery(SELECT_ALL_QUERY + "ORDER BY " + ID + " ASC", null);
        if (c != null && c.getCount() > 0) {
            c.moveToFirst();
            do {
                String hit = c.getString(c.getColumnIndex(HIT));
                String time = c.getString(c.getColumnIndex(DATE));
                int retry = c.getInt(c.getColumnIndex(RETRY));
                hits.add(new Hit(hit, new Date(Long.parseLong(time)), retry, true));
            }
            while (c.moveToNext());
            c.close();
        }
        db.close();
        return hits;
    }

Should be written like this:

ArrayList<Hit> getOfflineHits() {
    SQLiteDatabase db = null;
    try {
        db = getReadableDatabase();
        if (db == null) {
            return new ArrayList<>();
        }
        ArrayList<Hit> hits = new ArrayList<>();
        Cursor c = null;
        try {
            c = db.rawQuery(SELECT_ALL_QUERY + "ORDER BY " + ID + " ASC", null);
            if (c != null && c.getCount() > 0) {
                c.moveToFirst();
                do {
                    String hit = c.getString(c.getColumnIndex(HIT));
                    String time = c.getString(c.getColumnIndex(DATE));
                    int retry = c.getInt(c.getColumnIndex(RETRY));
                    hits.add(new Hit(hit, new Date(Long.parseLong(time)), retry, true));
                }
                while (c.moveToNext());
            }
        } finally {
            if (c != null) c.close();
        }
    } finally {
        db.close();
    }
    return hits;
}
2020-05-15 14:29:54.878 D/StrictMode: StrictMode policy violation: android.os.strictmode.SqliteObjectLeakedViolation: Finalizing a Cursor that has not been deactivated or closed. database = /data/user/0/com.sprylab.purple.android.apps.trackingtest/databases/TrackerDatabase, table = null, query = SELECT * FROM StoredOfflineHit ORDER BY id ASC
        at android.os.StrictMode.onSqliteObjectLeaked(StrictMode.java:2060)
        at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:289)
        at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:289)
        at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:276)
        at java.lang.Daemons$Daemon.run(Daemons.java:137)
        at java.lang.Thread.run(Thread.java:919)
     Caused by: android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
        at android.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:106)
        at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:52)
        at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1443)
        at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1382)
        at com.atinternet.tracker.Storage.getOfflineHits(Core.java:2011)
        at com.atinternet.tracker.Sender.sendOfflineHits(Core.java:812)
        at com.atinternet.tracker.Sender.send(Core.java:804)
        at com.atinternet.tracker.Builder.run(Core.java:516)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919) 

New Logo

Hi, @at-internet I am a graphic designer, I want to help others in graphic design.

After I reviewed your project, you have no logo on this project. Therefore I want to contribute to this project by creating a new logo / icon. what do you think?

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.