Skip to content

Commit

Permalink
Creating tracking library:
Browse files Browse the repository at this point in the history
 - adding aspect to track texts, clicks, activities,
 - adding listeners to accelerometer, networking, location and battery,
 - gathering data about contacts, applications, messages and photos
 - adding api to send events
  • Loading branch information
Dawid Sitnik committed Sep 20, 2019
1 parent 25ad53c commit 549a9b7
Show file tree
Hide file tree
Showing 54 changed files with 1,101 additions and 297 deletions.
File renamed without changes.
32 changes: 26 additions & 6 deletions app/build.gradle → algolytics_tracking_android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,35 +1,55 @@
apply plugin: 'com.android.application'

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.archinamon.aspectj'
apply plugin: 'digital.wup.android-maven-publish'

android {
compileSdkVersion 29
buildToolsVersion "29.0.2"

defaultConfig {
applicationId "com.example.trackingapp"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
multiDexEnabled true
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'com.synerise.sdk:synerise-mobile-sdk:3.3.17'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
api group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.6.1'
api group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.6.1'
api 'com.google.code.gson:gson:2.8.5'
implementation 'androidx.multidex:multidex:2.0.0'
}


publishing {
publications {
aar(MavenPublication) {
from components.android
groupId = 'com.algolytics'
artifactId = 'tracking-android'
version = '0.0.1'
}

}
}
Empty file.
File renamed without changes.
13 changes: 13 additions & 0 deletions algolytics_tracking_android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.algolytics.tracker.api" >

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.algolytics.tracker.api.androidadapters

import android.text.Editable
import android.text.TextWatcher
import android.widget.TextView

abstract class DefaultTextWatcher(val editText: TextView) : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.algolytics.tracker.api.aspect

import android.app.Activity
import com.algolytics.tracker.api.model.Event
import com.algolytics.tracker.api.net.ApiTracker
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before

@Aspect
open class ActivityAspect {

@Before("execution(* android.app.Activity.onCreate(..))")
fun trackTouch(joinPoint: JoinPoint) {
val activity = joinPoint.`this` as Activity
ApiTracker.getInstance().addToList(
Event(
activity::class.java.simpleName
, "ACTIVITY_CHANGED"
)
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.algolytics.tracker.api.aspect

import android.view.View
import android.widget.*
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before


@Aspect
class ClickAspect {

@Before("execution(* android.view.View.OnClickListener.onClick(android.view.View)) && args(view)")
fun trackClick(view: View?) {
Toast.makeText(view!!.context, "trackClick", Toast.LENGTH_SHORT).show();
onClickOrTouchInteracted(view, EVENT_NAME)
}

@Before("execution(* android.view.View.OnLongClickListener.onLongClick(android.view.View)) && args(view)")
fun trackLongClick(view: View?) {
Toast.makeText(view!!.context, "trackLongClick", Toast.LENGTH_SHORT).show();

}

companion object {
private val EVENT_NAME = "click"
private val LABEL_INTERACTION_LONG_CLICK = "longClick"
}


private fun onClickOrTouchInteracted(view: View, labelInteraction: String) {
val id = if (view.id == View.NO_ID) "no-id" else view.resources.getResourceName(view.id)
val map = when (view) {
is SeekBar -> mapOf("progress" to view.progress)
is RatingBar -> mapOf("rating" to view.rating)
is ProgressBar -> mapOf("progress" to view.progress)
is DatePicker -> mapOf("date" to view.year.toString() + "-" + (view.month + 1) + "-" + view.dayOfMonth)
is TimePicker -> mapOf("hour" to view.currentHour, "minute" to view.currentMinute)
is NumberPicker -> mapOf("value" to view.value)
is Spinner -> {
when (val item = view.selectedItem) {
is String -> mapOf("values" to item)
is TextView -> mapOf("values" to item.text.toString())
else -> mapOf()
}
}
is CompoundButton -> mapOf("checked" to view.isChecked)

else -> mapOf()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.algolytics.tracker.api.aspect

import android.text.Editable
import com.algolytics.tracker.api.androidadapters.DefaultTextWatcher
import com.algolytics.tracker.api.model.Event
import com.algolytics.tracker.api.net.ApiTracker
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before

@Aspect
class TextAspect {
@Before("execution(* com.algolytics.tracker.api.androidadapters.DefaultTextWatcher.afterTextChanged(android.text.Editable)) && args(e)")
fun trackEditText(e: Editable, joinPoint: JoinPoint) {
val textWatcher = joinPoint.`this` as DefaultTextWatcher
ApiTracker.getInstance().addToList(
Event(
mapOf(
"name" to textWatcher.editText.resources.getResourceEntryName(textWatcher.editText.id),
"input" to e.toString()
), "TEXT_INSERTED"
)
)
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.algolytics.tracker.api.aspect.model

data class ClickEvent(private val id: String, private val params: Map<String, Any>)
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.algolytics.tracker.api.data.amount

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.provider.ContactsContract
import androidx.core.content.ContextCompat
import com.algolytics.tracker.api.model.Event
import com.algolytics.tracker.api.net.ApiTracker

class ContactsAmount {
companion object {

data class ContactsNumber(val contactsNumber: Int)

fun getContactsList(context: Context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED
) {
return
}
val cursor =
context.contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
null
)

val contactsNumber = cursor?.use {
(1..it.count)
.map {
cursor.moveToNext()
cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)
}
.filter { num -> num > 0 }
.count()
} ?: 0

ApiTracker.getInstance().addToList(
Event(
ContactsNumber(
contactsNumber
),
"CONTACT_NUMBER"
)
)
cursor?.close()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.algolytics.tracker.api.data.amount

import android.database.Cursor

fun extractDataFromCursor(cursor: Cursor?): Pair<String?, Int> {
var sentCounter1 = 0
var lastSendMessageDate: String? = null
if (cursor?.moveToFirst() == true) {
do {
if (sentCounter1 == 0) {
lastSendMessageDate = cursor.getString(cursor.getColumnIndexOrThrow("date"))
}
sentCounter1++
} while (cursor.moveToNext())
}
return Pair(lastSendMessageDate, sentCounter1)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.algolytics.tracker.api.data.amount

import android.Manifest
import android.app.Application
import android.content.pm.PackageManager
import android.net.Uri
import androidx.core.content.ContextCompat
import com.algolytics.tracker.api.model.Event
import com.algolytics.tracker.api.net.ApiTracker

class NumberOfSMS {
companion object {
private const val inboxUri = "content://sms/inbox"
private const val sentUri = "content://sms/sent"

data class NumberOfSMS(val sent: Int, val lastSendMessage: String?, val inbox: Int, val lastInboxMessage: String?)

fun getSMS(application: Application) {
if (ContextCompat.checkSelfPermission(
application.applicationContext,
Manifest.permission.READ_SMS
)
!= PackageManager.PERMISSION_GRANTED
) {
return
}
val inboxPair = application.contentResolver.query(Uri.parse(inboxUri), null, null, null, null)
.use { extractDataFromCursor(it) }

val sentPair = application.contentResolver.query(Uri.parse(sentUri), null, null, null, null)
.use { extractDataFromCursor(it) }

ApiTracker.getInstance().addToList(
Event(
NumberOfSMS(
inboxPair.second,
inboxPair.first,
sentPair.second,
sentPair.first
), "SMS"
)
)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.algolytics.tracker.api.data.amount

import android.Manifest
import android.app.Application
import android.content.pm.PackageManager
import android.provider.MediaStore
import androidx.core.content.ContextCompat
import com.algolytics.tracker.api.model.Event
import com.algolytics.tracker.api.net.ApiTracker
import java.util.*


class PhotosAmount {
companion object {

private val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI

private val projection =
arrayOf(MediaStore.MediaColumns.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME)

data class Photos(val numberOfPhotos: Int, val lastPhotoDate: String?)

fun getNumberOfPhotos(application: Application) {
if (ContextCompat.checkSelfPermission(
application.applicationContext,
Manifest.permission.READ_EXTERNAL_STORAGE
)
!= PackageManager.PERMISSION_GRANTED
) {
return
}

// val photosPair = application.contentResolver.query(uri, projection, null, null, null)
// .use { extractDataFromCursor(it) }

//
// ApiTracker.getInstance().addToList(
// Event(
// Photos(photosPair.second, photosPair.first),
// "PHOTOS"
// )
// )
}
}
}
Loading

0 comments on commit 549a9b7

Please sign in to comment.