Commit inicial

This commit is contained in:
2023-09-27 10:49:20 -06:00
commit 94d176ea9e
15 changed files with 1837 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
**/Objects
**/AutoBackups

273
DBRequestManager.bas Normal file
View File

@@ -0,0 +1,273 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=6.8
@EndOfDesignText@
'Necesita la libreria RandomAccessFile
'Class module
Sub Class_Globals
Private mTarget As Object
Type DBResult (Tag As Object, Columns As Map, Rows As List)
Type DBCommand (Name As String, Parameters() As Object)
Private link As String
Private bc As ByteConverter
Private T_NULL = 0, T_STRING = 1, T_SHORT = 2, T_INT = 3, T_LONG = 4, T_FLOAT = 5 _
,T_DOUBLE = 6, T_BOOLEAN = 7, T_BLOB = 8 As Byte
Private VERSION As Float = 0.9
Private tempArray(1) As Object
Dim jobTagAnterior As String = "" 'Mod por CHV - 211027
End Sub
'Target - The module that handles JobDone (usually Me).
'ConnectorLink - URL of the Java server.
Public Sub Initialize (Target As Object, ConnectorLink As String)
mTarget = Target
link = ConnectorLink
End Sub
'Sends a query request.
'Command - Query name and parameters.
'Limit - Maximum rows to return or 0 for no limit.
'Tag - An object that will be returned in the result.
'Timeout - The http request timeout in ms, or 0 if default (30 secs)
Public Sub ExecuteQuery(Command As DBCommand, Limit As Int, Tag As Object, Timeout As Int) 'Mod por CHV, agregué el parametro Timeout - 211229
Dim j As HttpJob
Dim ms As OutputStream
Dim out2 As OutputStream = StartJob(j,ms, Tag)
WriteObject(Command.Name, out2)
WriteInt(Limit, out2)
WriteList(Command.Parameters, out2)
out2.Close
j.PostBytes(link & "?method=query", ms.ToBytesArray)
If Timeout <> 0 Then j.GetRequest.Timeout = Timeout
End Sub
'Executes a batch of (non-select) commands.
'ListOfCommands - List of the commands that will be executes.
'Tag - An object that will be returned in the result.
Public Sub ExecuteBatch(ListOfCommands As List, Tag As Object)
Dim j As HttpJob
Dim ms As OutputStream
Dim out2 As OutputStream = StartJob(j,ms, Tag)
WriteInt(ListOfCommands.Size, out2)
For Each Command As DBCommand In ListOfCommands
WriteObject(Command.Name, out2)
WriteList(Command.Parameters, out2)
Next
out2.Close
j.PostBytes(link & "?method=batch", ms.ToBytesArray)
End Sub
'Similar to ExecuteBatch. Sends a single command.
Public Sub ExecuteCommand(Command As DBCommand, Tag As Object)
ExecuteBatch(Array As DBCommand(Command), Tag)
End Sub
Private Sub StartJob(j As HttpJob, MemoryStream As OutputStream, Tag As Object) As OutputStream
j.Initialize("DBRequest", mTarget)
j.Tag = Tag
MemoryStream.InitializeToBytesArray(0)
Dim compress As CompressedStreams
Dim out As OutputStream = compress.WrapOutputStream(MemoryStream, "gzip")
WriteObject(VERSION, out)
Return out
End Sub
Private Sub WriteList(Parameters As List, out As OutputStream)
Dim data() As Byte
If Parameters = Null Or Parameters.IsInitialized = False Then
Dim Parameters As List
Parameters.Initialize
End If
data = bc.IntsToBytes(Array As Int(Parameters.Size))
out.WriteBytes(data, 0, data.Length)
For Each o As Object In Parameters
WriteObject(o, out)
Next
End Sub
Private Sub WriteObject(o As Object, out As OutputStream)
Dim data() As Byte
tempArray(0) = o
If tempArray(0) = Null Then
out.WriteBytes(Array As Byte(T_NULL), 0, 1)
Else If tempArray(0) Is Short Then
out.WriteBytes(Array As Byte(T_SHORT), 0, 1)
data = bc.ShortsToBytes(Array As Short(o))
Else If tempArray(0) Is Int Then
out.WriteBytes(Array As Byte(T_INT), 0, 1)
data = bc.IntsToBytes(Array As Int(o))
Else If tempArray(0) Is Float Then
out.WriteBytes(Array As Byte(T_FLOAT), 0, 1)
data = bc.FloatsToBytes(Array As Float(o))
Else If tempArray(0) Is Double Then
out.WriteBytes(Array As Byte(T_DOUBLE), 0, 1)
data = bc.DoublesToBytes(Array As Double(o))
Else If tempArray(0) Is Long Then
out.WriteBytes(Array As Byte(T_LONG), 0, 1)
data = bc.LongsToBytes(Array As Long(o))
Else If tempArray(0) Is Boolean Then
out.WriteBytes(Array As Byte(T_BOOLEAN), 0, 1)
Dim b As Boolean = 0
Dim data(1) As Byte
If b Then data(0) = 1 Else data(0) = 0
Else If GetType(tempArray(0)) = "[B" Then
data = o
out.WriteBytes(Array As Byte(T_BLOB), 0, 1)
WriteInt(data.Length, out)
Else 'If o Is String Then (treat all other values as string)
out.WriteBytes(Array As Byte(T_STRING), 0, 1)
data = bc.StringToBytes(o, "UTF8")
WriteInt(data.Length, out)
End If
If data.Length > 0 Then out.WriteBytes(data, 0, data.Length)
End Sub
Private Sub ReadObject(In As InputStream) As Object
Dim data(1) As Byte
In.ReadBytes(data, 0, 1)
Select data(0)
Case T_NULL
Return Null
Case T_SHORT
Dim data(2) As Byte
Return bc.ShortsFromBytes(ReadBytesFully(In, data, data.Length))(0)
Case T_INT
Dim data(4) As Byte
Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0)
Case T_LONG
Dim data(8) As Byte
Return bc.LongsFromBytes(ReadBytesFully(In, data, data.Length))(0)
Case T_FLOAT
Dim data(4) As Byte
Return bc.FloatsFromBytes(ReadBytesFully(In, data, data.Length))(0)
Case T_DOUBLE
Dim data(8) As Byte
Return bc.DoublesFromBytes(ReadBytesFully(In, data, data.Length))(0)
Case T_BOOLEAN
Dim b As Byte = ReadByte(In)
Return b = 1
Case T_BLOB
Dim len As Int = ReadInt(In)
Dim data(len) As Byte
Return ReadBytesFully(In, data, data.Length)
Case Else
Dim len As Int = ReadInt(In)
Dim data(len) As Byte
ReadBytesFully(In, data, data.Length)
Return BytesToString(data, 0, data.Length, "UTF8")
End Select
End Sub
Private Sub ReadBytesFully(In As InputStream, Data() As Byte, Len As Int) As Byte()
Dim count = 0, read As Int
Do While count < Len And read > -1
read = In.ReadBytes(Data, count, Len - count)
count = count + read
Loop
Return Data
End Sub
Private Sub WriteInt(i As Int, out As OutputStream)
Dim data() As Byte
data = bc.IntsToBytes(Array As Int(i))
out.WriteBytes(data, 0, data.Length)
End Sub
Private Sub ReadInt(In As InputStream) As Int
Dim data(4) As Byte
Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0)
End Sub
Private Sub ReadByte(In As InputStream) As Byte
Dim data(1) As Byte
In.ReadBytes(data, 0, 1)
Return data(0)
End Sub
'Handles the Job result and returns a DBResult.
Public Sub HandleJob(Job As HttpJob) As DBResult
' Dim start As Long = DateTime.Now
Dim In As InputStream = Job.GetInputStream
Dim cs As CompressedStreams
In = cs.WrapInputStream(In, "gzip")
Dim serverVersion As Float = ReadObject(In) 'ignore
Dim method As String = ReadObject(In)
Dim table As DBResult
table.Initialize
table.Columns.Initialize
table.rows.Initialize
table.Tag = Job.Tag
If jobTagAnterior <> Job.Tag Then LogColor("HandleJob: '"&Job.Tag&"'", Colors.Blue) 'Mod por CHV - 211023
jobTagAnterior = Job.Tag 'Mod por CHV - 211023
If method = "query" Then
Dim numberOfColumns As Int = ReadInt(In)
For i = 0 To numberOfColumns - 1
table.Columns.Put(ReadObject(In), i)
Next
Do While ReadByte(In) = 1
Dim rowObjects(numberOfColumns) As Object
table.rows.Add(rowObjects)
For col = 0 To numberOfColumns - 1
Dim o As Object = ReadObject(In)
rowObjects(col) = o
Next
Loop
Else If method = "batch" Then
table.Columns.Put("AffectedRows", 0)
Dim rows As Int = ReadInt(In)
For i = 0 To rows - 1
table.rows.Add(Array As Object(ReadInt(In)))
Next
End If
In.Close
' Log("HandleJob: " & (DateTime.Now - start))
Return table
End Sub
'Reads a file and returns the file as a bytes array.
Public Sub FileToBytes(Dir As String, FileName As String) As Byte()
Dim out As OutputStream
out.InitializeToBytesArray(0)
Dim In As InputStream = File.OpenInput(Dir, FileName)
File.Copy2(In, out)
out.Close
Return out.ToBytesArray
End Sub
'Converts an image to a bytes array (for BLOB fields).
Public Sub ImageToBytes(Image As Bitmap) As Byte()
Dim out As OutputStream
out.InitializeToBytesArray(0)
Image.WriteToStream(out, 100, "JPEG")
out.Close
Return out.ToBytesArray
End Sub
'Converts a bytes array to an image (for BLOB fields).
Public Sub BytesToImage(bytes() As Byte) As Bitmap
Dim In As InputStream
In.InitializeFromBytesArray(bytes, 0, bytes.Length)
Dim bmp As Bitmap
bmp.Initialize2(In)
Return bmp
End Sub
'Prints the table to the logs.
Public Sub PrintTable(Table As DBResult)
Log("Tag: " & Table.Tag & ", Columns: " & Table.Columns.Size & ", Rows: " & Table.Rows.Size)
Dim sb As StringBuilder
sb.Initialize
For Each col In Table.Columns.Keys
sb.Append(col).Append(TAB)
Next
Log(sb.ToString)
For Each row() As Object In Table.Rows
Dim sb As StringBuilder
sb.Initialize
For Each record As Object In row
sb.Append(record).Append(TAB)
Next
ToastMessageShow(sb.ToString, True)
Next
End Sub

