Cómo un programador desarrolló una útil aplicación de viajes para su novia
Published: 2021-04-16 17:53:14

*“Se dice que son cinco centímetros por segundo. La velocidad con la que caen los pétalos de la flor del cerezo, son cinco centímetros por segundo”*

![](https://miro.medium.com/max/860/1*wPjkoS-T3DJ8YagEV0mRww.jpeg)

Al escuchar estas líneas de diálogo de un bien conocido anime japonés, John, un desarrollador de Huawei, se dio cuenta de que los cerezos estaban floreciendo en ese momento.
La novia de John, Jenny adora las flores de cerezo, y planeaba visitar el parque de cerezos más famoso de París el fin de semana, el Parc de Sceaux. Desafortunadamente, John se encontraba en un viaje de trabajo ese fin de semana y no le fue posible acompañar a Jenny.

Así que John se dijo a sí mismo, “¿Qué tal si desarrollo una aplicación de viajes inteligente para Jenny? Después de todo, soy desarrollador. Así ella podría disfrutar de las flores de cerezos de la mejor forma posible”. Entonces John se puso manos a la obra y enlistó los siguientes requerimientos para la app que estaba a punto de desarrollar.

* Recordatorios del viaje: Recordarle los eventos importantes con anticipación en su horario, como cuándo partir.

* Pronóstico del tiempo: Proporcionar sugerencias sobre qué traer y vestir en función de las condiciones meteorológicas en su destino.

* Envío de notificaciones: Enviar consejos útiles e información de descuentos a ella una vez que llegue al destino.

Afortunadamente para John, las capacidades previamente enlistadas podían ser fácilmente implementadas utilizando las funcionalidades de consulta del Tiempo y Clima de HUAWEI Awareness Kit, las geo-cercas de Location Kit y la capacidad de envío de notificaciones de Push Kit.

#Descripción general
**Awareness Kit** proporciona a tu aplicación la capacidad de obtener información contextual incluyendo hora actual, ubicación, comportamiento, conexión de los audífonos, clima, luz ambiental, estado de conexión del auto estéreo y estado de conexión de balizas, que pueden combinarse para crear varias barreras que corren en segundo plano y se activan una vez que se detecta un cambio en las condiciones.

**Location Kit** combina capacidades de geolocalización de GNSS, Wi-Fi y estación base en tu aplicación, lo que permite proporcionar servicios flexibles basados en la ubicación para usuarios de todo el mundo.

**Push Kit** es un servicio de mensajería diseñado para desarrolladores, que ayuda a crear un canal de mensajería de nube a dispositivo. Con Push Kit integrado, tu aplicación puede enviar mensajes a los dispositivos de los usuarios en tiempo real.

#Desarrollo
##Integración de Awareness Kit
Los siguientes tres pasos clave son necesarios para integrar Awareness kit. Para obtener más detalles, consulta la guía de desarrollo en el sitio web de HUAWEI Developers.

Configurar la información de la aplicación en AppGallery Connect.
Integrar el SDK de Awareness de HMS Core.
Configurar los scripts de ofuscación.

##Proceso de desarrollo
Declara los permisos necesarios en el archivo AndroidManifest.xml

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

Obtén información del clima basado en el nombre de la ciudad.
```
String city = edCity.getText().toString();

if (city != null && !city.equals("")) {

    WeatherPosition weatherPosition = new WeatherPosition();

    weatherPosition.setCity(city);

    // Pass the language type of the passed address. The value format is "Language_country", such as "zh_CN", "en_US".

    weatherPosition.setLocale("en_US");
// Obtain the Capture Client of Awareness Kit, and call the weather query capability.

    Awareness.getCaptureClient(getApplicationContext()).getWeatherByPosition(weatherPosition)

            .addOnSuccessListener(new OnSuccessListener<WeatherStatusResponse>() {

                @Override

                public void onSuccess(WeatherStatusResponse weatherStatusResponse) {

                    // Process the returned weather data.

                    WeatherStatus weatherStatus = weatherStatusResponse.getWeatherStatus();

                    WeatherSituation weatherSituation = weatherStatus.getWeatherSituation();

                    Situation situation = weatherSituation.getSituation();

                    String weather;

                    // Match the weather ID with the weather.

                    weather = getApplicationContext().getResources().getStringArray(R.array.cnWeather)[situation.getCnWeatherId()];

                    // Update UI.

                    ((TextView) findViewById(R.id.tv_weather)).setText(weather);

                    ((TextView) findViewById(R.id.tv_windDir)).setText(situation.getWindDir());

                    ((TextView) findViewById(R.id.tv_windSpeed)).setText(situation.getWindSpeed() + " km/h");

                    ((TextView) findViewById(R.id.tv_temperature)).setText(situation.getTemperatureC() + "℃");

                }

            }).addOnFailureListener(new OnFailureListener() {

        @Override

        public void onFailure(Exception e) {

        }

    });

}
```

Implementa recordatorios programados y envío de notificaciones una vez que el usuario llegue a su destino.

Registra un Broadcast Receiver para saber cuando la app se cierre.

Código en el AndroidManifest.xml
```
<receiver android:name=".BarrierReceiver">

<intent-filter>

    <action android:name="com.test.awarenessdemo.TimeBarrierReceiver.BARRIER_RECEIVER_ACTION"/>

</intent-filter>

</receiver>
```

Código Java
```
Intent intent = new Intent();

intent.setComponent(new ComponentName(MainActivity.this, BarrierReceiver.class));

mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
```

Define la barrera del tiempo y su Tag correspondiente, luego agrega la barrera.
```
// Obtain the entered time.

String timeHour = edTimeHour.getText().toString();

String timeMinute = edTimeMinute.getText().toString();

int hour = 0;

int minute = 0;

if (!timeHour.equals("")) {

    hour = Integer.parseInt(timeHour);

    if (!timeMinute.equals("")) {

        minute = Integer.parseInt(timeMinute);

    }

}

long oneHourMilliSecond = 60 * 60 * 1000L;

long oneMinuteMilliSecond = 60 * 1000L;

// Define the duringPeriodOfDay barrier to send notifications within a specified time period in a specified time zone.

AwarenessBarrier periodOfDayBarrier = TimeBarrier.duringPeriodOfDay(TimeZone.getDefault(),

        // Set the notification time to two hours in advance.

        (hour - 2) * oneHourMilliSecond + minute * oneMinuteMilliSecond,

        hour * oneHourMilliSecond + minute * oneMinuteMilliSecond);

String timeBarrierLabel = "period of day barrier label";

// Define a request for updating a barrier.

BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();

BarrierUpdateRequest request = builder.addBarrier(timeBarrierLabel, periodOfDayBarrier, mPendingIntent).build();

Awareness.getBarrierClient(getApplicationContext()).updateBarriers(request)

        .addOnSuccessListener(new OnSuccessListener<Void>() {

            @Override

            public void onSuccess(Void aVoid) {

            }

        })

        .addOnFailureListener(new OnFailureListener() {

            @Override

            public void onFailure(Exception e) {

            }

        });
```

Define la barrera de ubicación
```
if (city != null && !city.equals("")) {

    // Obtain the longitude and latitude of the city based on the city name from the assets folder.

    String data = cityMap.get(city);

    if (data != null){

        int flag = data.indexOf(",");

        double latitude = Double.parseDouble(data.substring(flag+1));

        double longitude = Double.parseDouble(data.substring(0,flag));

        double radius = 50;

        long timeOfDuration = 5000;

        // Define the stay barrier. If a user enters a specified area and stays for a specified time period, a barrier event is triggered and reported.

        AwarenessBarrier stayBarrier = LocationBarrier.stay(latitude, longitude, radius, timeOfDuration);

        String stayBarrierLabel = "stay barrier label";

        // Define a request for updating a barrier.

        BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();

        BarrierUpdateRequest request = builder.addBarrier(stayBarrierLabel, stayBarrier, mPendingIntent).build();

        Awareness.getBarrierClient(getApplicationContext()).updateBarriers(request)

                .addOnSuccessListener(new OnSuccessListener<Void>() {

                    @Override

                    public void onSuccess(Void aVoid) {

                    }

                })

                .addOnFailureListener(new OnFailureListener() {

                    @Override

                    public void onFailure(Exception e) {

                    }

                });

    }

}
```

Define un BroadcastReceiver para escuchar cuando se disparen las barreras y realizar las operaciones correspondientes.
```
class BarrierReceiver extends BroadcastReceiver {

    @Override

    public void onReceive(Context context, Intent intent) {

        BarrierStatus barrierStatus = BarrierStatus.extract(intent);

        String label = barrierStatus.getBarrierLabel();

        int barrierPresentStatus = barrierStatus.getPresentStatus();

        String city = intent.getStringExtra("city");

        switch (label) {

            case DURING_PERIOD_OF_DAT_BARRIER_LABEL:

                if (barrierPresentStatus == BarrierStatus.TRUE) {



                    initNotification(context,"1","time_channel","Travel reminder","Two hours before departure");

                } else if (barrierPresentStatus == BarrierStatus.FALSE) {

                    showToast(context, "It's not between ");

                } else {

                    showToast(context, "The time status is unknown.");

                }

                break;



            case STAY_BARRIER_LABEL:

                if (barrierPresentStatus == BarrierStatus.TRUE) {



                    initNotification(context,"2","area_channel","Welcome to"+city,"View travel plans");

                } else if (barrierPresentStatus == BarrierStatus.FALSE) {

                    showToast(context,"You are not staying in the area set by locationBarrier" +

                            " or the time of duration is not enough.");

                } else {

                    showToast(context, "The location status is unknown.");

                }

                break;

        }

    }
}
```

##Envío de notificaciones basado en la ubicación
![](https://miro.medium.com/max/1280/1*OZSBoz5TwtjNvrw8e0AJSw.gif)

Agrega la dirección del repositorio Maven al archivo build.gradle a nivel de proyecto.
```
buildscript {
repositories {
maven { url 'http://developer.huawei.com/repo/'}
}
dependencies {
...
// Add AppGallery Connect plugin configuration.
classpath 'com.huawei.agconnect:agcp:1.4.2.300'
}
}allprojects {
repositories {
maven { url 'http://developer.huawei.com/repo/'}
}
}
```

Agrega las dependencias de Location y Push al archivo build.gradle a nivel de app.
```
dependencies {
implementation 'com.huawei.hms:location:5.0.2.300'
implementation 'com.huawei.hms:push: 5.0.2.301'
}
```

##Pasos Clave
###Declara los permisos necesarios en el archivo AndroidManifest.xml

Location Kit incorpora capacidades de posicionamiento GNSS, Wi-Fi y estación base en tu aplicación. Para ello, requiere acceso a la red, y permisos de ubicación. Si deseas que la aplicación obtenga continuamente ubicaciones de usuario cuando se ejecuta en segundo plano, también es necesario declarar el permiso _**ACCESS_BACKGROUND_LOCATION**_ en el AndroidManifest.

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

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

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

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

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

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

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

<uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />

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

_**Nota:** los permisos **ACCESS_FINE_LOCATION, WRITE_EXTERNAL_STORAGE,** y **READ_EXTERNAL_STORAGE** están catalogados como permisos riesgozos, de modo que tendrás que solicitar estos permisos en tiempo de ejecución. Si tu app no obtiene la autorización de estos permisos, Location Kit no podrá funcionar._

###Crea una Geocerca y activala

```
LocationSettingsRequest.Builder builders = new LocationSettingsRequest.Builder();
 builders.addLocationRequest(mLocationRequest);
 LocationSettingsRequest locationSettingsRequest = builders.build();
 // Before requesting location update, call checkLocationSettings to check device settings.
 Task<LocationSettingsResponse> locationSettingsResponseTasks = mSettingsClient.checkLocationSettings(locationSettingsRequest);
 locationSettingsResponseTasks.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
     @Override
     public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
         Log.i(TAG, "check location settings success");
  mFusedLocationProviderClient
                 .requestLocationUpdates(mLocationRequest, mLocationCallbacks, Looper.getMainLooper())
                 .addOnSuccessListener(new OnSuccessListener<Void>() {
                     @Override
                     public void onSuccess(Void aVoid) {
                         LocationLog.i(TAG, "geoFence onSuccess");
                     }
                 })
                 .addOnFailureListener(new OnFailureListener() {
                     @Override
                     public void onFailure(Exception e) {
                         LocationLog.e(TAG,
                                 "geoFence onFailure:" + e.getMessage());
                     }
                 });
     }
 })
```

###Dispara el envío de la notificación
Envía una notificación cuando el callback onReceive del GeoFenceBroadcastReceiver detecte que la geocerca se ha disparado. El mensaje será desplegado en el panel de notificaciones del dispositivo.

```
if (geofenceData != null) {
     int errorCode = geofenceData.getErrorCode();
     int conversion = geofenceData.getConversion();
     ArrayList<Geofence> list = (ArrayList<Geofence>) geofenceData.getConvertingGeofenceList();
     Location myLocation = geofenceData.getConvertingLocation();
     boolean status = geofenceData.isSuccess();
     sb.append("errorcode: " + errorCode + next);
     sb.append("conversion: " + conversion + next);
     if (list != null) {
         for (int i = 0; i < list.size(); i++) {
             sb.append("geoFence id :" + list.get(i).getUniqueId() + next);
         }
     }
     if (myLocation != null) {
         sb.append("location is :" + myLocation.getLongitude() + " " + myLocation.getLatitude() + next);
     }
     sb.append("is successful :" + status);
     LocationLog.i(TAG, sb.toString());
     Toast.makeText(context, "" + sb.toString(), Toast.LENGTH_LONG).show();
    
     new PushSendUtils().netSendMsg(sb.toString());
 }
```

_**Nota:** La geocerca creada usando el código de ejemplo activará dos callbacks para los tipos de conversión 1 y 4. Una se activa cuando un usuario ingresa a la geocerca y la otra se activa cuando el usuario permanece en ella. Si Trigger está configurado en 7 en el código, se configuran los callbacks para todos los escenarios, incluyendo entrar, permanecer y salir de la geocerca._