Servicio de notificaciones tipo Facebook Messenger con Xamarin.Android


Uno de los beneficios que tenemos en android es el poder dibujar sobre la ventana en cualquier parte del sistema algo que si lo sabemos usar es muy comodo para el usuario ya que podemos notificar directamente en la pantalla, como todo debemos usarlo con medida ya que al igual que comodo el tapizarle la pantalla al usuario con cosas puede ser algo incomodo en este blog veremos como usar un servicio para poder dibujar en la pantalla este tipo de notificaciones bueno despues de esta teoria iniciaremos:

antes que nada deberemos de agregar un permiso en nuestro AndroidManifest.xml en el cual pediremos permiso al sistema para poder norificar o pintar sobre la pantalla del usuario:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Crearemos una clase tipo servicio con el nombre de "ChatHeadService.cs" y le agregaremos View.IOnTouchListener para instanciarle los atributos y propiedades del un objeto acceseible a la interaccion del usuario eventos tipo touch el codigo sera el siguiente:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Graphics;
namespace AndroidNotification
{
    //Agregamos el atributo [Service] para especificar que la clase sera del tipo servicio
    //Service Implenetaremos la clase del tipo servicio para que pueda usar metodos de esta clase padre
    //al igual usaremos View.IOnTouchListener para poder implementar los metodos de interaccion tocuh del usuario
    [Service]
    public class ChatHeadService : Service, View.IOnTouchListener
    {
        //Usaremos estas variables para manejar la posicion del objeto sobre la ventana
        private int initialX;
        private int initialY;
        private float initialTouchX;
        private float initialTouchY;

        //crearemos una variable del tipo IWindowManager como manejador pricipal de la pantall
        private IWindowManager windowManager;
        //crearemos una simple imagen la cual mostraremos sobre la ventana
        private ImageView chatHead;
        //Crearemos una variable del tipo WindowManagerLayoutParams que contendra los parametros necesarios para poder
        //presentar la imagen de manera correcta sobre la pantalla
        WindowManagerLayoutParams param = null;
        //metodo para hacer Bind al servicio el cual no usaremos en este ejemplo
        public override IBinder OnBind (Intent intent)
        {
            return null;
        }
        //Metodo principal en el cual se creara el servicio y pintaremos nuestro imageview sobre la ventana
        public override void OnCreate ()
        {
            base.OnCreate ();
            //incializaremos en windowmanager obteniendo el servicio directo de la ventan del sistema y haremos
            //un casting de tipo JavaCast<IWindowManager>
            windowManager = GetSystemService ("window").JavaCast<IWindowManager> ();
            //inicializaremos nuestro imageview dandole los atributos de nuestra clase para que obtenga los metodos
            //de touch
            chatHead = new ImageView(this);
            //definimos la imagen del imageview
            chatHead.SetImageResource (Resource.Drawable.ic_launcher);
            //Asignamos el listener del touch nuestra clase del tipo View.IOnTouchListener
            chatHead.SetOnTouchListener (this);
            //instanciamos los parametros que necesitamos para poder tomar la pantalla y asi poder mostrar nuestro imageview
            param = new WindowManagerLayoutParams(
                WindowManagerLayoutParams.WrapContent,
                WindowManagerLayoutParams.WrapContent,
                WindowManagerTypes.Phone,
                WindowManagerFlags.NotFocusable,
                Format.Translucent);
            //Agregamos la propiedad de gravedad en la parte de arriba hacia la izquieda
            param.Gravity = GravityFlags.Top | GravityFlags.Left;
            //Asignamos la posicion X del imageview
            param.X = 0;
            //Asignamos la posicion Y del imageview
            param.Y = 100;
            //Agregamos una vista a la ventana del sistema con nuestro imageview y los parametros generados
            windowManager.AddView (chatHead, param);
        }
        //Metodo para destruir la imagen
        public override void OnDestroy ()
        {
            base.OnDestroy ();
            if (chatHead != null) windowManager.RemoveView(chatHead);
        }
        //Metodo hijo del tipo View.IOnTouchListener para manejar el tocuh sobre la imagen
        public bool OnTouch(View v, MotionEvent e)
        {
            //Mediante este switch verificamos el tipo de accion
            switch (e.Action) {
            //Case tipo down de la imagen
            case MotionEventActions.Down:
                initialX = param.X;
                initialY = param.Y;
                initialTouchX = e.RawX;
                initialTouchY = e.RawY;
                return true;
            //Case tipo Up de la iamgen
            case MotionEventActions.Up:
                return true;
            //Case tipo Move de la imagen
            case MotionEventActions.Move:
                param.X = initialX + (int) (e.RawX - initialTouchX);
                param.Y = initialY + (int) (e.RawY - initialTouchY);
                windowManager.UpdateViewLayout(chatHead, param);
                return true;
            }
            return false;
        }
    }
} 
En la principal mandaremos a llamar el nuestro servicio creado con la accion del boton:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace AndroidNotification
{
    [Activity (Label = "AndroidNotification", MainLauncher = true)]
    public class MainActivity : Activity
    {
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
            // Set our view from the "main" layout resource
            SetContentView (Resource.Layout.Main);
            // Get our button from the layout resource,
            // and attach an event to it
            Button button = FindViewById<Button> (Resource.Id.myButton);
            button.Click += delegate {
                //button.Text = string.Format ("{0} clicks!", count++);
                StartService(new Intent(this, typeof(ChatHeadService)));
            };
        }

    }
} 
Listo ahora veremos nuestro trabajo final:




Este post fue una adaptacion a Xamarin.Android del siguente blog:

http://www.piwai.info/chatheads-basics/

Pueden acceder al ejemplo completo desde mi github:

https://github.com/AlejandroRuiz/Mono/tree/master/AndroidNotification

Si quieren adentrarse aun mas a los servicios en android les dejo los siguientes enlaces de interes:
Android Manifest Permissions: http://developer.android.com/reference/android/Manifest.permission.html
Xamarin.Android Services: http://docs.xamarin.com/guides/android/application_fundamentals/services/

Happy code les dejo algo para que se motiven:


Comentarios

Entradas populares de este blog

Bluetooth Arduino + Xamarin.Android

Xamarin.Forms: Get native image from ImageSource

Simple ListView with Xamarin.Forms