149
DBRequestManagerV2.bas Normal file
View File

@@ -0,0 +1,149 @@
B4J=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=5.45
@EndOfDesignText@
'Requires support for resumable subs
'Class module
Sub Class_Globals
Private mTarget As Object
Private link As String
Private VERSION As Float = 2
End Sub
'Target - The module that handles JobDone (usually Me).
'ConnectorLink - URL of the Java server.
Public Sub Initialize (Target As Object, ConnectorLink As String)
mTarget = Target
link = ConnectorLink
End Sub
'Sends a query request.
'Command - Query name and parameters.
'Limit - Maximum rows to return or 0 for no limit.
'Tag - An object that will be returned in the result.
Public Sub ExecuteQuery(Command As DBCommand, Limit As Int, Tag As Object, Timeout As Int) As HttpJob
Dim ser As B4XSerializator
Dim data() As Byte = ser.ConvertObjectToBytes(CreateMap("command": Command, "limit": Limit, "version": VERSION))
Return SendJob(CreateJob, data, Tag, "query2", Timeout)
End Sub
Private Sub SendJob(j As HttpJob, Data() As Byte, Tag As Object, Method As String, Timeout As Int) As HttpJob
j.Tag = Tag
j.PostBytes(link & "?method=" & Method , Data)
If Timeout <> 0 Then j.GetRequest.Timeout = Timeout
Return j
End Sub
Private Sub CreateJob As HttpJob
Dim j As HttpJob
j.Initialize("DBRequest", mTarget)
Return j
End Sub
'Executes a batch of (non-select) commands.
'ListOfCommands - List of the commands that will be executes.
'Tag - An object that will be returned in the result.
Public Sub ExecuteBatch(ListOfCommands As List, Tag As Object) As HttpJob
Dim j As HttpJob = CreateJob
ExecuteBatchImpl(j, ListOfCommands, Tag)
Return j
End Sub
Private Sub ExecuteBatchImpl(Job As HttpJob, ListOfCommands As List, Tag As Object)
Dim ser As B4XSerializator
ser.ConvertObjectToBytesAsync(CreateMap("commands": ListOfCommands, "version": VERSION), "ser")
Wait For (ser) ser_ObjectToBytes (Success As Boolean, Bytes() As Byte)
If Success = False Then
Log("Error building command: " & LastException)
Return
End If
Dim ser As B4XSerializator = Sender
SendJob(Job, Bytes, Tag, "batch2", 0)
End Sub
'Similar to ExecuteBatch. Sends a single command.
Public Sub ExecuteCommand(Command As DBCommand, Tag As Object) As HttpJob
Return ExecuteBatch(Array As DBCommand(Command), Tag)
End Sub
'Handles the Job result and returns a DBResult.
'It is recommended to use HandleJobAsync instead.
Public Sub HandleJob(Job As HttpJob) As DBResult
Dim ser As B4XSerializator
Dim data() As Byte = Bit.InputStreamToBytes(Job.GetInputStream)
Dim res As DBResult = ser.ConvertBytesToObject(data)
res.Tag = Job.Tag
Return res
End Sub
'Handles the Job result and raises the Result event when the data is ready.
Public Sub HandleJobAsync(Job As HttpJob, EventName As String)
Dim ser As B4XSerializator
Dim data() As Byte = Bit.InputStreamToBytes(Job.GetInputStream)
ser.ConvertBytesToObjectAsync(data, "ser")
Wait For (ser) ser_BytesToObject (Success As Boolean, NewObject As Object)
If Success = False Then
Log("Error reading response: " & LastException)
Return
End If
Dim res As DBResult = NewObject
res.Tag = Job.Tag
CallSubDelayed2(mTarget, EventName & "_result", res)
End Sub
'Reads a file and returns the file as a bytes array.
Public Sub FileToBytes(Dir As String, FileName As String) As Byte()
Dim out As OutputStream
out.InitializeToBytesArray(0)
Dim In As InputStream = File.OpenInput(Dir, FileName)
File.Copy2(In, out)
out.Close
Return out.ToBytesArray
End Sub
#if Not(B4J)
'Converts an image to a bytes array (for BLOB fields).
Public Sub ImageToBytes(Image As Bitmap) As Byte()
Dim out As OutputStream
out.InitializeToBytesArray(0)
Image.WriteToStream(out, 100, "JPEG")
out.Close
Return out.ToBytesArray
End Sub
'Converts a bytes array to an image (for BLOB fields).
Public Sub BytesToImage(bytes() As Byte) As Bitmap
Dim In As InputStream
In.InitializeFromBytesArray(bytes, 0, bytes.Length)
Dim bmp As Bitmap
bmp.Initialize2(In)
Return bmp
End Sub
#End If
'Prints the table to the logs.
Public Sub PrintTable(Table As DBResult)
Log("Tag: " & Table.Tag & ", Columns: " & Table.Columns.Size & ", Rows: " & Table.Rows.Size)
Dim sb As StringBuilder
sb.Initialize
For Each col In Table.Columns.Keys
sb.Append(col).Append(TAB)
Next
Log(sb.ToString)
For Each row() As Object In Table.Rows
Dim sb As StringBuilder
sb.Initialize
For Each record As Object In row
sb.Append(record).Append(TAB)
Next
Log(sb.ToString)
Next
End Sub

216
FLP-ML.b4a Normal file
View File

