Está en la página 1de 17

U NIVERSIDAD AUTÓNOMA DE Q UERÉTARO

FACULTAD DE I NGENIERÍA

I NGENIERÍA EN AUTOMATIZACIÓN

Programación de Dispositivos Moviles

Servicios y Notificaciones

Practica 6

Profesor:
Dr. Ramos Arreguín Juan Manuel

Alumno:
Cervantes Ortiz José Eduardo 283343

14 de Septiembre de 2022
1. Generacion de Notificaciones
Las notificaciones proporcionan información breve sobre eventos de la aplicacion cuando no
está en uso. Existen varias funciones para Android 4.0 (API nivel 14) y versiones posteriores.
1.1 Definición del contenido de la notificación
Primero se debe configurar el contenido y el canal de la notificación con un objeto Notifica-
tionCompat.Builder. En siguiente codigo se muestra como se crea una notificación con un ícono
pequeño, establecido por setSmallIcon(), un título, establecido por setContentTitle(), el texto del
cuerpo establecido por setContentText() y la prioridad de notificación, establecida por setPriority().
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(textTitle)
.setContentText(textContent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);

1.2 Cómo crear un canal y definir la importancia


Antes de poder publicar la notificación en Android 8.0 y versiones posteriores, se debe registrar
el canal de notificaciones de la app en el sistema transfiriendo una instancia de NotificationChannel
a createNotificationChannel(). De este modo, una condición de la versión SDKINT bloquea el
siguiente código:
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can’t change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}

1.3 Cómo establecer la acción de toque de la notificación


Cada notificación debería responder a un toque, por lo general para abrir una actividad en la
app que se corresponda con la notificación. Para hacerlo, se debe especificar un intent de contenido
definido con un objeto PendingIntent y pasarlo a setContentIntent().
En el siguiente fragmento, se muestra cómo crear un intent básico para abrir una actividad
cuando el usuario presiona la notificación:
// Create an explicit intent for an Activity in your app
Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

1
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true);

1.4 Cómo mostrar la notificación


Para que aparezca la notificación, se usa el metodo NotificationManagerCompat.notify() y se
le pasa un ID único para la notificación y el resultado de NotificationCompat.Builder.build(). Por
ejemplo:
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

// notificationId is a unique int for each notification that you must define
notificationManager.notify(notificationId, builder.build());

1.5 Cómo agregar botones de acción


Una notificación puede ofrecer hasta tres botones de acción que le permitan al usuario respon-
der de manera rápida, como posponer un recordatorio o incluso responder un mensaje de texto.
Pero estos botones de acción no deben duplicar la acción realizada cuando el usuario presiona la
notificación.
Para agregar un botón de acción, se pasa un elemento PendingIntent al método addAction(). Esto
es similar a configurar la acción de toque predeterminada de la notificación, excepto que en lugar
de iniciar una actividad, se puede llevar a cabo una variedad de otras funciones, como iniciar un
BroadcastReceiver que realice un trabajo en segundo plano, de modo que la acción no interrumpa
a la app que ya está abierta.
Por ejemplo, en el siguiente código se muestra cómo enviar una transmisión a un receptor
específico:
Intent snoozeIntent = new Intent(this, MyBroadcastReceiver.class);
snoozeIntent.setAction(ACTION_SNOOZE);
snoozeIntent.putExtra(EXTRA_NOTIFICATION_ID, 0);
PendingIntent snoozePendingIntent =
PendingIntent.getBroadcast(this, 0, snoozeIntent, 0);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)


.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.addAction(R.drawable.ic_snooze, getString(R.string.snooze),
snoozePendingIntent);

2
1.6 Cómo agregar una barra de progreso
Las notificaciones pueden incluir un indicador de progreso animado que muestre a los usuarios
el estado de una operación constante.
Si se puede estimar qué parte de la operación estará completa en cualquier momento, se llama a
setProgress(max, progress, false). El primer parámetro es el valor çompleto"(como 100); el segundo
es qué parte está completa; y el último indica que se trata de una barra de progreso definido.
Mientras la operación avance, se llama a setProgress(max, progress, false) de manera continua con
un valor actualizado de progress y vuelve a emitir la notificación.
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setContentTitle("Picture Download")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.ic_notification)
.setPriority(NotificationCompat.PRIORITY_LOW);

// Issue the initial notification with zero progress


int PROGRESS_MAX = 100;
int PROGRESS_CURRENT = 0;
builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
notificationManager.notify(notificationId, builder.build());

// Do the job here that tracks the progress.


// Usually, this should be in a
// worker thread
// To show progress, update PROGRESS_CURRENT and update the notification with:
// builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
// notificationManager.notify(notificationId, builder.build());

