Aplicación de vigilancia con Android (actualizada). The End.

 

Recordemos los pasos anteriormente descritos

Partiendo de la anterior entrada, hay que recordar:

  • Instalar la aplicación (ver punto 1.3 y 1.4), aceptar los permisos, configurarla en el móvil para que se ejecute sin restricciones, con inicio automático (para los Redmi con Android 7)  y ejecutarla un par de veces para que se activen los permisos que permitan acceder a los ficheros, compartir y obtener el intent android.intent.action.BOOT_COMPLETED, probar a reiniciar para verificar que se ejecuta nada más iniciar el móvil.
  •  Crear una programación que apague el móvil y lo encienda una vez cada dos días, por ejemplo, para ahorrar batería

Detalle de la app ejecutándose en una virtual del AVD

 

Resolviendo problemas del servicio de correo

En Junio de 2022, se produjo el cese en el servicio "Less Secure Apps" que nos permitía en la anterior entrada utilizar gmail como servicio smtp de notificación. Esto tuvo como consecuencia inmediata el bloqueo de este servicio de correo que teníamos configurado en nuestra aplicación android.

Para evitar este problema, debemos configurar la cuenta con la autenticación en dos pasos y generar una App Password (única contraseña) que nos permita seguir utilizando este servidor smtp.

Una vez configurada nuestra cuenta de esta manera actualizamos el apk con la nueva contraseña y debe seguir funcionando sin problemas. Por lo que el código de github sigue siendo funcional para dispositivos Android 7 y posiblemente 8. En Android 11 no funciona.

Manifest y FILE_PROVIDER_PATHS

El manifest entero:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tomafotoenviafoto2">

<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.CAMERA"
android:required="true" />
<uses-feature android:name="android.hardware.CAMERA.AUTOFOCUS" />

<uses-permission android:name="android.permission.CAMERA" />

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

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<uses-permission android:name="android.permission.WAKE_LOCK" />
<queries>
<!-- Camera -->
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
<application

android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light"
>


<!-- añadido 2022 android permission
android:enabled="true"
-->
<receiver
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
android:name=".CamaraRunOnStartup"
>

<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />

<action android:name="android.intent.action.REBOOT"/>
</intent-filter>

</receiver>



<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.tomafotoenviafoto2.fileprovider"
android:exported="false"
android:grantUriPermissions="true"

>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />

</provider>

</application>


</manifest>

Recordar que es preciso declarar un xml con la ruta por defecto en la que se tendrá acceso para guardar  y compartir archivos, filepaths en el ejemplo de arriba. La ruta de ese archivo se encuentra bajo nuestro proyecto:
C:\Users\<usuario>\AndroidStudioProjects\tomafotoenviafoto2\app\src\main\res\xml
y como ejemplo hemos decidido incluir los siguientes valores de acuerdo a la ruta en la que programamos el guardado de archivos para su compartición:
<paths xmlns:android="http://schemas.android.com/apk/res/android">

<files-path path="Pictures/" name="Pictures" />
</paths>
 

Fragmento del receiver

package com.example.tomafotoenviafoto2;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class CamaraRunOnStartup extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Log.i("JAVI_APP", "Se inicia la aplicación al inicio del móvil-entramos en INTENT");
//if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
if (intent != null) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(i);
Log.i("JAVI_APP", "Se inicia la aplicación al inicio del móvil");
Log.i("JAVI_APP", intent.getAction());
}
}
}
}

Gradle

De https://developer.android.com/studio/build:  "Android Studio usa Gradle, un paquete de herramientas de compilación avanzadas, para automatizar y administrar el proceso de compilación y, al mismo tiempo, definir configuraciones de compilación personalizadas y flexibles. Cada configuración de compilación puede definir su propio conjunto de código y recursos, y reutilizar las partes comunes a todas las versiones de tu app. El complemento de Android para Gradle funciona con el paquete de herramientas de compilación a fin de proporcionar procesos y ajustes configurables específicos para la compilación y prueba de apps para Android."
 
Como se indica en este enlace "As Android Studio comes with Gradle system pre-installed, there is no need to install additional runtime softwares to build our project."
 