@@ -0,0 +1,216 @@
Build1=Default,flp2.chv.com
File1=gps_hist.db
File2=Layout.bal
FileGroup1=Default Group
FileGroup2=Default Group
Group=Default Group
Library1=administrator
Library10=mlwifi400
Library11=notificationlistener
Library12=okhttputils2
Library13=phone
Library14=randomaccessfile
Library15=reflection
Library16=runtimepermissions
Library17=sql
Library18=replyauto
Library2=byteconverter
Library3=compressstrings
Library4=core
Library5=firebaseanalytics
Library6=firebasenotifications
Library7=fusedlocationprovider
Library8=gps
Library9=json
ManifestCode='This code will be applied to the manifest file during compilation.~\n~'You do not need to modify it in most cases.~\n~'See this link for for more information: https://www.b4x.com/forum/showthread.php?p=78136~\n~AddManifestText(~\n~<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="27"/>~\n~<supports-screens android:largeScreens="true" ~\n~ android:normalScreens="true" ~\n~ android:smallScreens="true" ~\n~ android:anyDensity="true"/>)~\n~SetApplicationAttribute(android:icon, "@drawable/icon")~\n~SetApplicationAttribute(android:label, "$LABEL$")~\n~CreateResourceFromFile(Macro, Themes.LightTheme)~\n~'End of default text.~\n~AddPermission(android.permission.ACCESS_FINE_LOCATION)~\n~AddPermission(android.permission.WRITE_EXTERNAL_STORAGE)~\n~CreateResourceFromFile(Macro, FirebaseAnalytics.GooglePlayBase)~\n~CreateResourceFromFile(Macro, FirebaseAnalytics.Firebase)~\n~CreateResourceFromFile(Macro, FirebaseAnalytics.FirebaseAnalytics)~\n~CreateResourceFromFile(Macro, FirebaseNotifications.FirebaseNotifications)~\n~SetServiceAttribute(Tracker, android:foregroundServiceType, "location")~\n~~\n~AddApplicationText(<receiver android:name="anywheresoftware.b4a.objects.AdminReceiver2"~\n~ android:permission="android.permission.BIND_DEVICE_ADMIN">~\n~ <meta-data android:name="android.app.device_admin"~\n~ android:resource="@xml/device_admin" />~\n~ <intent-filter>~\n~ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />~\n~ </intent-filter>~\n~</receiver>)~\n~~\n~CreateResource(xml, device_admin.xml,~\n~<device-admin xmlns:android="http://schemas.android.com/apk/res/android">~\n~ <uses-policies>~\n~ <limit-password />~\n~ <reset-password />~\n~ <force-lock />~\n~ </uses-policies>~\n~</device-admin>~\n~)~\n~AddPermission(android.permission.SEND_SMS)~\n~AddPermission(android.permission.RECEIVE_SMS)~\n~AddPermission(android.permission.READ_PHONE_STATE)~\n~AddPermission(android.permission.READ_CALL_LOG)~\n~AddApplicationText(~\n~<service android:name="b4a.jsaplication.com.br.ReplyAuto"~\n~ android:label="Mariana" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">~\n~ <intent-filter><action android:name="android.service.notification.NotificationListenerService" /></intent-filter>~\n~ </service>)
Module1=DBRequestManager
Module2=FirebaseMessaging
Module3=Mods
Module4=NotificationService
Module5=Starter
Module6=Subs
Module7=Tracker
NumberOfFiles=2
NumberOfLibraries=18
NumberOfModules=7
Version=12.5
@EndOfDesignText@
#Region Project Attributes
#ApplicationLabel: FLP 2.0
#VersionCode: 1
#VersionName: 3.07.07
'SupportedOrientations possible values: unspecified, landscape or portrait.
#SupportedOrientations: unspecified
#CanInstallToExternalStorage: False
' #AdditionalJar: com.android.support:support-v4
#AdditionalJar: com.google.android.gms:play-services-location
#BridgeLogger:True
#End Region
#Region Activity Attributes
#FullScreen: False
#IncludeTitle: True
#End Region
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim wifi As MLwifi
Dim wifiS As MLScan
Public manager As AdminManager
' Dim ruta As String
Dim fechaRuta As String
Dim laUbicacion As Location
End Sub
Sub Globals
'These global variables will be redeclared each time the activity is created.
Private Button1 As Button
Private et_id As EditText
Private b_guardarId As Button
Private l_coords As Label
Dim l_lastUpdate As Label
Private l_id As Label
End Sub
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("Layout")
' ruta = File.DirInternal
Subs.getPhnId
et_id.Text = Starter.devModel.trim
getSSID
Button1.Left = Round(Activity.Width/2)-(Button1.Width/2)
l_id.Left = (Activity.Width / 2) - (l_id.Width / 2)
l_lastUpdate.Left = (Activity.Width / 2) - (l_lastUpdate.Width / 2)
b_guardarId.Left = (Activity.Width / 2) - (b_guardarId.Width / 2)
et_id.Left = (Activity.Width / 2) - (et_id.Width / 2)
End Sub
Sub Activity_Resume
chkPermisosUbicacion 'Permisos de ubicacion para Tracker
chkPermisosAlmacenamientoExterno
Subs.getPhnId
et_id.Text = Starter.devModel.Trim
getSSID
getAdminRights
l_lastUpdate.Text = Starter.lastLocUpdate
' ruta = File.DirInternal
If Not(CheckNotificationAccess) Then
Msgbox2Async($"Se necesita acceso a las notificaciones, haga clic en "Aceptar" y en la siguiente pantalla permita el acceso a la aplicación "${Application.LabelName}"."$, "Permisos necesarios", "Aceptar", "Cancelar", "", Null, True)
Wait For Msgbox_Result (resultado As Int)
If resultado = DialogResponse.POSITIVE Then
Dim In As Intent
In.Initialize("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS", "")
StartActivity(In)
End If
End If
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub Button1_Click
Subs.mandaLocAServer(laUbicacion, Starter.devModel.Trim)
Dim params As Map = CreateMap("topic": FirebaseMessaging.Sprvsr,"title":"Prueba Trckr", "body":"Prueba Trckr", "d":Starter.devModel, "t":"pong")
CallSubDelayed2(FirebaseMessaging, "SendMessage",params)
If Starter.logger Then Log("Start wifi scan")
wifiS.startscan("WiFi", True)
Wait For WiFi_ScanDone (Results() As String, Count As Int)
End Sub
Sub Button1_LongClick
copiaDB
End Sub
Sub chkPermisosAlmacenamientoExterno
Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
If Result Then
If Starter.logger Then Log("Permisos de almacenamiento externo OK")
Else
' ToastMessageShow("SIN permisos de almacenamiento externo", True)
End If
End Sub
Sub chkPermisosUbicacion
If Starter.logger Then Log("Revisamos permisos de ubicación.")
Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_ACCESS_FINE_LOCATION)
Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
If Result Then
StartService(Tracker)
If Starter.logger Then Log("Start Tracker")
Else
' ToastMessageShow("SIN permisos de ubicacion", True)
End If
End Sub
Sub getSSID
If wifi.isWifiConnected Then
Subs.ssid = wifi.WifiSSID
End If
End Sub
Sub getAdminRights
If manager.Enabled = False Then
manager.Enable("Please enable in order to get access to the secured server.")
End If
End Sub
'Sub wifiScanned_ScanDone
' Log("//////////////////////////////wifi_conected_result")
' ToastMessageShow("Wifi_ConnectionResult",True)
' If wifi.isWifiConnected Then
' ssid = wifi.WifiSSID
' End If
'End Sub
Sub copiaDB
' Log("ruta="&ruta)
' Log("File.DirInternal="&File.DirInternal)
' Log("File.DirRootExternal="&File.DirRootExternal)
' Log("File.DirDefaultExternal="&File.DirDefaultExternal)
' Log(Starter.rp.GetSafeDirDefaultExternal(""))
' Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
' Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
' If Result Then
' If Starter.logger Then Log("Tenemos permisos de escritura.")
' File.Copy(Starter.ruta , "gps_hist.db", File.DirDefaultExternal, "gps_hist.db")
' If Starter.logger Then Log($"DB escrita a ${File.DirDefaultExternal}"$)
' ToastMessageShow($"DB escrita a ${File.DirDefaultExternal}"$, True)
' End If
End Sub
Private Sub b_guardarId_Click
If et_id.Text.Length > 2 Then 'Si tenemos valor para ID
File.WriteString(File.DirInternal, "phnId.txt", et_id.Text.trim) 'Sobreescribimos archivo IdPersonal.txt con ID
Starter.devModel = et_id.Text.Trim
If Starter.logger Then Log("Tenemos ID: "& et_id.Text.Trim & " "&File.DirInternal&"/phnId.txt sobreescrito")
Else If et_id.Text.Length < 3 Then ' Si no tenemos valor, lo leemos de IdPersonal.txt
Dim s As String = File.ReadString(File.DirInternal, "phnId.txt")
Starter.devModel = s
If Starter.logger Then Log("Leemos id de "&File.DirInternal&"/phnId.txt")
et_id.Text = Starter.devModel.Trim
If Starter.logger Then Log(Starter.devModel.Trim)
End If
If Tracker.FLP.IsInitialized Then Subs.mandaLocAServer(laUbicacion, Starter.devModel.Trim)
End Sub
Sub ponCoords
l_coords.left = (Activity.Width/2) - (l_coords.Width/2)
l_coords.Text = $"${Starter.UUC.Latitude},${Starter.UUC.Longitude}"$
End Sub
'Revisa si la aplicación tiene permiso para acceder a las notificaciones.
Sub CheckNotificationAccess As Boolean
Dim ph As Phone
Dim nstr, pstr As String
Dim r As Reflector
pstr = r.GetStaticField("anywheresoftware.b4a.BA", "packageName")
nstr = ph.GetSettings("enabled_notification_listeners")
Return nstr.Contains(pstr)
End Sub
Sub actualizaLabelUU
l_lastUpdate.Text = Subs.fechaKMT(Starter.lastLocUpdate)
End Sub

27
FLP-ML.b4a.meta Normal file
View File

@@ -0,0 +1,27 @@
ModuleBookmarks0=
ModuleBookmarks1=
ModuleBookmarks2=
ModuleBookmarks3=
ModuleBookmarks4=
ModuleBookmarks5=
ModuleBookmarks6=
ModuleBookmarks7=
ModuleBreakpoints0=
ModuleBreakpoints1=
ModuleBreakpoints2=
ModuleBreakpoints3=
ModuleBreakpoints4=
ModuleBreakpoints5=
ModuleBreakpoints6=
ModuleBreakpoints7=
ModuleClosedNodes0=12,13
ModuleClosedNodes1=
ModuleClosedNodes2=
ModuleClosedNodes3=1
ModuleClosedNodes4=
ModuleClosedNodes5=
ModuleClosedNodes6=2,3,4,5,6,7,8,9,10,11,12,13,16
ModuleClosedNodes7=7,8
NavigationStack=Subs,ConvertMillisecondsToString,179,0,Main,actualizaLabelUU,173,5,Main,b_guardarId_Click,142,0,Visual Designer,Layout.bal,-100,6,Main,Globals,36,1,Main,Activity_Create,42,6,Starter,Timer1_Tick,54,0,Starter,Process_Globals,15,0,Subs,fechaKMT,141,0,Subs,mandaLocAServer,171,6
SelectedBuild=0
VisibleModules=5,2,7,3,6,4

180
FLP.bas Normal file
View File

