diff --git a/B4A/B4XMainPage.bas b/B4A/B4XMainPage.bas
index 36981d5..d4659a6 100644
--- a/B4A/B4XMainPage.bas
+++ b/B4A/B4XMainPage.bas
@@ -92,6 +92,8 @@ Sub Class_Globals
Private l_server As Label
Public rutaBDBackup As String = ""
Private b_envioBD As Button
+ Dim MES1 As ManageExternalStorage
+ Dim device As Phone
End Sub
Public Sub Initialize
@@ -185,14 +187,14 @@ Private Sub B4XPage_Created (Root1 As B4XView)
End Try
' If sDate = "20190523" Then
' Starter.db.ExecNonQuery2("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = ?", Array As Object ("SERVER"))
-' Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER", Starter.server))
+' Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER", Starter.DBReqServer))
' End If
' Starter.db.ExecNonQuery2("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = ?", Array As Object ("ULTIMOMODULO"))
' Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("ULTIMOMODULO", "MAIN"))
c=Starter.db.ExecQuery2("select count(*) as CUANTOS from CAT_VARIABLES WHERE CAT_VA_DESCRIPCION = ?", Array As String ("SERVER"))
c.Position =0
If c.GetString("CUANTOS") = 0 Then
- Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER", Starter.server))
+ Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER", Starter.DBReqServer))
' Else
' c=Starter.db.ExecQuery2("select CAT_VA_VALOR from CAT_VARIABLES WHERE CAT_VA_DESCRIPCION = ?", Array As String ("SERVER"))
' c.Position = 0
@@ -300,13 +302,37 @@ Private Sub B4XPage_Created (Root1 As B4XView)
' If Result Then Log("Tenemos permisos de bluetooth.")
' Log("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
' Log("Check phone state: " & rp.Check(rp.PERMISSION_READ_PHONE_STATE))
+
+ MES1.Initialize(Me, "MES1")
+ ' get the device SDK version
+ Dim SdkVersion As Int = device.SdkVersion
+ ' Choose which permission to request in order to access external storgage
+ If SdkVersion < 30 Then
+' Log("SDK = " & SdkVersion & " : Requesting WRITE_EXTERNAL_STORAGE permission")
+ Dim rp As RuntimePermissions
+ rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE) ' Implicit read capability if granted
+ Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
+' Log($"PERMISSION_WRITE_EXTERNAL_STORAGE = ${Result}"$)
+ Else
+' Log("SDK = " & SdkVersion & " : Requesting MANAGE_EXTERNAL_STORAGE permission")
+' Log("On Entry MANAGE_EXTERNAL_STORAGE = " & MES1.HasPermission)
+ If Not(MES1.HasPermission) Then
+ Dim r As String = Msgbox2("This app requires access to all files, please enable the option", "Manage All Files", "OK", "", "", Null)
+ If r = DialogResponse.POSITIVE Then
+ MES1.GetPermission
+' Wait For Msgbox_Result(Res As Int)
+' Log("Getting permission")
+ Wait For MES_StorageAvailable
+ End If
+ End If
+ End If
End Sub
Sub B4XPage_Appear
' server = "http://keymon.com.mx:1782"
' server = "http://201.99.139.28:1782"
' server = "http://177.244.63.54:1782"
- reqManager.Initialize(Me, Starter.server)
+ reqManager.Initialize(Me, Starter.DBReqServer)
Starter.montoActual = 0
Starter.clientesTotal = 0
Starter.clientesVenta = 0
@@ -366,7 +392,7 @@ Sub Entrar_Click
If user.Text = "ALTERNO" Then
c=Starter.db.ExecQuery2("select CAT_CO_CONFIGURACION, CAT_CO_RESULTADO from CAT_CODIGOS where CAT_CO_PONDERACION =1 AND CAT_CO_ACCION = ?", Array As String("SERVER"))
c.Position =0
- Starter.server = c.GetString("CAT_CO_CONFIGURACION")
+ Starter.DBReqServer = c.GetString("CAT_CO_CONFIGURACION")
alterno = c.GetString("CAT_CO_RESULTADO")
c.Close
If alterno = 1 Then
@@ -378,10 +404,10 @@ Sub Entrar_Click
End If
c=Starter.db.ExecQuery2("select CAT_CO_CONFIGURACION, CAT_CO_RESULTADO from CAT_CODIGOS where CAT_CO_PONDERACION =1 AND CAT_CO_ACCION = ?", Array As String("SERVER"))
c.Position =0
- Starter.server = c.GetString("CAT_CO_CONFIGURACION")
- user.Text = Starter.server
+ Starter.DBReqServer = c.GetString("CAT_CO_CONFIGURACION")
+ user.Text = Starter.DBReqServer
c.Close
-' reqManager.Initialize(Me, Starter.server)
+' reqManager.Initialize(Me, Starter.DBReqServer)
else if user.Text = "KMTSKLL1" Then
Starter.db.ExecNonQuery("delete from usuarioa")
Starter.db.ExecNonQuery2("INSERT INTO USUARIOA VALUES (?,?,?)", Array As Object(user.Text, pass.Text, DateTime.Date(DateTime.Now)))
@@ -498,7 +524,7 @@ Private Sub B4XPage_CloseRequest As ResumableSub
If Panel1.Visible Then
Panel1.Visible = False
Entrar.Visible = True
- Return True
+ Return False
Else
If logger Then Log("Saliendo")
B4XPages.ClosePage(Me)
@@ -575,10 +601,10 @@ End Sub
Sub B_SERVER_Click
Starter.db.ExecNonQuery2("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = ?", Array As Object ("SERVER"))
Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER",E_SERVER.text))
- Starter.server = E_SERVER.text
- If logger Then Log("Inicializamos reqManager con " & Starter.server)
- reqManager.Initialize(Me, Starter.server)
- CallSubDelayed(Starter, "reinicializaReqManager")
+ Starter.DBReqServer = E_SERVER.text
+ If logger Then Log("Inicializamos reqManager con " & Starter.DBReqServer)
+ reqManager.Initialize(Me, Starter.DBReqServer)
+ CallSubDelayed2(Starter, "reinicializaReqManager", Starter.DBReqServer)
Panel1.Visible = False
Entrar.Visible = True
End Sub
diff --git a/B4A/C_Cliente.bas b/B4A/C_Cliente.bas
index 382ffe8..3ebc52a 100644
--- a/B4A/C_Cliente.bas
+++ b/B4A/C_Cliente.bas
@@ -363,7 +363,7 @@ End Sub
Sub B4XPage_Appear
Log(Starter.rp.Check("android.permission.BLUETOOTH_CONNECT"))
- reqManager.Initialize(Me, Starter.server)
+ reqManager.Initialize(Me, Starter.DBReqServer)
' Log(Subs.traeUltimaActividadBD)
Subs.panelVisibleCompleto(P_INF_GENERAL, Root)
' P_INF_GENERAL.Height = Root.Height
@@ -3719,7 +3719,7 @@ Private Sub b_geopass_Click
cmd.Name = "select_geoPass"
cmd.Parameters = Array As Object(et_geopass.Text, Subs.traeAlmacen, Subs.traeRuta)
reqManager.ExecuteQuery(cmd , 0, "traeGeoPass")
- Log($"${Starter.server}, ${et_geopass.Text}, ${Subs.traeAlmacen}, ${Subs.traeRuta}"$)
+ Log($"${Starter.DBReqServer}, ${et_geopass.Text}, ${Subs.traeAlmacen}, ${Subs.traeRuta}"$)
et_geopass.Text = ""
End If
b_noVenta.Visible = True
diff --git a/B4A/C_Principal.bas b/B4A/C_Principal.bas
index 6130d77..7f3ff46 100644
--- a/B4A/C_Principal.bas
+++ b/B4A/C_Principal.bas
@@ -9,6 +9,8 @@ Sub Class_Globals
Private Root As B4XView 'ignore
Private xui As XUI 'ignore
Dim reqManager As DBRequestManager
+ Dim device As Phone
+ Dim kh As kms_helperSubs
Dim rp As RuntimePermissions
Dim t1 As Timer
Dim t2 As Timer
@@ -58,7 +60,7 @@ Sub Class_Globals
Dim Listo4 As String
Dim Listo5 As String
Dim EJECUTANDO As String
- Dim res As String
+' Dim res As String
Dim inve As String
Dim cuantos_pedidosc As String
Dim cuantos_pedido As String
@@ -182,10 +184,14 @@ Sub Class_Globals
Private l_porcentaje As Label
Private detenerLoop As Boolean = False
Dim logger As Boolean = True
+ Private admin As BluetoothAdmin
+ Public BluetoothState, ConnectionState As Boolean
+ Private ion As Object
End Sub
'You can add more parameters here.
Public Sub Initialize As Object
+ admin.Initialize("admin")
Return Me
End Sub
@@ -203,7 +209,7 @@ Private Sub B4XPage_Created (Root1 As B4XView)
fecha=DateTime.Date(DateTime.Now)
c=Starter.db.ExecQuery2("select CAT_CO_CONFIGURACION from CAT_CODIGOS where CAT_CO_PONDERACION =1 AND CAT_CO_ACCION = ?", Array As String("SERVER"))
c.Position =0
- Starter.server = c.GetString("CAT_CO_CONFIGURACION")
+ Starter.DBReqServer = c.GetString("CAT_CO_CONFIGURACION")
c.Close
b=Starter.db.ExecQuery("Select count(*) as CUANTOS from pedido_cliente")
b.Position=0
@@ -252,33 +258,97 @@ Private Sub B4XPage_Created (Root1 As B4XView)
l_ctast.Text = d.GetString("TOTAL_VISITAR")
'l_porvisitar.Text = e.GetString("POR_VISITAR")
End If
- ' Log("Permisos BT: " & rp.Check("android.permission.BLUETOOTH_CONNECT"))
- Log("XXXXXXXXXXXXXXXXXXXXXXXXX REVISAMOS PERMISOS DE BT")
- rp.CheckAndRequest("android.permission.BLUETOOTH_CONNECT")
- Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
- If Result Then Log("Tenemos permisos de bluetooth.")
+ kh.Initialize(Me, "kh")
+ kh.RD_Init
+ Log("XXXXXXXXXXXXXXXXXXXXXXXXX REVISAMOS PERMISOS DE BT - APPEAR -")
+ StartBluetooth
Log("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
-' Log("Check phone state: " & rp.Check(rp.PERMISSION_READ_PHONE_STATE))
+
+End Sub
+
+Private Sub StartBluetooth
+ If admin.IsEnabled = False Then
+ Wait For (EnableBluetooth) Complete (Success As Boolean)
+ If Success = False Then
+ ToastMessageShow("Failed to enable bluetooth", True)
+ End If
+ End If
+ BluetoothState = admin.IsEnabled
+ StateChanged
+End Sub
+
+Private Sub StateChanged
+' btnSearchForDevices.Enabled = BluetoothState
+' btnAllowConnection.Enabled = BluetoothState
+' ChatPage1.btnSend.Enabled = ConnectionState
+End Sub
+
+Private Sub EnableBluetooth As ResumableSub
+ ToastMessageShow("Enabling Bluetooth adapter...", False)
+ Dim ph As Phone
+ If ph.SdkVersion >= 31 Then
+ Log(31)
+ rp.CheckAndRequest("android.permission.BLUETOOTH_CONNECT")
+ Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
+ Log(Result)
+ If Result = False Then Return False
+ If ph.SdkVersion >= 33 Then
+ Log(33)
+ Dim in As Intent
+ in.Initialize("android.bluetooth.adapter.action.REQUEST_ENABLE", "")
+ StartActivityForResult(in)
+ Wait For ion_Event (MethodName As String, Args() As Object)
+ Return admin.IsEnabled
+ End If
+ End If
+ Return admin.Enable
+End Sub
+
+Private Sub StartActivityForResult(i As Intent)
+ Dim jo As JavaObject = GetBA
+ ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
+ jo.RunMethod("startActivityForResult", Array As Object(ion, i))
+End Sub
+
+Sub GetBA As Object
+ Dim jo As JavaObject = Me
+ Return jo.RunMethod("getBA", Null)
End Sub
'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.
Sub B4XPage_Appear
+ If Not(kh.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
If Subs.traeUltimaActividadBD <> "principal" Then Subs.iniciaActividad(Subs.traeUltimaActividadBD)
- reqManager.Initialize(Me, Starter.server)
- Starter.btAdmin.Initialize("btAdmin")
- Log("BTADMIN INICIALIZADO: "&Starter.btAdmin.IsEnabled)
- If Not(Starter.btAdmin.IsEnabled) Then Starter.btAdmin.Enable 'Si no esta prendido el BT, lo prendemos.
+ reqManager.Initialize(Me, Starter.DBReqServer)
+' If Not(btAdmin.IsEnabled) Then btAdmin.Enable 'Si no esta prendido el BT, lo prendemos.
+ If kh.RD_Init_IsInitialized Then
+ kh.RD_respalda_cat_detalle_paq
+ kh.RD_respalda_cat_gunaprod
+ kh.RD_respalda_cat_gunaprod2
+ kh.RD_respalda_kmt_info
+ kh.RD_respalda_pedido
+ Else
+ Log("****** RD NO INICIALIZADO ********")
+ End If
e_ruta.Enabled = True
Starter.rutaV = l_ruta.Text
c=Starter.db.ExecQuery2("select count(*) as CUANTOS from CAT_VARIABLES WHERE CAT_VA_DESCRIPCION = ?", Array As String ("SERVER"))
c.Position =0
If c.GetString("CUANTOS") = 0 Then
- Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER", Starter.server))
+ Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER", Starter.DBReqServer))
Else
c=Starter.db.ExecQuery2("select CAT_VA_VALOR from CAT_VARIABLES WHERE CAT_VA_DESCRIPCION = ?", Array As String ("SERVER"))
c.Position =0
- Starter.server = c.GetString("CAT_VA_VALOR")
+ Starter.DBReqServer = c.GetString("CAT_VA_VALOR")
End If
c=Starter.db.ExecQuery2("select CAT_VA_VALOR from CAT_VARIABLES WHERE CAT_VA_DESCRIPCION = ?", Array As String ("FECHA"))
If c.RowCount > 0 Then
@@ -350,10 +420,10 @@ Sub B4XPage_Appear
Not(File.Exists(File.DirInternal,"FOTO2.jpg")) Or _
Not(File.Exists(File.DirInternal,"FOTO3.jpg")) Or _
Not(File.Exists(File.DirInternal,"FOTO4.jpg")) Then
- If Not(File.Exists(File.DirInternal,"FOTO1.jpg")) Then Log("Falta foto1")
- If Not(File.Exists(File.DirInternal,"FOTO2.jpg")) Then Log("Falta foto2")
- If Not(File.Exists(File.DirInternal,"FOTO3.jpg")) Then Log("Falta foto3")
- If Not(File.Exists(File.DirInternal,"FOTO4.jpg")) Then Log("Falta foto4")
+' If Not(File.Exists(File.DirInternal,"FOTO1.jpg")) Then Log("Falta foto1")
+' If Not(File.Exists(File.DirInternal,"FOTO2.jpg")) Then Log("Falta foto2")
+' If Not(File.Exists(File.DirInternal,"FOTO3.jpg")) Then Log("Falta foto3")
+' If Not(File.Exists(File.DirInternal,"FOTO4.jpg")) Then Log("Falta foto4")
Cedis_Check = 0
End If
If Cedis_Check = 0 And l_ruta.Text <> 0 Then
@@ -380,17 +450,17 @@ Sub B4XPage_Appear
' Subs.guardaUltimaActividadBD("principal")
- Log("Check phone state: " & rp.Check(rp.PERMISSION_READ_PHONE_STATE))
- Log("Pedimos permisos de estado del cel")
+' Log("Check phone state: " & rp.Check(rp.PERMISSION_READ_PHONE_STATE))
+' Log("Pedimos permisos de estado del cel")
rp.CheckAndRequest(rp.PERMISSION_READ_PHONE_STATE)
Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
If Result Then
Dim Phn As PhoneId
' IMEN.Text = "" 'Phn.GetDeviceId
imei ="" ' Phn.GetDeviceId
- If logger Then LogColor($"////////////////// IMEI: ${imei} ////////////////// "$, Colors.Blue)
+' If logger Then LogColor($"////////////////// IMEI: ${imei} ////////////////// "$, Colors.Blue)
End If
- Log("Permisos cel terminados")
+' Log("Permisos cel terminados")
' Log("Permisos BT: " & rp.Check("android.permission.BLUETOOTH_CONNECT"))
' Log("REVISAMOS PERMISOS DE BT")
@@ -2881,7 +2951,7 @@ Sub descargaCartaPorte
' Log(cartaPortePDF)
'Para el servidor
Private pdfServer As String = "keymon.lat"
- If Starter.server.IndexOf("10.0.0.205") > -1 Then pdfServer = "10.0.0.205"
+ If Starter.DBReqServer.IndexOf("10.0.0.205") > -1 Then pdfServer = "10.0.0.205"
' Log(pdfServer)
pdfURL = $"https://${pdfServer}/CartaPorteKelloggs/CartaPorteMovil${DateTime.Date(DateTime.now)}/${cartaPortePDF}"$
LogColor(pdfURL,Colors.Red)
diff --git a/B4A/KelloggsV4.b4a b/B4A/KelloggsV4.b4a
index 682811c..d06d6ec 100644
--- a/B4A/KelloggsV4.b4a
+++ b/B4A/KelloggsV4.b4a
@@ -129,13 +129,14 @@ Library27=xcustomlistview
Library28=xui
Library29=zxing_scanner
Library3=baqrcode
+Library30=replyauto
Library4=bitmapcreator
Library5=byteconverter
Library6=camera
Library7=contentresolver
Library8=core
Library9=fileprovider
-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~~\n~)~\n~SetApplicationAttribute(android:icon, "@drawable/icon")~\n~SetApplicationAttribute(android:label, "$LABEL$")~\n~CreateResourceFromFile(Macro, Themes.LightTheme)~\n~'End of default text.~\n~~\n~AddApplicationText(~\n~)~\n~'Set activity to Landscape~\n~SetActivityAttribute(foto, android:screenOrientation, "landscape")~\n~AddApplicationText(~\n~~\n~ ~\n~)~\n~AddManifestText(~\n~~\n~)~\n~'''' para el teclado~\n~ SetActivityAttribute(main, android:windowSoftInputMode, adjustResize|stateHidden)~\n~ SetApplicationAttribute(android:allowBackup, "false")~\n~ SetServiceAttribute(Tracker, android:foregroundServiceType, "location")~\n~ ~\n~ AddManifestText(~\n~~\n~)~\n~''CreateResourceFromFile(Macro, FirebaseAnalytics.GooglePlayBase)~\n~ 'End of default text.~\n~ ~\n~SetApplicationAttribute(android:usesCleartextTraffic, "true")~\n~ AddManifestText(~\n~~\n~)~\n~AddPermission(android.permission.ACCESS_BACKGROUND_LOCATION)~\n~AddManifestText(~\n~~\n~)~\n~AddManifestText(~\n~~\n~)~\n~AddManifestText(~\n~~\n~)~\n~AddManifestText(~\n~~\n~)~\n~AddManifestText(~\n~~\n~)~\n~AddPermission(android.permission.ACCESS_FINE_LOCATION)~\n~AddPermission(android.permission.BLUETOOTH_ADVERTISE)~\n~AddPermission(android.permission.BLUETOOTH_CONNECT)~\n~AddPermission(android.permission.BLUETOOTH_SCAN)~\n~AddManifestText(~\n~~\n~) 'in order to access the device non-resettable identifiers such as IMEI and serial number.~\n~~\n~'///////////////////////// FLP Y PUSH /////////////~\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~'Le da mas memoria a la aplicacion~\n~SetApplicationAttribute(android:largeHeap, "true")~\n~ AddApplicationText(~\n~ ~\n~ ~\n~ ~\n~ )~\n~ CreateResource(xml, provider_paths,~\n~ ~\n~ ~\n~ ~\n~ ~\n~ ~\n~ )~\n~~\n~'Si al cargar un mapa de google manda este error "java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/ProtocolVersion". agregar la siguiente linea:~\n~AddApplicationText()~\n~SetApplicationAttribute(android:allowBackup, "false")~\n~AddManifestText()
+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~~\n~)~\n~SetApplicationAttribute(android:icon, "@drawable/icon")~\n~SetApplicationAttribute(android:label, "$LABEL$")~\n~CreateResourceFromFile(Macro, Themes.LightTheme)~\n~'End of default text.~\n~~\n~AddApplicationText(~\n~)~\n~'Set activity to Landscape~\n~SetActivityAttribute(foto, android:screenOrientation, "landscape")~\n~AddApplicationText(~\n~~\n~ ~\n~)~\n~AddManifestText(~\n~~\n~)~\n~'''' para el teclado~\n~ SetActivityAttribute(main, android:windowSoftInputMode, adjustResize|stateHidden)~\n~ SetApplicationAttribute(android:allowBackup, "false")~\n~ SetServiceAttribute(Tracker, android:foregroundServiceType, "location")~\n~ ~\n~ AddManifestText(~\n~~\n~)~\n~''CreateResourceFromFile(Macro, FirebaseAnalytics.GooglePlayBase)~\n~ 'End of default text.~\n~ ~\n~SetApplicationAttribute(android:usesCleartextTraffic, "true")~\n~ AddManifestText(~\n~~\n~)~\n~AddPermission(android.permission.ACCESS_BACKGROUND_LOCATION)~\n~AddManifestText(~\n~~\n~)~\n~AddManifestText()~\n~'AddManifestText()~\n~'AddManifestText()~\n~'AddManifestText()~\n~~\n~AddPermission(android.permission.ACCESS_FINE_LOCATION)~\n~AddPermission(android.permission.BLUETOOTH_ADVERTISE)~\n~AddPermission(android.permission.BLUETOOTH_CONNECT)~\n~AddPermission(android.permission.BLUETOOTH_SCAN)~\n~~\n~AddPermission(android.permission.MANAGE_EXTERNAL_STORAGE)~\n~AddManifestText() 'in order to access the device non-resettable identifiers such as IMEI and serial number.~\n~~\n~'///////////////////////// FLP Y PUSH /////////////~\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~'Le da mas memoria a la aplicacion~\n~SetApplicationAttribute(android:largeHeap, "true")~\n~AddApplicationText(~\n~ ~\n~ ~\n~ ~\n~)~\n~CreateResource(xml, provider_paths, ~\n~~\n~ ~\n~ ~\n~ ~\n~~\n~)~\n~~\n~'Si al cargar un mapa de google manda este error "java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/ProtocolVersion". agregar la siguiente linea:~\n~AddApplicationText()~\n~SetApplicationAttribute(android:allowBackup, "false")~\n~AddManifestText()~\n~AddApplicationText(~\n~~\n~ ~\n~ )
Module1=B4XMainPage
Module10=C_Pedidos
Module11=C_Principal
@@ -151,13 +152,16 @@ Module2=C_CheckList
Module20=errorManager
Module21=EscPosPrinter
Module22=foto
-Module23=MAPA_RUTAS
-Module24=Mods
-Module25=SD_Spinner
-Module26=Starter
-Module27=Subs
-Module28=Tracker
+Module23=kms_helperSubs
+Module24=ManageExternalStorage
+Module25=MAPA_RUTAS
+Module26=Mods
+Module27=NotificationService
+Module28=SD_Spinner
+Module29=Starter
Module3=C_Cliente
+Module30=Subs
+Module31=Tracker
Module4=C_Clientes
Module5=C_Historico
Module6=C_Mapas
@@ -165,8 +169,8 @@ Module7=C_Nota
Module8=C_NoVenta
Module9=C_NuevoCliente
NumberOfFiles=53
-NumberOfLibraries=29
-NumberOfModules=28
+NumberOfLibraries=30
+NumberOfModules=31
Version=12.5
@EndOfDesignText@
#Region Project Attributes
diff --git a/B4A/KelloggsV4.b4a.meta b/B4A/KelloggsV4.b4a.meta
index 8f24261..1a26da9 100644
--- a/B4A/KelloggsV4.b4a.meta
+++ b/B4A/KelloggsV4.b4a.meta
@@ -20,7 +20,10 @@ ModuleBookmarks25=
ModuleBookmarks26=
ModuleBookmarks27=
ModuleBookmarks28=
+ModuleBookmarks29=
ModuleBookmarks3=
+ModuleBookmarks30=
+ModuleBookmarks31=
ModuleBookmarks4=
ModuleBookmarks5=
ModuleBookmarks6=
@@ -49,7 +52,10 @@ ModuleBreakpoints25=
ModuleBreakpoints26=
ModuleBreakpoints27=
ModuleBreakpoints28=
+ModuleBreakpoints29=
ModuleBreakpoints3=
+ModuleBreakpoints30=
+ModuleBreakpoints31=
ModuleBreakpoints4=
ModuleBreakpoints5=
ModuleBreakpoints6=
@@ -72,19 +78,22 @@ ModuleClosedNodes2=
ModuleClosedNodes20=
ModuleClosedNodes21=20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39
ModuleClosedNodes22=
-ModuleClosedNodes23=
+ModuleClosedNodes23=6,7,8,9,10
ModuleClosedNodes24=
ModuleClosedNodes25=
ModuleClosedNodes26=
ModuleClosedNodes27=
ModuleClosedNodes28=
+ModuleClosedNodes29=
ModuleClosedNodes3=1
+ModuleClosedNodes30=
+ModuleClosedNodes31=
ModuleClosedNodes4=
ModuleClosedNodes5=
ModuleClosedNodes6=
ModuleClosedNodes7=
ModuleClosedNodes8=
ModuleClosedNodes9=
-NavigationStack=C_Pedidos,Class_Globals,4,0,C_Cliente,Class_Globals,0,0,C_Cliente,B4XPage_Created,281,0,C_Cliente,Initialize,278,0,C_Cliente,B_VENTA_Click,1918,0,C_Cliente,B4XPage_Appear,452,0,Visual Designer,cliente.bal,-100,2,C_Cliente,ListView1_ItemLongClick,708,0,C_Cliente,GPS_LocationChanged,695,5,C_Productos,lv_prodsPedido_ItemLongClick,886,6,C_Productos,clv_prods_ll_VisibleRangeChanged,1030,0
+NavigationStack=kms_helperSubs,logJobDoneResultados,410,0,kms_helperSubs,CheckNotificationAccess,413,0,C_Principal,descargaCartaPorte,2940,0,C_Principal,cargar_Click,561,0,C_Principal,B4XPage_Appear,321,2,C_Principal,EnableBluetooth,297,0,B4XMainPage,B_SERVER_Click,600,0,B4XMainPage,B4XPage_CloseRequest,520,1,B4XMainPage,JobDone,510,0,C_Principal,GetBA,312,0
SelectedBuild=0
-VisibleModules=1,26,11,14,27,3,4,13,12,2,10
+VisibleModules=1,29,11,23,27,14,30,3,4,13,12
diff --git a/B4A/ManageExternalStorage.bas b/B4A/ManageExternalStorage.bas
new file mode 100644
index 0000000..3b05516
--- /dev/null
+++ b/B4A/ManageExternalStorage.bas
@@ -0,0 +1,79 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=10.7
+@EndOfDesignText@
+' Version 1.00
+#Event: StorageAvailable
+Sub Class_Globals
+ Private ion As Object
+ Private mCallback As Object
+ Private mEventName As String
+
+End Sub
+
+
+' This pretty trivial class is modeled on (plagiarised from!) Erel's ExternalStorage class
+' It applies to devices implementing SDK30 and later
+' It allows apps to access the internal 'external' storage as was possible on earlier Android versions ussing traditional file I/O
+' You must manually add 'AddPermission(android.permission.MANAGE_EXTERNAL_STORAGE)' to the manifest
+' You must ensure that you provide the package name of your app in Sub GetPermission
+' This class uses the MANAGE_APP_ALL_FILES_ACCESS_PERMISSION intent action to direct users to a system settings page
+' They must enable the option on that page to give permission
+
+'Initializes the object
+Public Sub Initialize (Callback As Object, EventName As String)
+ mCallback = Callback
+ mEventName = EventName
+End Sub
+
+
+' Determine if the app already has MANAGE_EXTERNAL_STORAGE call Environment.isExternalStorageManager()
+' Return True if this app already has MANAGE_EXTERNAL_STORAGE permission
+Public Sub HasPermission As Boolean
+ Dim has As Boolean
+ Dim jo As JavaObject
+ jo.InitializeStatic("android.os.Environment")
+ has = jo.RunMethod("isExternalStorageManager", Null)
+ Return has
+End Sub
+
+' Check whether this app has MANAGE_EXTERNAL_STORAGE permission
+' If not show the user a dialog to enable MANAGE_EXTERNAL_STORAGE permission for this app
+' Raises the StorageAvailable event in the calling activity when complete
+Public Sub GetPermission
+ If HasPermission Then
+ RaiseEvent
+ Return
+ End If
+ Dim in As Intent
+ ' Be sure to reference your app package name in "pakageg:xxx"
+ in.Initialize("android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION", $"package:${Application.PackageName}"$)
+ StartActivityForResult(in)
+End Sub
+
+
+Private Sub RaiseEvent
+ Log("Calling : " & mEventName & "_StorageAvailable")
+ CallSubDelayed(mCallback, mEventName & "_StorageAvailable")
+End Sub
+
+
+Private Sub ion_Event (MethodName As String, Args() As Object) As Object
+ RaiseEvent
+ Return Null
+End Sub
+
+
+Private Sub StartActivityForResult(i As Intent)
+ Dim jo As JavaObject = GetBA
+ ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
+ jo.RunMethod("startActivityForResult", Array As Object(ion, i))
+End Sub
+
+Private Sub GetBA As Object
+ Dim jo As JavaObject = Me
+ Return jo.RunMethod("getBA", Null)
+End Sub
+
diff --git a/B4A/NotificationService.bas b/B4A/NotificationService.bas
new file mode 100644
index 0000000..8bd9e86
--- /dev/null
+++ b/B4A/NotificationService.bas
@@ -0,0 +1,178 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Service
+Version=11
+@EndOfDesignText@
+#Region Service Attributes
+ #StartAtBoot: False
+#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 rp As ReplyAuto
+' Dim activo As Boolean = True
+' Dim ultimaNoti As String
+ Dim logger As Boolean = False
+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)
+ Private logger As Boolean = True
+ 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)}|"$)
+ Private cmd() As String = Regex.Split(" ", SBN.Message)
+ If SBN.Message.StartsWith("#NS") And cmd.Length = 2 Then 'Si el mensaje contiene "#NS" y tiene un segundo parametro ...
+ If esMensajeWAValido(SBN) Then
+' Log(cmd(1))
+ rp.ClearNotification(SBN)
+ Starter.reinicializaReqManager(cmd(1))
+ rp.reply(SBN.Notification, SBN.PackageName, $"Servidor cambiado a ${cmd(1)} "$)
+ Sleep(1000)
+' rp.ClearNotification(SBN)
+ rp.ClearAll
+ 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
+ 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
+ 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
\ No newline at end of file
diff --git a/B4A/Starter.bas b/B4A/Starter.bas
index 58ad8ce..95d159e 100644
--- a/B4A/Starter.bas
+++ b/B4A/Starter.bas
@@ -26,7 +26,7 @@ Sub Process_Globals
'Para ENVIA_ULTIMA_GPS
Dim Timer1 As Timer
Dim Interval As Int = 300
- Dim server As String
+ Dim DBReqServer As String
Dim pe As PhoneEvents
Dim ph As Phone
Dim marcaCel As String = ph.manufacturer
@@ -66,15 +66,15 @@ Sub Service_Create
ubicacionActual.Initialize
pe.Initialize("pe") 'Para obtener la bateria
db = s.dbInit 'Inicializamos BD.
- server = "http://keymon.lat:1782"
+ DBReqServer = "http://keymon.lat:1782"
Private c As Cursor = db.ExecQuery($"select CAT_VA_VALOR from CAT_VARIABLES WHERE CAT_VA_DESCRIPCION = 'SERVER'"$)
If c.RowCount > 0 Then
c.Position = 0
- server = c.GetString("CAT_VA_VALOR")
+ DBReqServer = c.GetString("CAT_VA_VALOR")
End If
c.Close
- reqManager.Initialize(Me, server) 'Inicializamos reqManager.
- If Logger Then Log($"Starter reqManager server: ${server}"$)
+ reqManager.Initialize(Me, DBReqServer) 'Inicializamos reqManager.
+ If Logger Then Log($"Starter reqManager server: ${DBReqServer}"$)
'Para los Logs
#if RELEASE
logcat.LogCatStart(Array As String("-v","raw","*:F","B4A:v"), "logcat")
@@ -133,10 +133,10 @@ Private Sub Timer1_Tick
ENVIA_ULTIMA_GPS 'Comentado para que no estorbe hasta que no esten los queries correctos en el config.properties
End Sub
-Sub reinicializaReqManager
- reqManager.Initialize(Me, server)
- If Logger Then Log(server)
-End Sub
+'Sub reinicializaReqManager
+' reqManager.Initialize(Me, server)
+' If Logger Then Log(server)
+'End Sub
Sub ENVIA_ULTIMA_GPS
If Logger Then Log("Iniciamos ENVIA_ULTIMA_GPS")
@@ -227,3 +227,12 @@ Sub revisaBD 'ignore
If Not(File.Exists(ruta, "kmt.db")) Then File.Copy(File.DirAssets, "kmt.db", ruta, "kmt.db")
If Not(db.IsInitialized) Then db.Initialize(ruta, "kmt.db", True)
End Sub
+
+'Inicializa el reqServer con la dirección dada y lo guarda en CAT_VARIABLES.
+Sub reinicializaReqManager(srv As String)
+ db.ExecNonQuery2("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = ?", Array As Object ("SERVER"))
+ db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER", srv))
+ DBReqServer = srv
+ reqManager.Initialize(Me, srv)
+' LogColor(srv, Colors.red)
+End Sub
\ No newline at end of file
diff --git a/B4A/Subs.bas b/B4A/Subs.bas
index 40c027f..992507a 100644
--- a/B4A/Subs.bas
+++ b/B4A/Subs.bas
@@ -687,7 +687,7 @@ End Sub
'Guarda el nombre de la pagina en base de datos la muestra.
Sub iniciaActividad(ia As String)
If ia <> "" And ia <> Null Then
- If Starter.logger Then LogColor($"Guardamos en BD '${ia}'"$, Colors.Yellow)
+' If Starter.logger Then LogColor($"Guardamos en BD '${ia}'"$, Colors.Yellow)
Starter.db.ExecNonQuery2("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = ?", Array As Object ("ULTIMOMODULO"))
Starter.db.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("ULTIMOMODULO", ia))
B4XPages.ShowPage(ia)
diff --git a/B4A/kms_helperSubs.bas b/B4A/kms_helperSubs.bas
new file mode 100644
index 0000000..979f055
--- /dev/null
+++ b/B4A/kms_helperSubs.bas
@@ -0,0 +1,550 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=12.2
+@EndOfDesignText@
+Sub Class_Globals
+ Private Root As B4XView 'ignore
+ Private xui As XUI 'ignore
+ Dim skmt, rkmt As SQL
+ Private EventName As String 'ignore
+ Private CallBack As Object 'ignore
+ Dim rp As RuntimePermissions
+ Dim safePath As String
+ Dim fechaHoy As String
+ Dim skmtAttached As Boolean = False
+ '####### MES Vars ######
+ Private ion As Object
+ Dim device As Phone
+ Private mesCallback As Object
+ Private mesEventName As String
+ Dim RD_Init_IsInitialized As Boolean = False
+ Dim btAdmin As BluetoothAdmin
+End Sub
+
+'Inicializa la clase "kms_helperSubs".
+Public Sub Initialize (vCallback As Object, vEventName As String) As Object
+ EventName = vEventName
+ CallBack = vCallback
+ Return Me
+End Sub
+
+'This event will be called once, before the page becomes visible.
+'Private Sub B4XPage_Created (Root1 As B4XView)
+' Root = Root1
+' 'load the layout to Root
+'End Sub
+
+'RD - Inicializa Respaldo Diario
+Sub RD_Init
+ Log("************************** " & safePath)
+ Dim Dirp As String = File.DirRootExternal
+ Dim Dir As String
+' Dim Dir2 As String
+ Try
+ File.MakeDir(Dirp,"/kmts")
+ Dir = "/kmts"
+' Log("creado en kmts " & Dirp & Dir)
+ Catch
+ Dir = ""
+' Log("creado en raiz")
+ End Try
+ safePath = Dirp & Dir
+ Log($"Safepath:${safePath}"$)
+ Private name() As String = Regex.split(" ", Application.LabelName)
+ rkmt.Initialize(safePath,$"${name(0)}.rkmt.km"$, True)
+ skmt.Initialize(File.DirInternal,"kmt.db", False)
+' rkmt.ExecNonQuery($"create table if not exists pedidos (pe_folio NUMERIC, pe_desc NUMERIC, pe_costo_sin TEXT, pe_ruta TEXT, pe_cedis TEXT, pe_costo_tot NUMERIC, pe_costou NUMERIC, pe_cant NUMERIC, pe_pronombre TEXT, pe_proid TEXT, pe_cliente TEXT, pe_fecha TEXT, pe_usuario TEXT, pe_envio_ok TEXT)"$)
+' rkmt.ExecNonQuery($"create table if not exists inventarios (cat_gp_iniciativa TEXT, cat_gp_tipoprod TEXT, cat_gp_dev TEXT, cat_gp_almacen NUMERIC, cat_gp_id TEXT, cat_gp_nombre TEXT, cat_gp_imp1 TEXT, cat_gp_imp2 TEXT, cat_gp_precio TEXT, cat_gp_clasif TEXT, cat_gp_sts TEXT, cat_gp_tipo TEXT, cat_gp_subtipo TEXT, cat_gp_tipoprod2 TEXT, fecha TEXT)"$)
+'' rkmt.ExecNonQuery($"create table if not exists inventarios2 (cat_gp_iniciativa TEXT, cat_gp_tipoprod TEXT, cat_gp_dev TEXT, cat_gp_almacen NUMERIC, cat_gp_id TEXT, cat_gp_nombre TEXT, cat_gp_imp1 TEXT, cat_gp_imp2 TEXT, cat_gp_precio TEXT, cat_gp_clasif TEXT, cat_gp_sts TEXT, cat_gp_tipo TEXT, cat_gp_subtipo TEXT, cat_gp_tipoprod2 TEXT, fecha TEXT)"$)
+' rkmt.ExecNonQuery($"create table if not exists paquetes (cat_dp_precio_simptos TEXT, cat_dp_precio TEXT, cat_dp_almacen TEXT, cat_dp_id TEXT, cat_dp_idprod TEXT, cat_dp_tipo TEXT, cat_dp_pzas TEXT, cat_dp_usuario TEXT, cat_dp_fecha TEXT, cat_dp_regalo TEXT, cat_dp_clasif TEXT, fecha TEXT)"$)
+ If chkIfTableExists(skmt, "PEDIDO") Then rkmt.ExecNonQuery($"create table if not exists PEDIDO (${getTableColumnList(skmt, "PEDIDO")}, FECHA TEXT)"$)
+ If chkIfTableExists(skmt, "CAT_DETALLES_PAQ") Then rkmt.ExecNonQuery($"create table if not exists CAT_DETALLES_PAQ (${getTableColumnList(skmt, "CAT_DETALLES_PAQ")}, FECHA TEXT)"$)
+ If chkIfTableExists(skmt, "CAT_GUNAPROD") Then rkmt.ExecNonQuery($"create table if not exists CAT_GUNAPROD (${getTableColumnList(skmt, "CAT_GUNAPROD")}, FECHA TEXT)"$)
+ If chkIfTableExists(skmt, "CAT_GUNAPROD2") Then rkmt.ExecNonQuery($"create table if not exists CAT_GUNAPROD2 (${getTableColumnList(skmt, "CAT_GUNAPROD2")}, FECHA TEXT)"$)
+ If chkIfTableExists(skmt, "kmt_info") Then rkmt.ExecNonQuery($"create table if not exists kmt_info (${getTableColumnList(skmt, "kmt_info")}, FECHA TEXT)"$)
+ DateTime.DateFormat = "MM/dd/yyyy"
+ fechaHoy = DateTime.Date(DateTime.Now)
+ Log("RKMTS: " & rkmt.IsInitialized)
+ If revisaSkmtAttached And rkmt.IsInitialized Then RD_Init_IsInitialized = True Else RD_Init_IsInitialized = False
+End Sub
+
+'RD - Revisa si esta montada "kmt.db" como "skmt1" y si no, la monta
+'Para que "rkmt" vea a "skmt", es necesario montarla (attach).
+Sub revisaSkmtAttached As Boolean
+ skmtAttached = False
+ Dim rs As ResultSet = rkmt.ExecQuery("SELECT * FROM pragma_database_list")
+ Do While rs.NextRow 'Revisamos si esta montada "kmt.db" como "skmt1" y si no, la montamos.
+ If rs.GetString("name") = "skmt1" Then skmtAttached = True
+ Loop
+ If Not(skmtAttached) Then
+ rkmt.ExecNonQuery($"attach database '${File.Combine(File.DirInternal, "kmt.db")}' as skmt1;"$)
+ skmtAttached = True
+ End If
+ Return skmtAttached
+End Sub
+
+'Inicializa la BD con "kmt.db" en "File.DirInternal", si el archivo no existe, lo copia desde "File.DirAssets".
+'Ej: dim skmt as sql = dbInit
+Sub dbInit As SQL 'ignore
+ Private db As SQL
+ If File.Exists(File.DirInternal, "kmt.db") = False Then File.Copy(File.DirAssets, "kmt.db", File.DirInternal, "kmt.db")
+ db.Initialize(File.DirInternal,"kmt.db", True)
+' dbOk(True)
+' Log(db.IsInitialized)
+ Return db
+End Sub
+
+'RD - Copia la tabla PEDIDO a rkmt.db en la tarjeta del celular.
+Sub RD_respalda_pedido
+ Private inicio As String = DateTime.Now
+' Log("Copiando PEDIDO ...")
+ Private lasCols As String = getTableColumnListName(skmt, "PEDIDO")
+ rkmt.BeginTransaction
+ rkmt.ExecNonQuery($"delete from PEDIDO where FECHA = '${fechaHoy}'"$)
+ rkmt.ExecNonQuery($"insert into PEDIDO (${lasCols}, FECHA) select ${lasCols}, '${fechaHoy}' as FECHA from skmt1.PEDIDO where substr(pe_fecha, 1, 10) = '${fechaHoy}'"$)
+ rkmt.TransactionSuccessful 'Si no se pone TransactionSuccessful no se escribe NADA!!
+ rkmt.EndTransaction
+ Log(((DateTime.Now - inicio)/1000) & " segs")
+End Sub
+
+'RD - Copia la tabla CAT_GUNAPRODS a rkmt.db en la tarjeta del celular.
+Sub RD_respalda_cat_gunaprod
+ Private inicio As String = DateTime.Now
+' Log("Copiando CAT_GUNAPROD ...")
+ Private lasCols As String = getTableColumnListName(skmt, "CAT_GUNAPROD")
+ lasCols = lasCols.Replace(", CAT_GP_IMG", "") 'Quitamos la imagen del respaldo.
+ rkmt.BeginTransaction
+ rkmt.ExecNonQuery($"delete from CAT_GUNAPROD where FECHA = '${fechaHoy}'"$)
+ rkmt.ExecNonQuery($"insert into CAT_GUNAPROD (${lasCols}, FECHA) select ${lasCols}, '${fechaHoy}' as FECHA from skmt1.CAT_GUNAPROD"$)
+ rkmt.TransactionSuccessful 'Si no se pone TransactionSuccessful no se escribe NADA!!
+ rkmt.EndTransaction
+ Log(((DateTime.Now - inicio)/1000) & " segs")
+End Sub
+
+'RD - Copia la tabla CAT_GUNAPROD2 a rkmt.db en la tarjeta del celular.
+Sub RD_respalda_cat_gunaprod2
+ Private inicio As String = DateTime.Now
+' Log("Copiando CAT_GUNAPROD2 ...")
+ Private lasCols As String = getTableColumnListName(skmt, "CAT_GUNAPROD2")
+ lasCols = lasCols.Replace(", CAT_GP_IMG", "") 'Quitamos la imagen del respaldo.
+ rkmt.BeginTransaction
+ rkmt.ExecNonQuery($"delete from CAT_GUNAPROD2 where FECHA = '${fechaHoy}'"$)
+ rkmt.ExecNonQuery($"insert into CAT_GUNAPROD2 (${lasCols}, FECHA) select ${lasCols}, '${fechaHoy}' as FECHA from skmt1.CAT_GUNAPROD2"$)
+ rkmt.TransactionSuccessful 'Si no se pone TransactionSuccessful no se escribe NADA!!
+ rkmt.EndTransaction
+ Log(((DateTime.Now - inicio)/1000) & " segs")
+End Sub
+
+'RD - Copia la tabla CAT_DETALLE_PAQ a rkmt.db en la tarjeta del celular.
+Sub RD_respalda_cat_detalle_paq
+ Private inicio As String = DateTime.Now
+' Log("Copiando CAT_DETALLES_PAQ ...")
+ Private lasCols As String = getTableColumnListName(skmt, "CAT_DETALLES_PAQ")
+ If rkmt.IsInitialized Then
+ rkmt.BeginTransaction
+ rkmt.ExecNonQuery($"delete from CAT_DETALLES_PAQ where fecha = '${fechaHoy}'"$)
+ rkmt.ExecNonQuery($"insert into CAT_DETALLES_PAQ (${lasCols}, FECHA) select ${lasCols}, '${fechaHoy}' as FECHA from skmt1.CAT_DETALLES_PAQ"$)
+ rkmt.TransactionSuccessful 'Si no se pone TransactionSuccessful no se escribe NADA!!
+ rkmt.EndTransaction
+ Log(((DateTime.Now - inicio)/1000) & " segs")
+ End If
+End Sub
+
+'RD - Copia la tabla CAT_DETALLE_PAQ a rkmt.db en la tarjeta del celular.
+Sub RD_respalda_kmt_info
+ Private inicio As String = DateTime.Now
+' Log("Copiando kmt_info ...")
+ Private lasCols As String = getTableColumnListName(skmt, "kmt_info")
+ rkmt.BeginTransaction
+ rkmt.ExecNonQuery($"delete from kmt_info where fecha = '${fechaHoy}'"$)
+ rkmt.ExecNonQuery($"insert into kmt_info (${lasCols}, FECHA) select ${lasCols}, '${fechaHoy}' as FECHA from skmt1.kmt_info"$)
+ rkmt.TransactionSuccessful 'Si no se pone TransactionSuccessful no se escribe NADA!!
+ rkmt.EndTransaction
+ Log(((DateTime.Now - inicio)/1000) & " segs")
+End Sub
+
+'RD - Realiza un "vacuum" de la base de datos "rkmt".
+Sub RD_vacuum 'ignore
+ Log("Vacuum")
+ rkmt.ExecNonQuery("vacuum;")
+End Sub
+
+'Agrega una columna a la tabla especificada.
+'Hay que indicar el "tipo" de la columna (TEXT, INTEGER, ETC)
+'Ej. agregaColumna(DB, "TABLA", "COLUMNA", "TIPO")
+Sub agregaColumna(db As SQL, tabla As String, columna As String, tipo As String) 'ignore
+ Try 'Intentamos usar "pragma_table_info" para revisar si existe la columna en la tabla
+ Private c As Cursor = db.ExecQuery($"SELECT COUNT(*) AS fCol FROM pragma_table_info('${tabla}') WHERE name='${columna}'"$)
+ c.Position = 0
+ If c.GetString("fCol") = 0 Then 'Si no esta la columna la agregamos
+ db.ExecNonQuery($"ALTER TABLE ${tabla} ADD COLUMN ${columna} ${tipo}"$)
+ Log($"Columna "${columna} ${tipo}", agregada a "${tabla}"."$)
+ End If
+ Catch 'Si no funciona "pragma_table_info" lo hacemos con try/catch
+ Try
+ db.ExecNonQuery($"ALTER TABLE ${tabla} ADD COLUMN ${columna} ${tipo}"$)
+ Log($"Columna "${columna} ${tipo}", agregada a "${tabla}".."$)
+ Catch
+ Log(LastException)
+ End Try
+ End Try
+End Sub
+
+'Regresa los nombres y tipos de las columnas de una tabla dada.
+Sub getTableColumnList(db As SQL, table As String) As String 'ignore
+ Private l As String = ""
+ If chkIfTableExists(db, table) Then
+ Private c As Cursor = db.ExecQuery($"pragma table_info(${table})"$)
+ If c.RowCount > 0 Then
+ For i = 0 To c.RowCount - 1
+ c.Position = i
+ If l.Length = 0 Then
+ l = $"${c.GetString("name")} ${c.GetString("type")}"$
+ Else
+ l = $"${l}, ${c.GetString("name")} ${c.GetString("type")}"$
+ End If
+ Next
+ End If
+ Else
+ Return "No existe la tabla."
+ End If
+ c.Close
+ Return l
+End Sub
+
+'Regresa solo los nombres de las columnas de una tabla dada.
+Sub getTableColumnListName(db As SQL, table As String) As String 'ignore
+ Private l As String = ""
+ If chkIfTableExists(db, table) Then
+ Private c As Cursor = db.ExecQuery($"pragma table_info(${table})"$)
+ If c.RowCount > 0 Then
+ For i = 0 To c.RowCount - 1
+ c.Position = i
+ If l.Length = 0 Then
+ l = $"${c.GetString("name")}"$
+ Else
+ l = $"${l}, ${c.GetString("name")}"$
+ End If
+ Next
+ End If
+ Else
+ Return "No existe la tabla."
+ End If
+ c.Close
+ Return l
+End Sub
+
+'Revisa si una tabla dada existe en una base de datos dada, regresa true o false.
+Sub chkIfTableExists(db As SQL, table As String) As Boolean 'ignore
+ Private t As Boolean = False 'ignore
+ If db.IsInitialized Then
+ Private c As Cursor = db.ExecQuery($"SELECT name FROM sqlite_master WHERE type='table' AND name='${table}'"$)
+ If c.RowCount > 0 Then t = True
+ c.Close
+ End If
+ Return t
+End Sub
+
+'Hace visible y trae al frente el panel con los parametros "Top" y "Left" dados
+Sub panelVisible(panel As Panel, top As Int, left As Int) 'ignore
+ panel.BringToFront
+ panel.Visible = True
+ panel.Top = top
+ panel.Left = left
+End Sub
+
+'Centra una etiqueta dentro de un elemento superior
+Sub centraEtiqueta(elemento As Label, anchoElementoSuperior As Int) 'ignore
+ elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2)
+ etiquetaCentrada(True)
+End Sub
+
+Sub etiquetaCentrada(Success As Boolean)
+ If SubExists(CallBack, EventName & "_etiquetaCentrada") Then
+ CallSub2(CallBack, EventName & "_etiquetaCentrada", Success)
+ End If
+End Sub
+
+'Centra un panel horizontalmente dentro de un elemento superior
+Sub centraPanel(elemento As Panel, anchoElementoSuperior As Int) 'ignore
+ elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2)
+End Sub
+
+'Centra un panel verticalmente dentro de un elemento superior
+Sub centraPanelV(elemento As Panel, altoElementoSuperior As Int) 'ignore
+ elemento.Top = Round(altoElementoSuperior/2)-(elemento.Height/2)
+End Sub
+
+'Centra una barra de progreso dentro de un elemento superior
+Sub centraProgressBar(elemento As ProgressBar, anchoElementoSuperior As Int) 'ignore
+ elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2)
+End Sub
+
+'Regresa el usuario de la tabla USUARIOA, si no lo encuentra regresa "SinUsuario"
+Sub traeUsuarioDeDB(db As SQL) As String 'ignore
+ Private c As Cursor
+ Private u As String = "SinUsuario"
+ c = db.ExecQuery("select USUARIO from usuarioa")
+ c.Position=0
+ If c.RowCount > 0 Then u = c.GetString("USUARIO")
+ c.Close
+ Return u
+End Sub
+
+'Regresa el almacen actual de la base de datos.
+Sub traeAlmacen(db As SQL) As String 'ignore
+ Private c As Cursor
+ Private a As String
+ c = db.ExecQuery("select ID_ALMACEN from CAT_ALMACEN")
+ c.Position = 0
+ a = c.GetString("ID_ALMACEN")
+ c.Close
+ Return a
+End Sub
+
+'Regresa el nombre del producto desde CAT_GUNAPROD.
+Sub traeProdNombre(db As SQL, id As String) As String 'ignore
+ Private h As Cursor
+ Private n As String
+ h = db.ExecQuery2("select CAT_GP_NOMBRE from CAT_GUNAPROD where CAT_GP_ID = ? ", Array As String(id.Trim))
+ If h.RowCount > 0 Then
+ h.Position = 0
+ n = h.GetString("CAT_GP_NOMBRE")
+' Log(h.RowCount&"|"&id&"|"&n&"|")
+ End If
+ h.Close
+ If n = Null Or n="" Then n = "N/A"
+' Log(h.RowCount&"|"&id&"|"&n&"|")
+ Return n
+End Sub
+
+'Regresa la ruta actual de la base de datos.
+Sub traeRuta(db As SQL) As String 'ignore
+ Private c As Cursor
+ Private r As String
+ c = db.ExecQuery("select CAT_CL_RUTA from kmt_info where CAT_CL_CODIGO In (Select cuenta from cuentaa)")
+ r = "0"
+ If c.RowCount > 0 Then
+ c.Position=0
+ r = c.GetString("CAT_CL_RUTA")
+ End If
+ c.Close
+ Return r
+End Sub
+
+'Regresa el cliente actual de la base de dtos (CUENTAA).
+Sub traeCliente(db As SQL) As String 'ignore
+ Private c As Cursor
+ Private cl As String
+ c = db.ExecQuery("Select CUENTA from cuentaa")
+ c.Position=0
+ cl = c.GetString("CUENTA")
+ c.Close
+ Return cl
+End Sub
+
+'Regresa en un mapa el total de productos y monto del pedido del cliente actual
+'resultado = {"productos":"antidad_de_productos", "monto":"costo_total"}
+Sub traeTotalesClienteActual(db As SQL) As Map 'ignore
+ Private m As Map
+ m.Initialize
+ Private c_prodsX As Cursor = db.ExecQuery("select ifnull(sum(PE_CANT), 0) as cantProds, ifnull(sum(PE_COSTO_TOT), 0) as costoTotal FROM PEDIDO WHERE PE_CLIENTE IN (Select CUENTA from cuentaa) order by PE_PRONOMBRE asc")
+ c_prodsX.Position = 0
+' LogColor($"Productos de la orden: ${c_prodsX.GetString("cantProds")}, Total: ${c_prodsX.GetString("costoTotal")}"$, Colors.red)
+ m = CreateMap("productos": c_prodsX.GetString("cantProds"), "monto" : c_prodsX.GetString("costoTotal"))
+ Return m
+End Sub
+
+'Borra el pedido del cliente actual.
+'Borra los registros de la tabla "PEDIDO" y "PEDIDO_CLIENTE"
+'Actualiza las tablas "cat_gunaprod" y "kmt_info".
+Sub borraPedidoClienteActual(db As SQL) As String 'ignore
+ Private thisC As Cursor
+ thisC = db.ExecQuery("select PE_PROID,PE_CANT FROM PEDIDO where pe_cliente in (Select CUENTA from cuentaa) ")
+ If thisC.RowCount>0 Then
+ For i=0 To thisC.RowCount -1
+ thisC.Position=i
+ db.ExecNonQuery2("update cat_gunaprod set cat_gp_almacen = cat_gp_almacen + ? where cat_gp_id = ?", Array As Object(thisC.GetString("PE_CANT"),thisC.GetString("PE_PROID")))
+ db.ExecNonQuery2("INSERT INTO INVENT_X_ENVIAR (ALMACEN , PROID , CANTIDAD ) VALUES(?,?,?) ", Array As Object (traeAlmacen(db), thisC.GetString("PE_PROID"),thisC.GetString("PE_CANT")* -1))
+ Next
+ End If
+ db.ExecNonQuery("delete from pedido_cliente where pc_cliente in (Select CUENTA from cuentaa)")
+ db.ExecNonQuery("delete from pedido where pe_cliente in (Select CUENTA from cuentaa)")
+ db.ExecNonQuery("UPDATE kmt_info set gestion = 0 where CAT_CL_CODIGO In (select cuenta from cuentaa)")
+ Return 1
+End Sub
+
+'Regresa verdadero si la columna gestion en la tabla "kmt_info" tene valor 2.
+'si no, entonces regresa falso.
+Sub pedidoGuardado(db As SQL) As Boolean 'ignore
+ Private guardado As Boolean = False
+ Private g As Cursor = db.ExecQuery("select gestion from kmt_info where CAT_CL_CODIGO in (Select CUENTA from cuentaa)")
+ If g.RowCount > 0 Then
+ g.Position=0
+ If g.GetString("gestion") = "2" Then guardado = True
+ End If
+ Log($"Guardado=${guardado}"$)
+ Return guardado
+End Sub
+
+'Regresa verdadero si hay pedido en la tabla "PEDIDO" del cliente actual.
+Sub hayPedido(db As SQL) As Boolean 'ignore
+ Private thisC As Cursor = db.ExecQuery($"select count(PE_CLIENTE) as hayPedido from PEDIDO where PE_CLIENTE = '${traeCliente(db)}'"$)
+ thisC.Position = 0
+ Private hay As Boolean = False
+ If thisC.GetInt("hayPedido") > 0 Then hay = True
+' Log($"Cliente actual=${traeCliente}, hayPedido=${hay}"$)
+ Return hay
+End Sub
+
+'Guarda el nombre y version de la app en CAT_VARIABLES.
+Sub guardaAppInfo(db As SQL) 'ignore
+ db.ExecNonQuery("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = 'EMPRESA' or CAT_VA_DESCRIPCION = 'APP_NAME' or CAT_VA_DESCRIPCION = 'APP_VERSION'")
+ db.ExecNonQuery($"insert into CAT_VARIABLES (CAT_VA_DESCRIPCION, CAT_VA_VALOR) values ('APP_NAME', '${Application.LabelName}')"$)
+ db.ExecNonQuery($"insert into CAT_VARIABLES (CAT_VA_DESCRIPCION, CAT_VA_VALOR) values ('APP_VERSION', '${Application.VersionName}')"$)
+End Sub
+
+'Muestra en el Log los campos y valores que regresan en el JobDone.
+Sub logJobDoneResultados(resultado As DBResult) 'ignore
+ For Each records() As Object In resultado.Rows
+ LogColor($"====== ${resultado.Tag} - REGISTROS = ${resultado.Rows.Size}"$, Colors.RGB(215,37,0))
+ For Each k As String In resultado.Columns.Keys
+ LogColor(k & " = " & records(resultado.Columns.Get(k)), Colors.RGB(215,37,0))
+ Next
+ Next
+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
+
+'################ Manage External Storage (MES) #########################
+'
+''Inicializa "Manage External Storage" (MES), que nos da acceso a la tarjeta de memoria en Android 11+
+'Public Sub MES_Init (mCallBack As Object, mEventName As String)
+' mesCallback = mCallBack
+' mesEventName = mEventName
+'End Sub
+'
+'Sub MES_checkPermission 'ignore
+'' ' get the device SDK version
+'' Dim SdkVersion As Int = device.SdkVersion
+'' ' Choose which permission to request in order to access external storgage
+'' If SdkVersion < 30 Then
+''' Log("SDK = " & SdkVersion & " : Requesting WRITE_EXTERNAL_STORAGE permission")
+'' Dim rp As RuntimePermissions
+'' rp.CheckAndRequestPermission(rp.PERMISSION_WRITE_EXTERNAL_STORAGE) ' Implicit read capability if granted
+'' Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
+''' Log($"PERMISSION_WRITE_EXTERNAL_STORAGE = ${Result}"$)
+'' Else
+''' Log("SDK = " & SdkVersion & " : Requesting MANAGE_EXTERNAL_STORAGE permission")
+''' Log("On Entry MANAGE_EXTERNAL_STORAGE = " & MES1.HasPermission)
+'' If Not(MES_HasPermission) Then
+'' MsgboxAsync("This app requires access to all files, please enable the option", "Manage All Files")
+'' Wait For Msgbox_Result(Res As Int)
+''' Log("Getting permission")
+'' MES_GetPermission
+'' Wait For MES_StorageAvailable
+'' End If
+'' End If
+'End Sub
+'
+'' Determine if the app already has MANAGE_EXTERNAL_STORAGE call Environment.isExternalStorageManager()
+'' Return True if this app already has MANAGE_EXTERNAL_STORAGE permission
+'Public Sub MES_HasPermission As Boolean
+' Dim has As Boolean
+' Dim jo As JavaObject
+' jo.InitializeStatic("android.os.Environment")
+' has = jo.RunMethod("isExternalStorageManager", Null)
+' Return has
+'End Sub
+'
+'' Check whether this app has MANAGE_EXTERNAL_STORAGE permission
+'' If not show the user a dialog to enable MANAGE_EXTERNAL_STORAGE permission for this app
+'' Raises the StorageAvailable event in the calling activity when complete
+'Public Sub MES_GetPermission
+' If MES_HasPermission Then
+' RaiseEvent
+' Return
+' End If
+' Dim in As Intent
+' ' Be sure to reference your app package name in "pakageg:xxx"
+' in.Initialize("android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION", $"package:${Application.PackageName}"$)
+' StartActivityForResult(in)
+'End Sub
+'
+'Private Sub RaiseEvent
+' Log("Calling : " & mesEventName & "_StorageAvailable")
+' CallSubDelayed(mesCallback, mesEventName & "_StorageAvailable")
+'End Sub
+'
+'Private Sub ion_Event (MethodName As String, Args() As Object) As Object
+' RaiseEvent
+' Return Null
+'End Sub
+'
+'Private Sub StartActivityForResult(i As Intent)
+' Dim jo As JavaObject = MES_GetBA
+' ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
+' jo.RunMethod("startActivityForResult", Array As Object(ion, i))
+'End Sub
+'
+'Private Sub MES_GetBA As Object
+' Dim jo As JavaObject = Me
+' Return jo.RunMethod("getBA", Null)
+'End Sub
+'################ TERMINA Manage External Storage (MES) #########################
+
+
+'################ INICIA ENABLE BLUETOOTH #########################
+Sub StartBluetooth 'ignore
+ btAdmin.Initialize("btAdmin")
+ Log("btAdmin: " & btAdmin.IsEnabled)
+ If btAdmin.IsEnabled = False Then
+ Wait For (EnableBluetooth) Complete (Success As Boolean)
+ If Success = False Then
+ ToastMessageShow("Failed to enable bluetooth", True)
+ End If
+ Log(Success)
+ End If
+ Log($"BTADMIN: ${btAdmin.IsEnabled}"$)
+End Sub
+
+Sub EnableBluetooth As ResumableSub
+ ToastMessageShow("Enabling Bluetooth adapter...", False)
+ Private ph As Phone
+ If ph.SdkVersion >= 31 Then
+ rp.CheckAndRequest("android.permission.BLUETOOTH_CONNECT")
+ Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
+ If Result = False Then Return False
+ Log($"BTCONNECT: ${Result}"$)
+ If ph.SdkVersion >= 33 Then
+ Dim in As Intent
+ in.Initialize("android.bluetooth.adapter.action.REQUEST_ENABLE", "")
+ StartActivityForResult(in)
+ Wait For ion_Event (MethodName As String, Args() As Object)
+ Return btAdmin.IsEnabled
+ End If
+ End If
+ Return btAdmin.Enable
+End Sub
+
+Private Sub GetBA As Object
+ Dim jo As JavaObject = Me
+ Return jo.RunMethod("getBA", Null)
+End Sub
+
+Private Sub StartActivityForResult(i As Intent)
+ Dim jo As JavaObject = GetBA
+ ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
+ jo.RunMethod("startActivityForResult", Array As Object(ion, i))
+End Sub
+'################ TERMINA ENABLE BLUETOOTH #########################
\ No newline at end of file