En cualquier caso , tras esta última compilación es requisito indispensable disponer de un fichero de configuración de gradle para nuestro proyecto que enlace con las librerías que son necesarias de acuerdo al SDK que estemos usando para compilar. Es imprescindible usar la API 31 para el uso de algunas librerías y para que funcione nuestra aplicación. Aquí se detalla el fichero de gradle de la app al que nos referimos:
 C:\Users\<usuario>\AndroidStudioProjects\tomafotoenviafoto2\app\build.gradle
plugins {
id 'com.android.application'
}
repositories {
maven { url 'http://repo1.maven.org/maven2' }
}
android {
compileSdkVersion 31
//buildToolsVersion '29.0.2'

defaultConfig {
applicationId "com.example.tomafotoenviafoto2"
minSdkVersion 21
targetSdkVersion 31
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

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

dependencies {

implementation 'androidx.appcompat:appcompat:1.2.0'
// implementation 'androidx.appcompat:appcompat:1.0.0-alpha01'

implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.camera:camera-view:1.0.0-alpha01'
testImplementation 'junit:junit:4.4.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

// CameraX core library using the camera2 implementation
// def camerax_version = "1.2.0-alpha04"
//def camerax_version = "1.0.0-alpha01"
def camerax_version = "1.1.0"
// The following line is optional, as the core library is included indirectly by camera-camera2
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle library
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
// If you want to additionally use the CameraX VideoCapture library
//implementation "androidx.camera:camera-video:${camerax_version}"
// If you want to additionally use the CameraX View class
implementation "androidx.camera:camera-view:${camerax_version}"
// If you want to additionally add CameraX ML Kit Vision Integration
//implementation "androidx.camera:camera-mlkit-vision:${camerax_version}"
// If you want to additionally use the CameraX Extensions library
implementation "androidx.camera:camera-extensions:${camerax_version}"
//implementation 'javax.mail:mail:1.4.7'
//compile group: 'javax.mail', name: 'javax.mail-api', version: '1.4.7'
//Thanks for using https://jar-download.com
// https://mvnrepository.com/artifact/com.sun.mail/javax.mail
//implementation group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2'
implementation 'com.sun.mail:android-mail:1.6.2'
// implementation "androidx.startup:startup-runtime:1.1.1"




 

Código para obtener el porcentaje de batería

 Este trozo de código no aparece en el github compartido, aquí va:
dentro de
public class MainActivity extends  AppCompatActivity{
static float batteryp;
... 
this.batteryp = getBattery_percentage();
... 
 float getBattery_percentage()
{
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = getApplicationContext().registerReceiver(null, ifilter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level / (float)scale;
float p = batteryPct * 100;
Log.i("APLICACION JAVI","Battery percentage with round: "+ String.valueOf(p));
return p;
...
y por último dentro de
class emailSendBackground extends AsyncTask  {
..
m.setBody("Se adjunta foto en fecha y hora del mensaje. La batería se encuentra al " + Math.round(MainActivity.batteryp) + " %");
.. 
 

Importante recordar

 Si hacemos uso de Android MIUI es preciso con nuestra aplicación 
Configurarla en el móvil para que se ejecute sin restricciones, con inicio automático (para los Redmi con Android 7), Ahorro de batería: sin restricciones y en otros permisos activar "Mostrar ventanas emergentes mientras se ejecuta en segundo plano" y "Notificación permanente", también Notificaciones a Sí  y ejecutarla un par de veces para que se activen los permisos que permitan acceder a los ficheros, compartir y obtener el intent android.intent.action.BOOT_COMPLETED, probar a apagar/enceder para verificar que se ejecuta nada más iniciar el móvil.

Adicionalmente recordar que para quitar el bloqueo de pantalla en un móvil XIAOMI, debido a la capa de personalización de MI, es preciso activar las opciones de desarrollador (pulsando 10 veces en la versión ), y dentro de las opciones de desarrollador, activar "OMITIR PANTALLA DE BLOQUEO"  , para que nuestra aplicación no se encuentre con el móvil bloqueado por defecto.

Y eso es todo, espero que os haya resultado útil. 

The End

Con esta entrada abro un (espero pequeño) paréntesis en el que no habrá nuevas publicaciones de entradas en el futuro más inmediato. Espero que hayáis disfrutado como yo y que os haya servido para vuestros propios proyectos. Gracias por vuestro interés.

Un saludo.