@@ -0,0 +1,180 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Service
Version=10.5
@EndOfDesignText@
#Region Service Attributes
#StartAtBoot: True
#End Region
'******************************************************************************
'No olvidar agregar esta linea al editor de manifiesto:
' SetServiceAttribute(Tracker, android:foregroundServiceType, "location")
'
'En Starter agregar estas lineas en Process_Globals
' Public rp As RuntimePermissions
' Public FLP As FusedLocationProvider
' Private flpStarted As Boolean
'
'En Main agregar estas lineas a Activity_Resume
' Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_ACCESS_FINE_LOCATION)
' Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
' If Result Then
' StartService(Tracker)
' Log("Start Tracker")
' Else
' ToastMessageShow("No permission", True)
' End If
'
'Se necesita la libreria FusedLocationProvider, Phone, GPS y RunTimePermissions
'
'Y en Main agregar estas dos lineas:
'#AdditionalJar: com.android.support:support-v4
'#AdditionalJar: com.google.android.gms:play-services-location
Sub Process_Globals
Private nid As Int = 1
'Private GPS As GPS
Private Tracking As Boolean
Private LastUpdateTime As Long
Private lock As PhoneWakeState
'Para FusedLocationProvider (2 lineas)
Public FLP As FusedLocationProvider
Private flpStarted As Boolean
End Sub
Sub Service_Create
Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_NEVER 'we are handling it ourselves
'Para FusedLocationProvider (2 lineas)
FLP.Initialize("flp")
FLP.Connect
lock.PartialLock
StartFLP
End Sub
Sub flp_ConnectionSuccess
Log("Connected to location provider")
End Sub
Sub flp_ConnectionFailed(ConnectionResult1 As Int)
Log("Failed to connect to location provider")
End Sub
Sub Service_Start (StartingIntent As Intent)
'Para FusedLocationProvider (1 linea)
Service.StopAutomaticForeground
Service.StartForeground(nid, CreateNotification("..."))
StartServiceAt(Me, DateTime.Now + 30 * DateTime.TicksPerMinute, True)
Track
End Sub
Public Sub StartFLP
Log("StartFLP - flpStarted="&flpStarted)
Do While FLP.IsConnected = False
Sleep(500)
Log("sleeping")
Loop
If flpStarted = False Then
Log("RequestLocationUpdates")
FLP.RequestLocationUpdates(CreateLocationRequest) 'Buscamos ubicacion
Log("Buscamos ubicacion")
flpStarted = True
Else
FLP.RequestLocationUpdates(CreateLocationRequest2times) 'Buscamos ubicacion 2 peticiones
Log("Buscamos ubicacion 2 peticiones")
End If
End Sub
Private Sub CreateLocationRequest As LocationRequest
'Log("CreateLocationRequest")
Dim lr As LocationRequest
lr.Initialize
lr.SetInterval(10000)
lr.SetFastestInterval(lr.GetInterval / 2)
lr.SetSmallestDisplacement(10) 'Solo registra cambio de ubicacion si es mayor a 50 mts
lr.SetPriority(lr.Priority.PRIORITY_HIGH_ACCURACY)
Return lr
End Sub
Private Sub CreateLocationRequest2times As LocationRequest
'Log("CreateLocationRequest")
Dim lr As LocationRequest
lr.Initialize
lr.SetInterval(5000)
lr.SetFastestInterval(lr.GetInterval / 2)
lr.setNumUpdates(2)
lr.SetSmallestDisplacement(50) 'Solo registra cambio de ubicacion si es mayor a 50 mts
lr.SetPriority(lr.Priority.PRIORITY_HIGH_ACCURACY)
Return lr
End Sub
Public Sub StopFLP
'Log("StopFLP")
If flpStarted Then
FLP.RemoveLocationUpdates
flpStarted = False
End If
End Sub
Public Sub Track
'Log("Track")
If Tracking Then Return
If Starter.rp.Check(Starter.rp.PERMISSION_ACCESS_FINE_LOCATION) = False Then
Log("No permission")
Return
End If
'Para FusedLocationProvider (1 linea)
StartFLP
Tracking = True
End Sub
Sub flp_LocationChanged (Location1 As Location)
If DateTime.Now > LastUpdateTime + 10 * DateTime.TicksPerSecond Then
Dim n As Notification = CreateNotification($"$2.5{Location1.Latitude} / $2.5{Location1.Longitude}"$)
n.Notify(nid)
LastUpdateTime = DateTime.Now
End If
Log("loc changed")
Dim coords As String = Location1.Latitude&","&Location1.Longitude&","&Main.devModel
CallSub2(Main,"ubicacionRecibida",coords)
'Cambiamos el formato de la hora
Dim OrigFormat As String=DateTime.DateFormat 'save orig date format
DateTime.DateFormat="MMM-dd HH:mm:ss"
Dim lastUpdate As String=DateTime.Date(DateTime.Now)
DateTime.DateFormat=OrigFormat 'return to orig date format
'Escribimos coordenadas y fecha a un archivo de texto
' Dim ubic As String = Location1.Latitude&","&Location1.Longitude&"|"&lastUpdate
' Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", True)
' Dim s As String = ubic & CRLF
' Dim t() As Byte = s.GetBytes("UTF-8")
' out.WriteBytes(t, 0, t.Length)
' out.Close
Log("Loc changed : "&Location1.Latitude&","&Location1.Longitude&"|"&Location1.Accuracy&"|"&lastUpdate)
End Sub
Sub CreateNotification (Body As String) As Notification
Dim notification As Notification
notification.Initialize2(notification.IMPORTANCE_LOW)
notification.Icon = "icon"
notification.SetInfo("Tracking location", Body, Main)
Return notification
End Sub
Sub Service_Destroy
If Tracking Then
StopFLP
End If
Tracking = False
lock.ReleasePartialLock
End Sub
'//////////////////////////////////////////////////////////////////////////////////////////////
'//////////////////////////////// EXTRAS ///////////////////////////////////////////////////////
'//////////////////////////////////////////////////////////////////////////////////////////////
Public Sub StartLocationUpdates
FLP.RequestLocationUpdates(CreateLocationRequest)
End Sub

BIN
Files/gps_hist.db Normal file

Binary file not shown.

BIN
Files/layout.bal Normal file

Binary file not shown.

195
FirebaseMessaging.bas Normal file
View File