// When done, update the notification one more time to remove the progress bar
builder.setContentText("Download complete")
.setProgress(0,0,false);
notificationManager.notify(notificationId, builder.build());

1.7 Cómo mostrar un mensaje urgente


Es posible que la app necesite mostrar un mensaje urgente e importante, como una llamada te-
lefónica entrante o una alarma. En estas situaciones se puede asociar un intent de pantalla completa
a la notificación.
Si el dispositivo del usuario está bloqueado, aparece una actividad en pantalla completa, que cubre
la pantalla de bloqueo. Si el dispositivo del usuario está desbloqueado, la notificación aparece en
forma expandida e incluye opciones para controlar o descartar la notificación.
Intent fullScreenIntent = new Intent(this, ImportantActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)


.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")

3
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setFullScreenIntent(fullScreenPendingIntent, true);

1.8 Cómo establecer la visibilidad de la pantalla de bloqueo


Para controlar el nivel de los detalles visibles en la notificación desde la pantalla de bloqueo se
llama a setVisibility() y se especifica uno de los siguientes valores:

VISIBILITY_PUBLIC muestra el contenido completo de la notificación.

VISIBILITY_SECRET no muestra ninguna parte de la notificación en la pantalla de bloqueo.

VISIBILITY_PRIVATE muestra información básica, como el ícono de la notificación y el


título del contenido, pero oculta todo el contenido de la notificación.

1.9 Cómo actualizar una notificación


Para actualizar la notificación después de emitirla, se vuelve a llamar a NotificationManager-
Compat.notify() pasandole una notificación con el mismo ID usado anteriormente. Si se la descartó,
se crea una notificación nueva.
1.10 Cómo quitar una notificación
Las notificaciones permanecen visibles hasta que alguna de estas acciones tiene lugar:

El usuario descarta la notificación.

El usuario hace clic en la notificación y se llama a setAutoCancel() cuando se crea la notifi-


cación.

Se llama a cancel() para un ID de notificación específico.

Se llama a cancelAll(), que elimina todas las notificaciones que emitiste previamente.

Si se configura un tiempo de espera cuando se crea una notificación con setTimeoutAfter(),


el sistema la cancela después de que transcurre la duración especificada.

4
2. Service GPS
En el androidmanifest se activan los permisos y se define el nuevo servicio, se crea el servicio
dentro del cual están los métodos para checar si es que el usuario tiene activado el gps y en caso de
que no se crea la solicitud para que lo active.

Figura 1: Solicitud de permisos al usuario.

5
En el main Activity se encuentran dos botones para el incio y paro del servicio asi como un
objeto de tipo TextView. En el método de activación se define un objeto de tipo intent que es con
el que se va a llamar a al servicio. Cuando el servicio es activado se despliega una notificacion
indicando la direccion actual. En la clase donde se define el servicio se encuentran dos objetos de
la clase LocationListener y LocationManager que van a ser usados para obtener la dirección así
como su actualización.

(a) MainActivity (b) Notificacion

Figura 2:

6
Cada que se actualiza la localización esta es mandada hacia la notificación creada en el mo-
mento que se inicia el servicio. Si se presiona la notificación entonces se pasa el dato de la última
localización hacia un texto en la actividad principal.

Figura 3: Pase de dato al main Activity

7
Cuando se presiona la tecla de detener el servicio se deja de actualizar la direccion y se elimina
la notificacion creada.

Figura 4: Detención del servicio.

8
3. Código
3.1 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.servicegps">

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


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

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ServiceGPS"
tools:targetApi="31">
<activity
android:name=".OtherActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>

<service android:name=".GPS_Service" />


</application>

</manifest>

3.2 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Service"
android:id="@+id/button"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

9
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop Service"
android:id="@+id/button2"
android:layout_alignTop="@+id/button"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />

<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/scrollView"
android:layout_centerHorizontal="true"
android:foregroundGravity="top|right"
android:layout_above="@+id/button"
android:layout_alignParentTop="true"
android:clickable="true">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:id="@+id/textView" />
</ScrollView>

</RelativeLayout>

3.3 MainActivity.java
package com.example.servicegps;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.RemoteInput;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

private Button btn_start, btn_stop;


private TextView textView;
private BroadcastReceiver broadcastReceiver;

@Override

10
protected void onResume() {
super.onResume();
if(broadcastReceiver == null){
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

textView.setText("Coordenadas:\n" +intent.getExtras().get("coordinates"));

}
};
}
registerReceiver(broadcastReceiver,new IntentFilter("location_update"));
}

