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
<?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>
<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
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
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;
}
...
}
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
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.