@@ -0,0 +1,195 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Service
Version=10.5
@EndOfDesignText@
'///////////////////////////////////////////////////////////////////////////////////////
'/// Agregar estas lineas al editor de manifiestos
'
' CreateResourceFromFile(Macro, FirebaseAnalytics.GooglePlayBase)
' CreateResourceFromFile(Macro, FirebaseAnalytics.Firebase)
' CreateResourceFromFile(Macro, FirebaseAnalytics.FirebaseAnalytics)
' CreateResourceFromFile(Macro, FirebaseNotifications.FirebaseNotifications)
'
'/// Agregar modulo de servicio nuevo FirebaseMessaging y copiar este modulo
'
'/// Bajar el archivo google-services.json de la consola de Firebase (https://console.firebase.google.com/)
'/// El nombre de la app en el archivo json tiene que ser el mismo que el nombre del paquete (Proyecto/Conf de Compilacion/Paquete)
'
'/// En Starter agregar esta linea
'
' Sub Service_Create
' CallSubDelayed(FirebaseMessaging, "SubscribeToTopics")
' End Sub
'
'/// En Main en Sub Process_Globals agregar esta linea
'
' Private const API_KEY As String = "AAAAv__xxxxxxxxxxxxx-xxxxxxxxxxxxxx-xxxxxxxxxxxx"
'
'/// Esta llave se consigue igualmente en la consola de Firebase, configuracion de proyecto, Cloud Messaging,
'/// es la clave de servidor.
'///
'/// Se necesitan agregar las librerías: FirebaseAnalitics, FirebaseNotifications, JSON y OkHttpUtils
'/// ... JSON es necesario si se van a enviar mensajes, si solo se van a recibir, no es necesario.
'
'///////////////////////////////////////////////////////////////////////////////////////
Sub Process_Globals
Private fm As FirebaseMessaging
Private const API_KEY As String = "AAAAv1qt3Lk:APA91bECIR-pHn6ul53eYyoVlpPuOo85RO-0zcAgEXwE7vqw8DFSbBtCaCINiqWQAkBBZXxHtQMdpU6B-jHIqgFKVL196UgwHv0Gw6_IgmipfV_NiItjzlH9d2QNpGLp9y_JUKVjUEhP"
Dim locRequest As String
Dim pe As PhoneEvents
Dim batt As Int
Dim au As String
Dim Sprvsr As String = "Sprv-ML"
End Sub
Sub Service_Create
Starter.ruta = File.DirInternal
fm.Initialize("fm") 'Inicializamos FirebaseMessaging
Subs.getPhnId
pe.Initialize("pe") 'Para obtener la bateria
Subs.revisaBD
End Sub
Public Sub SubscribeToTopics
' fm.SubscribeToTopic("Trckr") 'Global (you can subscribe to more topics)
fm.SubscribeToTopic("Trckr") 'Tracker Global
If Starter.logger Then Log("Subscrito a tracker global")
fm.SubscribeToTopic("Trckr-ML") 'Global (you can subscribe to more topics)
If Starter.logger Then Log("Subscrito a Trckr-ML")
fm.SubscribeToTopic(Starter.devModel) 'Propio (you can subscribe to more topics)
If Starter.logger Then Log("Subscrito a "&Starter.devModel)
If Starter.logger Then Log(fm.token)
fm.UnsubscribeFromTopic("Sprvsr") 'Unsubscribe from topic
End Sub
Sub Service_Start (StartingIntent As Intent)
Subs.getPhnId
Subs.gps_hist.Initialize(Starter.ruta,"gps_hist.db", True)
Subs.gps_hist.ExecNonQuery("CREATE TABLE IF NOT EXISTS RUTA_GPS(FECHA INTEGER, LAT TEXT, LON TEXT)")
If StartingIntent.IsInitialized Then fm.HandleIntent(StartingIntent)
Sleep(0)
Service.StopAutomaticForeground 'remove if not using B4A v8+.
StartServiceAt(Me, DateTime.Now + 15 * DateTime.TicksPerMinute, True) 'Iniciamos servicio cada XX minutos
End Sub
Sub fm_MessageArrived (Message As RemoteMessage)
If Starter.logger Then Log("Message arrived")
If Starter.logger Then Log($"Message data: ${Message.GetData}"$)
Subs.getPhnId
Subs.getSSID
If Message.GetData.ContainsKey("t") Then
Dim tipos As List = Regex.Split(",",Message.GetData.Get("t"))
If tipos.IndexOf("pu") <> -1 Or tipos.IndexOf("au") <> -1 Then 'Si es una peticion de ubicacion
If Starter.logger Then Log("Es una peticion de ubicacion")
If Starter.logger Then Log($"UUC: ${Starter.UUC.Latitude},${Starter.UUC.Longitude}"$)
If Starter.UUC.Latitude <> 0.0 Then
mandamosLoc($"${Starter.UUC.Latitude},${Starter.UUC.Longitude},${Subs.formatoFecha(Starter.UUC.Time)}"$)
If Starter.logger Then LogColor($"Mandamos UUC: ${Starter.UUC.Latitude},${Starter.UUC.Longitude},${Subs.formatoFecha(Starter.UUC.Time)}"$, Colors.Magenta)
End If
locRequest="Activa"
If Starter.logger Then Log("Llamamos StartFLP")
CallSubDelayed(Tracker, "StartFLP")
End If
If tipos.IndexOf("au") <> -1 Then 'Si es una actualizacion de ubicacion
au = 1
End If
If tipos.IndexOf("ping") <> -1 Then 'Si es un ping
If Starter.logger Then Log("Es un ping")
If Starter.logger Then Log("Mandamos pong")
Dim params As Map = CreateMap("topic":Sprvsr,"title":"pong", "body":Starter.devModel&" - Recibi mensaje "&Message.GetData.Get("title"), "t":"pong")
SendMessage(params)
End If
If tipos.IndexOf("bgps") <> -1 Then 'Si es una instruccion de borrar archivo gps
If Starter.logger Then Log("Es una instruccion de borrar archivo gps")
If Starter.logger Then Log("Borramos archivo gps")
Subs.borramosArchivoGPS
End If
If tipos.IndexOf("bgps2") <> -1 Then 'Si es una instruccion de borrar db gps
If Starter.logger Then Log("Es una instruccion de borrar archivo gps")
If Starter.logger Then Log("Borramos archivo gps")
Subs.deleteGPS_DB
End If
If tipos.IndexOf("dr") <> -1 Then 'Si es una peticion de ruta gps
If Starter.logger Then Log("Es una peticion de Ruta GPS")
Dim rutaGpsCmp As String = Subs.dameRuta
Dim params As Map = CreateMap("topic":Sprvsr,"title":"ruta", "body":Starter.devModel&" - Recibi mensaje "&Message.GetData.Get("title"), "t":"ruta", "r":rutaGpsCmp, "fr": Main.fechaRuta)
SendMessage(params)
End If
If tipos.IndexOf("pu") = -1 And tipos.IndexOf("ping") = -1 And tipos.IndexOf("dr") = -1 Then
if starter.logger then Log("No es ping ni solicitud de ubicacion o ruta, entonces no hacemos nada")
End If
End If
' Dim n As Notification
' n.Initialize
' n.Icon = "icon"
' n.SetInfo(Message.GetData.Get("title"), Message.GetData.Get("body"), Main)
' n.Notify(1)
End Sub
Sub Service_Destroy
End Sub
Sub SendMessage(params As Map)
Dim topic As String= params.Get("topic")
Dim title As String= params.Get("title")
Dim body As String= params.Get("body")
Dim tipo As String= params.Get("t")
If params.ContainsKey("r") Then
Dim rutaGpsCmp As String= params.Get("r")
Else
Dim rutaGpsCmp As String = ""
End If
Dim Job As HttpJob
Job.Initialize("fcm", Me)
Dim m As Map = CreateMap("to": $"/topics/${topic}"$)
Dim data As Map = CreateMap("title":title, "body":body, "d":Starter.devModel.Trim, "t":tipo, "w":Subs.ssid, "b":batt, "r":rutaGpsCmp, "v":Application.VersionName)
m.Put("data", data)
Dim jg As JSONGenerator
jg.Initialize(m)
Job.PostString("https://fcm.googleapis.com/fcm/send", jg.ToString)
Job.GetRequest.SetContentType("application/json;charset=UTF-8")
Job.GetRequest.SetHeader("Authorization", "key=" & API_KEY)
If Starter.logger Then Log("Mandamos mensaje: " & m)
End Sub
Sub mandamosLoc(coords As String)
If Starter.logger Then LogColor("Iniciamos mandamosLoc ("&coords&")", Colors.Magenta)
' Log("locRequest="&locRequest)
Subs.guardaInfoEnBD(coords)'Escribimos coordenadas y fecha a una bd
Dim t As String
If locRequest="Activa" Then
If au = 1 Then
t = "au" ' es una actualizacion
Else
t = "u" ' es una peticion
End If
Dim params As Map = CreateMap("topic":Sprvsr,"title":"ubicacionRecibida", "body":coords, "t":t)
SendMessage(params)
locRequest="Enviada"
CallSubDelayed(Tracker,"CreateLocationRequest")
End If
End Sub
Sub pe_BatteryChanged (Level As Int, Scale As Int, Plugged As Boolean, Intent As Intent)
batt=Level
End Sub
Sub PE_PhoneStateChanged (State As String, IncomingNumber As String, Intent As Intent)
If Starter.logger Then Log("Phone state: " & State)
If State = "RINGING" Then
if starter.logger then Log("The incoming number is: " & IncomingNumber)
Else
End If
End Sub
'Sub wifiScanned_ScanDone
' Log("//////////////////////////////wifi_conected_result")
' ToastMessageShow("Wifi_ConnectionResult",True)
' If Main.wifi.isWifiConnected Then
' ssid = Main.wifi.WifiSSID
' End If
'End Sub

35
Mods.bas Normal file
View File

@@ -0,0 +1,35 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=StaticCode
Version=11
@EndOfDesignText@
'Code module
Sub process_globals
End Sub
'Ver 3.07.07
'Se hicieron ajustes a la precision minima y a como y cuando manda los datos al servidor.
'Ver 2.01.29
'Se paso a "Starter.Service_Create" el código para al iniciar, copiar la base de datos a la tarjeta.
'Ver 2.01.14
'Se cambio codigo en "FirebaseMessaging.SendMessage" para que mande la version en cada mensaje "Application.VersionName"
'Agregué en Tracker:
'Sub formatoFecha(fecha As String) As String
' Log(fecha)
' Dim OrigFormat As String = DateTime.DateFormat 'save orig date format
' DateTime.DateFormat="yyMMddHHmmss"
' Dim lastUpdate As String=DateTime.Date(fecha)
' DateTime.DateFormat=OrigFormat 'return to orig date format
' Log(lastUpdate)
' Return lastUpdate
'End Sub
'Modifique Tracker/flp_LocationChanged usando la funcion formatofecha:
' Dim coords As String = Location1.Latitude&","&Location1.Longitude&","&formatoFecha(DateTime.Now)
'Modifiqué Tracker/dameUltimaUbicacionConocida usando la funcion formatofecha:
' Dim coords As String = FLP.GetLastKnownLocation.Latitude&","&FLP.GetLastKnownLocation.Longitude&","&formatoFecha(FLP.GetLastKnownLocation.Time)

210
NotificationService.bas Normal file
View File