@Override
protected void onDestroy() {
super.onDestroy();
if(broadcastReceiver != null){
unregisterReceiver(broadcastReceiver);
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btn_start = (Button) findViewById(R.id.button);


btn_stop = (Button) findViewById(R.id.button2);
textView = (TextView) findViewById(R.id.textView);

if(!runtime_permissions())
enable_buttons();
}

private void enable_buttons() {

btn_start.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent i =new Intent(getApplicationContext(),GPS_Service.class);
startService(i);
}
});

btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

Intent i = new Intent(getApplicationContext(),GPS_Service.class);


stopService(i);

}
});

11
private boolean runtime_permissions() {
if(Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_

requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACC

return true;
}
return false;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] gra
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 100){
if( grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PER
enable_buttons();
}else {
runtime_permissions();
}
}
}
}

3.4 activity_other.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".OtherActivity">

</androidx.constraintlayout.widget.ConstraintLayout>

3.5 OtherActivity.java
package com.example.servicegps;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.widget.TextView;

public class OtherActivity extends AppCompatActivity {

private LocationListener listener;


private LocationManager locationManager;
private static final String KEY_TEXT_REPLY = "key text reply";
private NotificationHelper nh;

12
private Context cont;
TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);

listener = new LocationListener() {


@Override
public void onLocationChanged(Location location) {
Intent i = new Intent("location_update");
i.putExtra("coordinates",location.getLongitude()+" "+location.getLatitude());
sendBroadcast(i);
locationManager.removeUpdates(listener);
//stopService(i);
}

@Override
public void onStatusChanged(String s, int i, Bundle bundle) {

@Override
public void onProviderEnabled(String s) {

@Override
public void onProviderDisabled(String s) {
//Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//startActivity(i);
}

};

locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE

//noinspection MissingPermission
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,3000,0,listener);

//locationManager.removeUpdates(listener);

}
}

3.6 strings.xml
<resources>
<string name="app_name">ServiceGPS</string>
<string name="reply_label">Etiqueta de replica</string>
</resources>

3.7 GPS_Service.java
package com.example.servicegps;

13
import android.app.RemoteInput;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;

import androidx.annotation.Nullable;

public class GPS_Service extends Service {


private LocationListener listener;
private LocationManager locationManager;

private static final String KEY_TEXT_REPLY = "key text reply";


private NotificationHelper nh;
private Context cont;

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onCreate() {

String replyLabel = getResources().getString(R.string.reply_label);


RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build();
cont=this;

listener = new LocationListener() {


@Override
public void onLocationChanged(Location location) {
//Intent i = new Intent("location_update");
//i.putExtra("coordinates",location.getLongitude()+" "+location.getLatitude());
//sendBroadcast(i);

nh = new NotificationHelper(cont);
nh.createNotification("GPS", "long: "+location.getLongitude() +"\nlat: "+location.getLatitud
}

@Override
public void onStatusChanged(String s, int i, Bundle bundle) {

@Override
public void onProviderEnabled(String s) {

@Override
public void onProviderDisabled(String s) {
Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);

14
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
};

locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE

//noinspection MissingPermission
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,3000,0,listener);
}

@Override
public void onDestroy() {
super.onDestroy();
if(locationManager != null){
//noinspection MissingPermission
locationManager.removeUpdates(listener);
}
nh.cancelNotification();
}
}

3.8 NotificationHelper.java
package com.example.servicegps;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.provider.Settings;

import androidx.core.app.NotificationCompat;

public class NotificationHelper {


private Context mContext;
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mBuilder;
public static final String NOTIFICATION_CHANNEL_ID = "10001";
private NotificationChannel channel;
private int NOTIFICATION_ID = 0;
public NotificationHelper(Context context) {
mContext = context;
//Solamente se obtiene el canal si el API es Mayor de 25
if (Build.VERSION.SDK_INT < 26) {
return;
}
NotificationManager notificationManager =
(NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
channel = new NotificationChannel("default",
"Channel name",
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("Channel description");
notificationManager.createNotificationChannel(channel);

15
}
/**
* Create and push the notification
*/
public void createNotification(String title, String message)
{
/**Creates an explicit intent for an Activity in your app**/
Intent resultIntent = new Intent(mContext , OtherActivity.class);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//PendingIntent resprueba = PendingIntent.getActivity()
PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
0 /* Request code */, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder = new NotificationCompat.Builder(mContext, "default");
mBuilder.setSmallIcon(R.mipmap.ic_launcher);
mBuilder.setContentTitle(title)
.setContentText(message)
.setAutoCancel(false)
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setContentIntent(resultPendingIntent);
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(NOTIFICATION_ID /* Request Code */, mBuilder.build());
}
//Originalmente no se encuentra esta función.
public void cancelNotification()
{
mNotificationManager.cancel(NOTIFICATION_ID);
}
}

16

También podría gustarte