@@ -0,0 +1,210 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Service
Version=11
@EndOfDesignText@
#Region Service Attributes
#StartAtBoot: False
#End Region
'##################################################################################################
'Requiere las liberias: Reflection y NotificationListener}
'##################################################################################################
'Agregar estas lienas al manifiesto:
'
'AddApplicationText(
'<Service android:name="b4a.jsaplication.com.br.ReplyAuto"
' android:label="Mariana" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
' <intent-filter><action android:name="android.service.notification.NotificationListenerService" /></intent-filter>
' </Service>)
'
'Lo siguiente es para revisar que tenga autorización para interceptar notificaciones, hay que ponerlo en Main o Starter:
' If Not(CheckNotificationAccess) Then
' Msgbox2Async($"Se necesita acceso a las notificaciones, haga clic en "Aceptar" y en la siguiente pantalla permita el acceso a la aplicación "${Application.LabelName}"."$, "Permisos necesarios", "Aceptar", "Cancelar", "", Null, True)
' Wait For Msgbox_Result (resultado As Int)
' If resultado = DialogResponse.POSITIVE Then
' Dim In As Intent
' In.Initialize("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS", "")
' StartActivity(In)
' End If
' End If
'
''Revisa si la aplicación tiene permiso para acceder a las notificaciones.
'Sub CheckNotificationAccess As Boolean
' Dim ph As Phone
' Dim nstr, pstr As String
' Dim r As Reflector
' pstr = r.GetStaticField("anywheresoftware.b4a.BA", "packageName")
' nstr = ph.GetSettings("enabled_notification_listeners")
' Return nstr.Contains(pstr)
'End Sub
'##################################################################################################
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim rp As ReplyAuto
' Dim activo As Boolean = True
' Dim ultimaNoti As String
Dim logger As Boolean = False 'ignore
End Sub
Sub Service_Create
rp.Initialize("NotiMon")
#if not(DEBUG)
logger = False
#end if
' If logger Then Log("**************** Iniciamos Monitor Keymon ***********************")
End Sub
Sub Service_Start (StartingIntent As Intent)
' Log("NotificationService Start")
If rp.HandleIntent(StartingIntent) Then Return
' DateTime.DateFormat = "mm"
' ultimaNoti = DateTime.Date(DateTime.now)
' If logger Then LogColor($"Ultima notificación en el minuto ${ultimaNoti}"$, Colors.green)
End Sub
Sub Service_Destroy
End Sub
Sub NotiMon_NotificationPosted (SBN As StatusBarNotification)
If not(Tracker.FLP.IsInitialized) then StartService(Tracker)
Private logger As Boolean = True
' Log("-= Notificacion recibida =-")
If SBN.PackageName = "com.whatsapp" Then
' If logger Then LogColor(SBN.PackageName, Colors.Red)
' If logger Then LogColor("isGroupWA2: "&isGroupWA(SBN),Colors.Magenta)
' If logger Then LogColor("isPersonWA: "&isPersonWA(SBN),Colors.Magenta)
' If logger Then Log($"getGroupName: |${getGroupName(SBN.Title)}|"$)
' Si recibimos un mensaje con la palabra "donde", "Donde" o "bien", entonces mandamos la última ubicación conocida.
If SBN.Message.Contains("donde") Or SBN.Message.Contains("Donde") Or SBN.Message.Contains("bien") Then 'Si el mensaje contiene "#NS" y tiene un segundo parametro ...
If esMensajeWAValido(SBN) Then
CallSub2(Tracker, "dameUltimaUbicacionConocida", Starter.UUC)
Log("Mandamos a Server")
End If
End If
End If
End Sub
'Regresa verdadero si el mensaje de whatsapp es un mensaje valido.
Sub esMensajeWAValido(SBN As StatusBarNotification) As Boolean 'ignore
Private valido As Boolean = False
Private ww() As String = Regex.Split("\|", SBN.Key)
If ww(3) <> Null And ww(3) <> "null" Then valido = True
Return valido
End Sub
'Returns TRUE if the sender is a GROUP.
'Searches the provided sbn.title for the string ": " to know if the sender is a group.
Sub isGroupWA2(sbnTitle As String) As Boolean 'ignore
Private x As Boolean = Regex.ismatch(".*(: ).*", sbnTitle)
Return x
End Sub
'Returns TRUE if the sender is a GROUP.
'Searches the provided notification object for the string "@g.us" and if found returns TRUE.
Sub isGroupWA(sbn As StatusBarNotification) As Boolean 'ignore
Private a As Boolean = False
If sbn.As(String).IndexOf("@g.us") > -1 Then a = True 'ignore
Return a
End Sub
'Returns TRUE if the sender is a PERSON.
'Searches the provided notification object for the string "@s.whatsapp.net" and if found returns TRUE.
Sub isPersonWA(sbn As StatusBarNotification) As Boolean 'ignore
Private a As Boolean = False
If sbn.As(String).IndexOf("@s.whatsapp.net") > -1 Then a = True 'ignore
Return a
End Sub
'Returns TRUE if the sender is a PERSON.
'Searches the provided notification object for the string "channel=individual" and if found returns TRUE.
Sub isPersonWA2(sbn As StatusBarNotification) As Boolean 'ignore
Private a As Boolean = False
If sbn.As(String).IndexOf("channel=individual") > -1 Then a = True 'ignore
Return a
End Sub
'Returns the sender's number.
'Searches the provided notification object and gets the numbers between "shortcut=" and "@s.whatsapp.net".
Sub getNumberWA(sbn As StatusBarNotification) As String
Private a As Int = sbn.As(String).IndexOf("@s.whatsapp.net") 'ignore
If a > -1 Then
Private x As String = sbn.As(String) 'ignore
Private y As Int = x.IndexOf("shortcut=")
If (y+9) > 0 And a > (y+9) Then x = x.SubString2(y+9, a) Else x = "Not a person"
Else 'It is probably is a group.
x = "Not a person"
End If
Return x
End Sub
'Returns the name of the group from the given text.
'If it is not a group, then returns the notification's title.
Sub getGroupName(sbnTitle As String) As String 'ignore
Private a As Int = sbnTitle.IndexOf(": ")
Private x As String = sbnTitle
If a > -1 Then
Private b As String = sbnTitle.SubString2(0, a)
x = Regex.Replace(" \(.+\)", b, "")
End If
Return x
End Sub
'Returns the name of the group from the given notification object.
'Searches the provided notification for the string "hiddenConversationTitle" and if found, gets the name.
'If it is not a group,then it returns the notification's title.
Sub getGroupName2(sbn As StatusBarNotification) As String 'ignore
Private inicio As Int = sbn.Extras.As(String).IndexOf("hiddenConversationTitle=") 'ignore
If inicio > -1 And sbn.Extras.As(String).IndexOf("hiddenConversationTitle=null") = -1 Then 'ignore
Private x As String = sbn.Extras.As(String) 'ignore
Private fin As Int = x.IndexOf(", android.reduced.images=")
x = x.SubString2(inicio+24, fin)
x = Regex.Replace(" \(.+\)", x, "") 'Replace anything between () with "", this en the case that we have something like "MyGroupName (5 messages)"
Else 'Is not from a group.
Private x As String = sbn.Title
End If
Return x
End Sub
'Returns the person's name (or the number) when the message comes from a group.
'Searches the provided sbn.title for the string ": " in the title and returns the string after that,
'if it does not find ": " then returns the complete string.
Sub getPersonFromGroup(sbnTitle As String) As String 'ignore
Private a As Int = sbnTitle.IndexOf(": ")
If a = -1 Then a = -2 'Is not from a group.
Private b As String = sbnTitle.SubString(a+2)
Return b
End Sub
'Returns the NUMBER of the sender and if NOT a person, then returns the name of the group.
Sub getNumberOrGroupWA(sbn As StatusBarNotification) As String 'ignore
Private numRemitente As String = getNumberWA(sbn)
If numRemitente = "Not a person" Then numRemitente = getGroupName(sbn.Title)
Return numRemitente
End Sub
'Regresa el "shortcut" del remitente.
'Si es de un grupo, es algo como "120363023512345678@g.us"
'Si es de una persona, entonces "5215512345678@s.whatsapp.net"
Sub getShortcut(sbn As StatusBarNotification) As String 'ignore
Private ap As Int = sbn.As(String).IndexOf("@s.whatsapp.net") 'ignore
Private ag As Int = sbn.As(String).IndexOf("@g.us") 'ignore
Private x As String = sbn.As(String) 'ignore
Private y As Int = x.IndexOf("shortcut=")
If ap > -1 Then
Private x As String = sbn.As(String) 'ignore
Private y As Int = x.IndexOf("shortcut=")
x = x.SubString2(y+9, ap+15)
Else if ag > -1 Then 'It is probably is a group.
Private x As String = sbn.As(String) 'ignore
Private y As Int = x.IndexOf("shortcut=")
x = x.SubString2(y+9, ag+5)
End If
Return x
End Sub

76
Starter.bas Normal file
View File

@@ -0,0 +1,76 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Service
Version=9.9
@EndOfDesignText@
#Region Service Attributes
#StartAtBoot: False
#ExcludeFromLibrary: True
#End Region
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Public rp As RuntimePermissions 'Para obtener permisos android 6+
Public FLP As FusedLocationProvider 'Para Tracker
Dim ruta As String
Dim reqManager As DBRequestManager
Dim cmd As DBCommand
Dim Timer1 As Timer
Dim interval As Int = 60 '600 segs (10 mins)
Dim UUC As Location
Dim run As Int = 0 'ignore
Dim devModel As String
Dim lastLocUpdate As String = 0
Dim logger As Boolean = True
End Sub
Sub Service_Create
'This is the program entry point.
'This is a good place to load resources that are not specific to a single activity.
ruta = File.DirInternal 'Ruta de la base de datos por defecto.
If File.ExternalWritable Then ruta = rp.GetSafeDirDefaultExternal("") 'Si podemos escribir a la tarjeta, cambiamos la ruta.
If Not(File.Exists(ruta, "gps_hist.db")) Then File.Copy(File.DirAssets, "gps_hist.db", ruta, "gps_hist.db") 'Si no existe el archivo de la base de datos, lo copiamos.
If logger Then Log(ruta)
CallSubDelayed(FirebaseMessaging, "SubscribeToTopics") 'Para FirebaseMessaging
End Sub
Sub Service_Start (StartingIntent As Intent)
Service.StopAutomaticForeground 'Starter service can start in the foreground state in some edge cases.
' reqManager.Initialize(Me, "http://10.0.0.205:1782")
reqManager.Initialize(Me, "http://keymon.lat:1782")
Timer1.Initialize("Timer1", interval * 1000)
Timer1.Enabled = True
UUC.Initialize
Subs.getPhnId
StartService(Tracker)
#if RELEASE
logger = False
#end if
End Sub
Private Sub Timer1_Tick
' ToastMessageShow("Timer",False)
If logger Then Log("Next run " & DateTime.Time(DateTime.Now + interval * 1000))
' Log($"|${Tracker.FLP.IsInitialized}|${Tracker.FLP.GetLastKnownLocation.IsInitialized}|"$)If DateTime.DateForm
CallSub2(Tracker, "dameUltimaUbicacionConocida", UUC)
'Si ya pasaron mas de 15 minutos (900 segs) desde la ultima actualización, entonces mandamos UUC.
If ((DateTime.now - lastLocUpdate)/1000) > (interval * 1.5) Then
LogColor($"Mandamos ubicacion porque no se ha enviado en ${(interval * 1.5)} segs."$, Colors.red)
Subs.mandaLocAServer(Tracker.FLP.GetLastKnownLocation, devModel)
End If
End Sub
Sub Service_TaskRemoved
'This event will be raised when the user removes the app from the recent apps list.
End Sub
'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
Return True
End Sub
Sub Service_Destroy
End Sub

188
Subs.bas Normal file
View File

@@ -0,0 +1,188 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=StaticCode
Version=11
@EndOfDesignText@
'Code module
'Subs in this code module will be accessible from all modules.
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Public GZip As GZipStrings
Private su As StringUtils
Dim phn As Phone
Dim devModel As String
Dim gps_hist As SQL
Dim wifi As MLwifi
Dim ssid As String
End Sub
Sub getPhnId 'Pone el valor de phn.Model en la variable global "devModel"
Private elId As String
If File.Exists(File.DirInternal, "phnId.txt") Then
elId = File.ReadString(File.DirInternal, "phnId.txt")
Else
File.WriteString(File.DirInternal, "phnId.txt", "") 'Creamos el archivo
End If
If elId.Length < 3 Then 'Si el modelo del archivo es menos de 2, lo sustituimos con devmodel
devModel = phn.Model
If devModel.Length > 1 Then elId = devModel
End If
If elId.Length < 3 Then 'Si el modelo del archivo es menos de 2, lo sustituimos con android_id
elId = phn.GetSettings("android_id") 'Intentamos con "android_id"
End If
If elId.Length < 3 Then elId = $"dev${DateTime.GetHour(DateTime.Now)}"$
File.WriteString(File.DirInternal, "phnId.txt", elId) 'Sobreescribimos archivo phnId.txt with elId
If Starter.logger Then Log("Escribimos phnId: "&elId&" a "&File.DirInternal&"/phnId.txt")
Starter.devModel = elId
If Starter.logger Then Log(Starter.devModel)
End Sub
Sub compress(str As String) As String ' Compresion
Dim compressed() As Byte = GZip.compress(str)
Log($"CompressedBytesLength: ${compressed.Length}"$)
Dim base64 As String = su.EncodeBase64(compressed)
Log($"CompressedBytes converted to base64 Length: ${base64.Length}"$)
Log($"CompressedBytes converted to base64: ${base64}"$)
Return base64
End Sub
Sub decompress(base64 As String) As String ' Descompresion 'ignore
Dim decompressedbytes() As Byte = su.DecodeBase64(base64)
Log($"decompressedbytesLength: ${decompressedbytes.Length}"$)
Dim bc As ByteConverter
Dim uncompressed As String = bc.StringFromBytes(decompressedbytes,"UTF8")
Log($"uncompressedLength: ${uncompressed.Length}"$)
Log($"Decompressed String = ${uncompressed}"$)
Return uncompressed
End Sub
Sub formatoFecha(fecha As String) As String 'Convierte una fecha al formato yyMMddHHmmss
' Log(fecha)
Dim OrigFormat As String = DateTime.DateFormat 'save orig date format
DateTime.DateFormat="yyMMddHHmmss"
Dim lastUpdate As String=DateTime.Date(fecha)
DateTime.DateFormat=OrigFormat 'return to orig date format
' Log(lastUpdate)
Return lastUpdate
End Sub
Sub CreateNotification (Body As String) As Notification
Dim notification As Notification
notification.Initialize2(notification.IMPORTANCE_LOW)
notification.Icon = "icon"
notification.SetInfo("FLP", Body, Main)
Return notification
End Sub
Sub guardaInfoEnArchivo(coords As String) 'Escribimos coordenadas y fecha a un archivo de texto 'ignore
' Cambiamos el formato de la hora
Dim OrigFormat As String=DateTime.DateFormat 'save orig date format
DateTime.DateFormat="MMM-dd HH:mm:ss"
Dim lastUpdate As String=DateTime.Date(DateTime.Now)
DateTime.DateFormat=OrigFormat 'return to orig date format
Dim ubic As String = coords&","&lastUpdate
Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", True)
Dim s As String = ubic & CRLF
Dim t() As Byte = s.GetBytes("UTF-8")
out.WriteBytes(t, 0, t.Length)
out.Close
End Sub
Sub guardaInfoEnBD(coords As String) 'Escribimos coordenadas y fecha a una BD
If Starter.logger Then Log("Guardamos ubicacion en db (" & coords & ")")
Dim latlon() As String = Regex.Split(",", coords)
If gps_hist.IsInitialized = False Then gps_hist.Initialize(Starter.ruta, "gps_hist.db", True)
gps_hist.ExecNonQuery2("INSERT INTO RUTA_GPS(fecha, lat, lon) VALUES (?,?,?)", Array As Object (latlon(2),latlon(0),latlon(1)))
End Sub
Sub dameRuta As String
Dim c As Cursor
If gps_hist.IsInitialized = False Then gps_hist.Initialize(Starter.ruta, "gps_hist.db", True)
c = gps_hist.ExecQuery("select FECHA, LAT, LON from RUTA_GPS order by FECHA desc limit 380")
c.Position = 0
Dim ruta2 As String = ""
If c.RowCount>0 Then
For i=0 To c.RowCount -1
c.Position=i
ruta2=ruta2&CRLF&c.GetString("LAT")&","&c.GetString("LON")
Main.fechaRuta = c.GetString("FECHA")
Next
End If
c.Close
Return compress(ruta2)
End Sub
Sub deleteGPS_DB
' gps_hist.ExecQuery
gps_hist.ExecNonQuery("delete from RUTA_GPS")
gps_hist.ExecNonQuery("vacuum;")
Log("RUTA_GPS borrada")
End Sub
Sub borramosArchivoGPS
Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", False)
Dim s As String = ""
Dim t() As Byte = s.GetBytes("UTF-8")
out.WriteBytes(t, 0, t.Length)
out.Close
End Sub
Sub revisaBD
' Starter.ruta = File.DirInternal
If File.Exists(Starter.ruta, "gps_hist.db") = False Then
File.Copy(File.DirAssets, "gps_hist.db", Starter.ruta, "gps_hist.db")
Log("No existe gps_hist, copiamos gps_hist.db")
End If
End Sub
Sub getSSID
If wifi.isWifiConnected Then
ssid = wifi.WifiSSID
End If
End Sub
'Convierte una fecha al formato yyMMddHHmmss
Sub fechaKMT(fecha As String) As String 'ignore
' Log(fecha)
Dim OrigFormat As String = DateTime.DateFormat 'save orig date format
DateTime.DateFormat="yyMMddHHmmss"
Dim nuevaFecha As String=DateTime.Date(fecha)
DateTime.DateFormat=OrigFormat 'return to orig date format
' Log(nuevaFecha)
Return nuevaFecha
End Sub
'Sub dameUltimaUbicacionConocida(lastLocation As Location)
' Log(0)
' If Tracker.FLP.GetLastKnownLocation.IsInitialized Then 'Mandamos ultima ubicacion guardada
' Log("dameUltimaUbicacionConocida")
' If Tracker.FLP.GetLastKnownLocation.Accuracy < 30 And Tracker.FLP.GetLastKnownLocation.DistanceTo(lastLocation) > 50 Then
' Starter.UUC = Tracker.FLP.GetLastKnownLocation
' mandaLocAServer(Tracker.FLP.GetLastKnownLocation, Starter.devModel)
' Log($"UUC: ${Starter.UUC.Latitude},${Starter.UUC.Longitude}"$)
' End If
' End If
'End Sub
Sub mandaLocAServer(loc As Location, id As String)
Starter.lastLocUpdate = DateTime.Now
CallSubDelayed(Main, "actualizaLabelUU")
Starter.cmd.Initialize
Starter.cmd.Name = "guardaDatos"
Starter.cmd.Parameters = Array As Object(fechaKMT(DateTime.Now), id, fechaKMT(DateTime.Now), $"${loc.Latitude},${loc.Longitude},${loc.Accuracy},${loc.AccuracyValid},${loc.Speed},${loc.SpeedValid}"$, "Coords")
' If Starter.logger Then
Log($"Mandamos loc a server: ${fechaKMT(DateTime.Now)}|${id}|${fechaKMT(DateTime.Now)}|${loc.Latitude},${loc.Longitude}|Coords"$)
' End If
Starter.reqManager.ExecuteCommand(Starter.cmd,"guardaDatos")
End Sub
Sub ConvertMillisecondsToString(t As Long) As String
Dim hours, minutes, seconds As Int
hours = t / DateTime.TicksPerHour
minutes = (t Mod DateTime.TicksPerHour) / DateTime.TicksPerMinute
seconds = (t Mod DateTime.TicksPerMinute) / DateTime.TicksPerSecond
Return $"$1.0{hours}:$2.0{minutes}:$2.0{seconds}"$
End Sub

160
Tracker.bas Normal file
View File

@@ -0,0 +1,160 @@
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Service
Version=10.5
@EndOfDesignText@
#Region Service Attributes
#StartAtBoot: True
#End Region
'******************************************************************************
'No olvidar agregar esta linea al editor de manifiesto:
' SetServiceAttribute(Tracker, android:foregroundServiceType, "location")
'
'En Starter agregar estas lineas en Process_Globals
' Public rp As RuntimePermissions
' Public FLP As FusedLocationProvider
' Private flpStarted As Boolean
'
'En Main agregar estas lineas a Activity_Resume
' Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_ACCESS_FINE_LOCATION)
' Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
' If Result Then
' StartService(Tracker)
' Log("Start Tracker")
' Else
' ToastMessageShow("No permission", True)
' End If
'
'Se necesitan las librerias FusedLocationProvider, GPS, Phone y RunTimePermissions
'
'Y en Main agregar estas dos lineas:
'#AdditionalJar: com.android.support:support-v4
'#AdditionalJar: com.google.android.gms:play-services-location
Sub Process_Globals
Private nid As Int = 1
Private Tracking As Boolean
Private lock As PhoneWakeState
'Para FusedLocationProvider (2 lineas)
Public FLP As FusedLocationProvider
Private flpStarted As Boolean
Dim minAccuracy As Int = 50
End Sub
Sub Service_Create
Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_NEVER 'we are handling it ourselves
'Para FusedLocationProvider (2 lineas)
FLP.Initialize("flp")
FLP.Connect
lock.PartialLock
StartFLP
If Starter.logger Then Log("FLP initialized")
End Sub
Sub flp_ConnectionSuccess
If Starter.logger Then Log("Connected to location provider")
'FLP.GetLastKnownLocation
End Sub
Sub flp_ConnectionFailed(ConnectionResult1 As Int)
if starter.logger then Log("Failed to connect to location provider")
End Sub
Sub Service_Start (StartingIntent As Intent)
'Para FusedLocationProvider (1 linea)
Service.StopAutomaticForeground
Service.StartForeground(nid, Subs.CreateNotification("..."))
Track
StartServiceAt(Me, DateTime.Now + 10 * DateTime.TicksPerMinute, True)
End Sub
Public Sub Track
'Log("Track")
If Tracking Then Return 'Si ya estamos "rastreando" no hacemos nada (return)
If Starter.rp.Check(Starter.rp.PERMISSION_ACCESS_FINE_LOCATION) = False Then
Log("No permission")
Return
End If
StartFLP 'Iniciamos FusedLocationProvider
Tracking = True
End Sub
Public Sub StartFLP
Log("StartFLP - flpStarted="&flpStarted)
Do While FLP.IsConnected = False
Sleep(500)
Log("sleeping")
Loop
' If flpStarted = False Then
Log("RequestLocationUpdates")
FLP.RequestLocationUpdates(CreateLocationRequest) 'Buscamos ubicacion
Log("Buscamos ubicacion")
flpStarted = True
' End If
End Sub
Private Sub CreateLocationRequest As LocationRequest
' Log("CreateLocationRequest")
Dim lr As LocationRequest
lr.Initialize
lr.SetInterval(30000) 'Intervalo deseado para actualizaciones de ubicacion en milisegundos
lr.SetFastestInterval(lr.GetInterval / 2) 'Intervalo minimo para actualizaciones de ubicacion
lr.SetSmallestDisplacement(30) 'Solo registra cambio de ubicacion si es mayor a XX mts
lr.SetPriority(lr.Priority.PRIORITY_HIGH_ACCURACY)
Return lr
End Sub
Sub dameUltimaUbicacionConocida(lastLocation As Location)
If Starter.logger Then LogColor("dameUltimaUbicacionConocida", Colors.Magenta)
If FLP.GetLastKnownLocation.IsInitialized Then 'Mandamos ultima ubicacion guardada
If Starter.logger Then Log("This accuracy: " & FLP.GetLastKnownLocation.Accuracy)
If Starter.logger Then Log("This distance to previous: " & FLP.GetLastKnownLocation.DistanceTo(lastLocation))
Dim coords As String = FLP.GetLastKnownLocation.Latitude&","&FLP.GetLastKnownLocation.Longitude&","&Subs.formatoFecha(FLP.GetLastKnownLocation.Time)
If FLP.GetLastKnownLocation.Accuracy < 30 And FLP.GetLastKnownLocation.DistanceTo(lastLocation) > 25 Then
Starter.UUC = FLP.GetLastKnownLocation
Subs.mandaLocAServer(FLP.GetLastKnownLocation, Starter.devModel)
If Starter.logger Then Log("Mandamos GetLastKnownLocation : "&DateTime.Time(FLP.GetLastKnownLocation.Time))
CallSubDelayed2(FirebaseMessaging,"mandamosLoc",coords)
Log($"UUC: ${Starter.UUC.Latitude},${Starter.UUC.Longitude}"$)
End If
' Log($"ultima actualizacion: ${Starter.lastLocUpdate}"$)
' Log($"${DateTime.now} - ${Starter.lastLocUpdate} = ${(DateTime.Now - Starter.lastLocUpdate)/1000}"$)
' Log("||" & Subs.ConvertMillisecondsToString((DateTime.Now - Starter.lastLocUpdate)))
End If
End Sub
Public Sub StopFLP
'Log("StopFLP")
If flpStarted Then
FLP.RemoveLocationUpdates 'Eliminamos todas las solicitudes de ubicacion
flpStarted = False
End If
End Sub
Sub flp_LocationChanged (Location1 As Location)
If Not(Starter.Timer1.Enabled) Then Starter.Timer1.Enabled = True : Log("timer enabled")
If Starter.logger Then LogColor("FLP_LocationChanged", Colors.Red)
' ToastMessageShow("FLP_LocationChanged", False)
Dim coords As String = Location1.Latitude&","&Location1.Longitude&","&Subs.formatoFecha(DateTime.Now)
Main.laUbicacion = Location1
' ToastMessageShow(coords, False)
' Log("Mandamos Ubicacion")
If Starter.logger Then Log(FirebaseMessaging.locRequest)
If Starter.logger Then Log(Location1)
If Starter.logger Then Log(Location1.Accuracy&" - "&Location1.AccuracyValid)
' solo mandamos la ubicacion si la precision es dentro de XX mts
If Location1.Accuracy < minAccuracy Then CallSubDelayed2(FirebaseMessaging,"mandamosLoc",coords)
If Location1.Accuracy < minAccuracy Then Starter.UUC = Location1
If Location1.Accuracy < minAccuracy Then Subs.mandaLocAServer(Location1, Starter.devModel)
if starter.logger then Log("Loc changed : "&Location1.Latitude&","&Location1.Longitude&"|"&Starter.devModel&"|")
CallSubDelayed(Main, "ponCoords")
End Sub
Sub Service_Destroy
If Tracking Then
StopFLP
End If
Tracking = False
lock.ReleasePartialLock
End Sub

126
google-services.json Normal file
View File

@@ -0,0 +1,126 @@
{
"project_info": {
"project_number": "821860097209",
"project_id": "pusher-4c091",
"storage_bucket": "pusher-4c091.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:821860097209:android:4a9c1af4c93ba100f24f68",
"android_client_info": {
"package_name": "flp2.chv.com"
}
},
"oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDS-_5lpLX5IiKYrG-0Et-KCKx1bwlY7R0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:821860097209:android:7b6620b2a870f23cf24f68",
"android_client_info": {
"package_name": "gunav2.keymon.com.mx"
}
},
"oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDS-_5lpLX5IiKYrG-0Et-KCKx1bwlY7R0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:821860097209:android:7780f81ae43bf0f3f24f68",
"android_client_info": {
"package_name": "pusher.chv.com"
}
},
"oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDS-_5lpLX5IiKYrG-0Et-KCKx1bwlY7R0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:821860097209:android:7c55bc95da6d952df24f68",
"android_client_info": {
"package_name": "ths.keymon.com.mx"
}
},
"oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDS-_5lpLX5IiKYrG-0Et-KCKx1bwlY7R0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "821860097209-ef17t5620111ghub7l0tple62otbb56v.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}