[Quedada CartujaDotNet] Mesa redonda de TDD

Mesa redonda

En el pasado Sevilla Mobility Day: Strikes back tuvimos una divertida mesa redonda sobre TDD de la mano de Juan María Lao.  En CartujaDotNet
nos parece una propuesta tan enriquecedora e interesante que hemos
decidido realizar una quedada informal y extender la mesa redonda. Asi
que si quieres analizar TDD, ventajas que aporta y otros muchos aspectos
mediante las opiniones de todos los asistentes, no te lo pierdas.

¿Te apuntas?

A continuación tienes disponible la fecha, hora y lugar:

Más información

[Evento CartujaDotNet] Material de “Integrando Apps con Cortana” en el Sevilla Mobility Day

El evento

El pasado sábado 25 de Octubre tenía lugar la segunda edición del Sevilla Mobility Day en el Cloud Pointing
de Microsoft situado en el Parque Empresarial Nuevo Torneo.  Un evento
con múltiples charlas relacionadas con el desarrollo móvil de CartujaDotNet, grupo de usuarios .NET de Sevilla.

El material

En mi caso, tuve el placer de poder “arrancar” el evento con una charla sobre integración de Apps Windows Phone con Cortana

Tenéis disponible la presentación utilizada a continuación:

 

Podéis descargar este ejemplo a continuación:


Quisiera terminar agradeciendo a todos los ponentes por su participación, a CampusMVP por el patrocinio, a Microsoft por la sala  y por supuesto a todos los asistentes. Espero que para todos fuese una mañana muy divertida y… ¿cuándo repetimos?

Más información

[Universal App] Usando las APIs Credential Locker

Introducción

En determinadas ocasiones, nuestras aplicaciones requieren seguridad o
personalización por usuario. En estos casos son típicos problemas como,
como almacenar usuario y contraseña, encriptar la información,
gestionar múltiples dispositivos, etc.

Era un proceso “habitual” pero que requiere tener en cuentas
bastantes aspectos. Ahora con la llegada de las APIs Credential Locker
disponibles en Windows.Security.Credentials, todo el proceso es mucho más simple.

En este artículo vamos a conocer las APIs de Credential Locker
utilizñandolas en un ejemplo real donde veremos como almacenar,
recuperar y eliminar claves.

¿Te apuntas?

¿Credential Locker?

El almacén de credenciales nos permite almacenar y administrar de forma segura
contraseñas de usuarios de una aplicación o servicio específico de modo
que por un lado, los datos almacenados de una aplicación se transfieren
automáticamente a los otros dispositivos de confianza del usuario,
simplificando el proceso de autenticación tanto a los usuarios como a
nosotros, y por otro lado, no es posible desde una aplicación o servicio
acceder a los credenciales asociados con otra aplicación o servicio.

Primeros pasos

Comenzamos creando un nuevo proyecto:

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo sera muy sencillo. Nuestra aplicación de ejemplo
pedirá fuente, usuario y contraseña permitiéndo con tres sencillos
botones, añadir, recuperar y eliminar credenciales utilizando la API
Credential Locker.

Comenzamos definiendo la interfaz de usuario:

<StackPanel Margin="12">
     <StackPanel Orientation="Vertical">
          <TextBox Header="Source" PlaceholderText="https://facebook.com" />
          <TextBox Header="User" PlaceholderText="user@mail.com" />
          <PasswordBox Header="Password" PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
          <Button Content="Guardar" />
          <Button Content="Recuperar" Margin="12, 0" />
          <Button Content="Borrar" />
     </StackPanel>
</StackPanel>
Muy simple. Permitimos obtener la información de seguridad requerida y contamos con tres botones de acción. En la viewmodel correspondiente contaremos con propiedades para obtener la información escrita en cada una de las cajas de texto:
// Variables
private string _source;
private string _user;
private string _password;
private string _info;
 
public string Source
{
     get { return _source; }
     set { _source = value; }
}
 
public string User
{
     get { return _user; }
     set { _user = value; }
}
 
public string Password
{
     get { return _password; }
     set { _password = value; }
}
 
public string Info
{
     get { return _info; }
     set
     {
          _info = value;
          RaisePropertyChanged("Info");
     }
}
Y cada botón, ejecutará un comando en la viewmodel:
// Commands
private ICommand _saveCommand;
private ICommand _readCommand;
private ICommand _deleteCommand;
 
public ICommand SaveCommand
{
     get { return _saveCommand = _saveCommand ?? new DelegateCommand(SaveCommandDelegate); }
}
 
public ICommand ReadCommand
{
     get { return _readCommand = _readCommand ?? new DelegateCommand(ReadCommandDelegate); }
}
 
public ICommand DeleteCommand
{
     get { return _deleteCommand = _deleteCommand ?? new DelegateCommand(DeleteCommandDelegate); }
}
 
public void SaveCommandDelegate()
{
 
}
 
public void ReadCommandDelegate()
{
 
}
 
public void DeleteCommandDelegate()
{
 
}
De modo que nuestra interfaz bindeada a las propiedades y comandos correspondientes quedara como podemos ver a continuación:
<StackPanel Margin="12">
     <StackPanel Orientation="Vertical">
          <TextBox Text="{Binding Source, Mode=TwoWay}" Header="Source" PlaceholderText="https://facebook.com" />
          <TextBox Text="{Binding User, Mode=TwoWay}" Header="User" PlaceholderText="user@mail.com" />
          <PasswordBox Password="{Binding Password, Mode=TwoWay}" Header="Password" PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
          <Button Content="Guardar" Command="{Binding SaveCommand}" />
          <Button Content="Recuperar" Margin="12, 0" Command="{Binding ReadCommand}" />
          <Button Content="Borrar" Command="{Binding DeleteCommand}" />
     </StackPanel>
     <ScrollViewer>
          <TextBlock Text="{Binding Info}"/>
     </ScrollViewer>
</StackPanel>
Hasta aqui, la interfaz y estructura básica de nuestro ejemplo.

Continuamos centrándonos en la parte importante, la gestión de credenciales.

Gestión de credenciales

Para realizar la gestión de credenciales utilizaremos las APIs Credential Locker disponibles en Windows.Security.Credentials. Vamos a crear un servicio con la siguiente definición:

public interface IPasswordVaultService
{
     void Save(string resource, string userName, string password);
 
     PasswordCredential Read(string resource, string userName);
 
     IReadOnlyList<PasswordCredential> GetAll();
 
     void Delete(string resource, string userName);
}

NOTA: El servicio será inyectado por Ioc en nuestra viewmodel.

El servicio contará con cuatro métodos:

  • Save: Nos permitirá guardar credenciales.
  • Read: Nos permitirá recuperar un credencial concreto.
  • GetAll: Recupera todos los credenciales que tengamos almacenados en el Credential Locker.
  • Delete: Eliminará un credencial concreto almacenado previamente.

Nos centramos a continuación en la implementación de cada método. Comenzamos por el método Save:

public void Save(string resource, string userName, string password)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = new PasswordCredential(resource, userName, password);
     vault.Add(cred);
}

Analicemos el código superior. Primero, obtenemos una referencia al Credential Locker usando on objeto de tipo PasswordVault definido en el namespace Windows.Security.Credentials. Continuamos creando un objeto de tipo PasswordCredential
que representará el credencial a almacenar con la referencia a nuestra
Aplicación o el tipo de Login utilizado además de los credenciales en
si, usuario y contraseña. Añadiremos el credencial creado al almacén de
credenciales utilizando el método PasswordVault.Add.

Continuamos con el método Read:

public PasswordCredential Read(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
 
     return vault.Retrieve(resource, userName);
}

Contamos con una gran variedad de opciones para recuperar
credenciales del almacén. En el código de la parte superior utilizamos
la forma más simple posible. Contando con el nombre de la App o tipo de
Login además del nombre de usuario, podemos recuperar la información
utilizando el método PasswordVault.Retrieve.

En el método GetAll utilizamos el método PasswordVault.RetrieveAll  para recuperar todos los credenciales almacenados en la Aplicación:

public IReadOnlyList<PasswordCredential> GetAll()
{
     PasswordVault vault = new PasswordVault();
 
     return vault.RetrieveAll();
}

Además de las dos formas utilizadas contamos con otras opciones para recuperar credenciales:

Por último, nos centramos en el método Delete, que como podemos imaginar se encargará de eliminar un credencial en concreto:

public void Delete(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = vault.Retrieve(resource, userName);
     vault.Remove(cred);
}

De nuevo, es un proceso muy sencillo que podemos hacer con pocas
líneas. Accedemos de nuevo al almacén de credenciales mediante un objeto
de tipo PasswordVault y utilizamos el método PasswordVault.Remove  para eliminar el credencial almacenado pasado como parámetro.

Con nuestro servicio para gestionar el almacén de credenciales
preparado, solo nos falta definir la acción de cada comando. Al guardar
el credencial:

public void SaveCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User) || string.IsNullOrEmpty(Password))
     {
          return;
     }
 
     try
     {
          _passwordVaultService.Save(Source, User, Password);
          Info += string.Format("Datos guardatos. Resource: {0}, User: {1}, Password: {2}",
          Source, User, Password)
     }
     catch(Exception ex)
     {
          Info += ex.Message;
     }
}

Sencillo, verificamos que los datos que definen el credencial son válidos y en caso afirmativo utilizamos el método Save de nuestro servicio PasswordVaultService. Para recuperar un credencial:

public void ReadCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
     {
          Info += "La fuente y el usuario son obligatorios.";
          return;
     }
 
     try
     {
          var cred = _passwordVaultService.Read(Source, User);
          Info += string.Format("Datos obtenidos con éxito. Resource: {0}, User: {1}, Password: {2}",
          cred.Resource, cred.UserName, cred.Password);
     }
     catch (Exception ex)
     {
          Info += ex.Message;
     }
}

Utilizaremos tras validar la información, el método Read de nuestro servicio. Y por último, en el comando para eliminar credenciales:

public void DeleteCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
     {
          Info += "La fuente y el usuario son obligatorios.";
           return;
     }
 
     try
     {
          _passwordVaultService.Delete(Source, User);
          Info += string.Format("Datos eliminados con éxito. Resource: {0}, User: {1}, Password: {2}",
          Source, User, Password);
     }
     catch (Exception ex)
     {
          Info += ex.Message;
     }
}

Utilizamos el método Delete del servicio.

Podéis descargar el ejemplo realizado a continuación:

Buenas prácticas

  • El almacén de credenciales esta pensado para facilitar la tarea de
    la gestión de la seguridad en nuestras aplicaciones. No se recomienda su
    uso para almacenar grandes cantidades de información. Contamos con
    otras APIs válidas y más adecuadas para esta necesidad.
  • Debemos controlar el ciclo de almacenamiento de credenciales en el
    Password Vault correctamente. No almacenar información hasta haber sido
    autenticado correctamente y haber marcado el usuario que desea recordar
    la información.

Conclusiones

En aplicaciones universales, es decir, tanto en aplicaciones Windows
Phone como en aplicaciones Windows Store, contamos con una API,
disponible bajo el namespace Windows.Security.Credentials llamada Credential Locker
que nos permite gestionar credenciales de usuario con suma facilidad.
La gran ventaja de utilizar la API es que nos almacena la información en
un almacén seguro, la información es encriptada al ser almacenada. Además, otra de las grandes ventajas de utilizar la API es el roaming de los credenciales entre dispositivos de confianza bajo la misma cuenta Microsoft.

Más información

[Windows Phone 8.1] Capturando la pantalla utilizando la API MediaCapture

Introducción

Entre la enorme cantidad de nuevas APIs, controles y herramientas
disponibles con la llegada de Windows Phone 8.1, desde un principio
llamo mucho la atención las nuevas APIs disponibles para grabar en video o tomar capturas de la actividad de la pantalla. Esta nueva característica la tenemos disponible dentro del namespace Windows.Media.Capture y sera nuestro centro de atención en este artículo.

¿Te apuntas?

Primeros pasos

Comenzamos creando un nuevo proyecto:

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo sera muy sencillo. Nuestra aplicación de ejemplo
contará con un botón para comenzar a grabar lo que ocurre en pantalla y
otro para detener la grabación. Tras terminar la grabación podemos ver
el video resultante.

Antes de comenzar, vamos a añadir la Webcam como capacidad en el archivo Package.manifiest:

Manos a la obra!

Tomar capturas de pantalla de la aplicación e incluso videos es una
funcionalidad fantástica para segun que tipo de aplicaciones y sobretodo
en juegos. En nuestro ejemplo, debíamos contar con “algo” interesante que grabar. Para ello, vamos a añadir un elipse con una animacion Easing de modo que otorgemos el efecto de una bola cayendo y rebotando.

Para gestionar la animación vamos a utilizar el SDK de Behaviors incluido dentro de las extensiones:

Nos centramos en la vista principal, MainView.xaml. Añadimos la elipse:

<Ellipse x:Name="Ball" Height="75" Width="75" Fill="Red" RenderTransformOrigin="0.5,0.5">
     <Ellipse.RenderTransform>
          <TranslateTransform/>
     </Ellipse.RenderTransform>
     <interactivity:Interaction.Behaviors>
          <core:EventTriggerBehavior EventName="Loaded">
               <media:ControlStoryboardAction ControlStoryboardOption="Play" Storyboard="{StaticResource MyStoryboard}"/>
          </core:EventTriggerBehavior>
     </interactivity:Interaction.Behaviors>
</Ellipse>

Al cargar lanzaremos una animacion llamada MyStoryBoard que tenemos definida en los recursos de la página:

<Storyboard x:Name="MyStoryboard">
    <DoubleAnimation From="0" To="250" Duration="00:00:10"
                     Storyboard.TargetName="Ball"
                     Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)">
         <DoubleAnimation.EasingFunction>
              <BounceEase Bounces="40" EasingMode="EaseOut"
                          Bounciness="1.2" />
         </DoubleAnimation.EasingFunction>
     </DoubleAnimation>
</Storyboard>

De este modo, al lanzar la aplicación se lanzará la animación con el siguiente resultado:

Ya tenemos listo el elemento visual a grabar. Necesitamos dos botones en
nuetra aplicación. Uno para grabar la pantalla y otro que permita ver
el resultado:

<Page.BottomAppBar>
     <CommandBar>
          <AppBarButton />
          <AppBarButton />
     </CommandBar>
</Page.BottomAppBar>

Creamos una CommandBar y añadimos los botones. El
primer botón nos permitirá comenzar y detener la grabación del video. El
segundo nos permitirá ver el video resultante. Para poder conseguir
este resultado, en la viewmodel necesitaremos una propiedad
bool que nos indique si se esta grabando el video o no, para permitir
comenzar o detener la grabación y otra propiedad bool que nos indique si
ya hay un video grabado:

private bool _recording;
private bool _result;
 
public bool Recording
{
     get { return _recording; }
     set
     {
          _recording = value;
          RaisePropertyChanged("Recording");
     }
}
 
public bool Result
{
     get { return _result; }
     set
     {
          _result = value;
          RaisePropertyChanged("Result");
     }
}

El segundo botón lo mostraremos cuando la propiedad Result sea cierta, necesitaremos un Converter para convertir la propiedad bool a Visibility:

public class BoolToVisibilityConverter : IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, string language)
     {
          if (value is bool)
               return ((bool) value) ? Visibility.Visible : Visibility.Collapsed;
 
          return Visibility.Collapsed;
     }
 
     public object ConvertBack(object value, Type targetType, object parameter, string language)
     {
          return null;
     }
}

El primer botón nos permite controlar dos estados diferentes:

  • Comenzar a grabar.
  • Detener una grabación.

Si estamos grabando o no nos lo indica la propiedad Recording, necesitaremos dos converters para obtener el Label y el Icon del AppBarButton segun el valor de la propiedad:

public class RecordStateToIconElementConverter : IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, string language)
     {
            var recording = value as bool?;
 
            if (recording != null)
                return recording == true ? new SymbolIcon(Symbol.Stop) : new SymbolIcon(Symbol.Play);
            return new SymbolIcon(Symbol.Stop);
     }
 
     public object ConvertBack(object value, Type targetType, object parameter, string language)
     {
            return null;
     }
}

Cada botón realizará una acción, en la viewmodel, la ejecución de un comando:

private ICommand _recordCommand;
private ICommand _resultCommand;
 
public ICommand RecordCommand
{
     get { return _recordCommand = _recordCommand ?? new DelegateCommandAsync(RecordCommandDelegate); }
}
 
public ICommand ResultCommand
{
     get { return _resultCommand = _resultCommand ?? new DelegateCommand(ResultCommandDelegate); }
}
 
public async Task RecordCommandDelegate()
{   
 
}
 
public void ResultCommandDelegate()
{
 
}

De modo que nuestros dos botones en la CommandBar quedaran:

<AppBarButton
     Label="{Binding Recording, Converter={StaticResource RecordStateToStringConverter}}"
     Icon="{Binding Recording, Converter={StaticResource RecordStateToIconElementConverter}}"
     Command="{Binding RecordCommand}" />
<AppBarButton
     Visibility="{Binding Result, Converter={StaticResource BoolToVisibilityConverter}}"
     Label="Result"
     Icon="Forward"
     Command="{Binding ResultCommand}" />

API Windows.Media.Capture

Llegamos a la parte fundamental del ejemplo y del artículo, el uso de las APIs disponibles en Windows.Media.Capture.
Crearemos un servicio sencillo que nos permita grabar con facilidad lo
que ocurre en la pantalla de nuestro dispositivo. El servicio lo
llamaremos ScreenRecorederService y su definición sera la siguiente:

public interface IScreenRecorderService
{
     ScreenRecorderService.RecordingStatus Status { get; }
     Task Start(string recordName);
     void Stop();
}

Como podemos ver contamos con:

  • Una propieddad Status. Nos permitirá consultar en
    todo momento si el servicio esta grabando la pantalla, esta detenido, ha
    terminado la grabación con éxito o por el contrario ha ocurrido algun
    error.
  • Un evento Start que recibirá como parámetro el
    nombre del video resultante de la grabación. Este evento se encarga de
    comenzar la grabación del video.
  • Un evento Stop que detiene una grabación inciada de video.

Nos centramos en la implementación del servicio. Contaremos con una
sencilla enumeración que nos permita determinar con facilidad el estado
de la grabación:

public enum RecordingStatus
{
     Stopped,
     Recording,
     Failed,
     Sucessfull
};

Sencillo, ¿cierto?.

Comenzar la grabación del video

Nos centramos en el método Start de nuestro servicio. Comenzamos creando un objeto de clase ScreenCapture utilizando el método: GetForCurrentView:

//Inicializamos ScreenCapture.
ScreenCapture screenCapture = ScreenCapture.GetForCurrentView();

A continuación, creamos una instancia de la clase MediaCaptureInitializationSettings y establecemos la fuente de audio y vídeo con las propiedades AudioSource y VideoSource del objeto ScreenCapture previamente definido:

// Establecemos MediaCaptureInitializationSettings para que ScreenCapture capture audio y video.
var mediaCaptureInitializationSettings = new MediaCaptureInitializationSettings
{
     VideoSource = screenCapture.VideoSource,
     AudioSource = screenCapture.AudioSource,
     StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo
};

El objeto MediaCaptureInitializationSettings nos permite establecer la
configuración básica necesaria para crear un objeto de tipo MediaCapture. El objeto MediaCapture es el encargado de ofrecernos la posibilidad de capturar fotos, audio y vídeos.

// Inicializamos MediaCapture con los settings anteriores.
_mediaCapture = new MediaCapture();
await _mediaCapture.InitializeAsync(mediaCaptureInitializationSettings);

Inicializamos utilizando el método InitializeAsync pasándole como parámetro la configuración anterior.

NOTA: InitializeAsync iniciará una solicitud de consentimiento para obtener permisos de usuario.

Continuamos suscribiéndonos a los eventos Failed, RecordLimitationExceeded, y SourceSuspensionChanged:

_mediaCapture.Failed += (s, e) => { _recordingStatus = RecordingStatus.Failed; };
_mediaCapture.RecordLimitationExceeded += s => { _recordingStatus = RecordingStatus.Failed; };
 
screenCapture.SourceSuspensionChanged += (s, e) => Debug.WriteLine("IsAudioSuspended:" +
                                                                   e.IsAudioSuspended +
                                                                   " IsVideoSuspended:" +
                                                                   e.IsVideoSuspended);

Tenemos:

  • El evento Failed se lanzará cuando cualquier tipo de error ocurra durante la grabacion del video.
  • El evento RecordLimitationExceeded se lanzará cuando se supere el tiempo máximo de grabación. En Windows 8.1 el tiempo máximo de grabación es de 3 horas.
  • El evento SourceSuspensionChanged se lanzará cada
    vez que se cambie el estado de activo y suspensión de la aplicación
    durante la grabación del video. Profundizaremos en la gestión de la
    grabación del video y la suspensión de la aplicación algo más adelante
    en este mismo artículo.

A continuación, definimos el perfil de codificación para el archivo
de video y audio. Para ello, utilizamos un objeto de la clase MediaEncondingProfile. Tenemos disponible los  formatos más habituales tanto de video como de audio:

  • MP3
  • MP4
  • Wav
  • Wma
  • Wmv
// Creamos un encondig a utilizar. Por defecto, MP4 1080P.                  
MediaEncodingProfile mediaEncodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD1080p);

Tras crear el perfil de codificación, creamos el archivo donde se guardarán los medios capturados:

// Creamos el fichero resultante de la grabación.            
StorageFile video =
                    await
                        ApplicationData.Current.LocalFolder.CreateFileAsync(string.Format("{0}.mp4", recordName),
                            CreationCollisionOption.ReplaceExisting);

Por último, utilizaremos el método StartRecordToStorageFileAsync para comenzar la grabación:

// Con el formato, calidad y archivo destino definidos, comenzamos a grabar.
IAsyncAction startAction = _mediaCapture.StartRecordToStorageFileAsync(mediaEncodingProfile, video);
startAction.Completed += (info, status) =>
{
     if (status == AsyncStatus.Completed)
          _recordingStatus = RecordingStatus.Recording;
     if (status == AsyncStatus.Error)
     {
          _recordingStatus = RecordingStatus.Failed;
          Debug.WriteLine(info.ErrorCode.Message);
     }
};

Detener la grabación del video

Para detener la grabación del video utilizamos el método StopRecordAsync.

public void Stop()
{
     //Detenemos la grabación.           
     IAsyncAction stopAction = _mediaCapture.StopRecordAsync();
     stopAction.Completed += (info, status) =>
     {
          if (status == AsyncStatus.Completed)
               if (_recordingStatus == RecordingStatus.Recording)
                    _recordingStatus = RecordingStatus.Sucessfull;
     };
}

Gestion de la suspensión

Ya hemos mencionado el evento SourceSuspensionChanged. Ante
ciertas circunstancias la grabación se suspende para ser reanudada tras
finalizar la acción que provocó la suspensión. El video y el audio se
pueden bloquear de manera independiente por lo que en ciertas
circunstancias se detendrá la grabación de video, en otras las de audio y
en ocasiones ambas. Entre alguna de las situaciones que provocan a
detención de la grabación tenemos:

  • Una llamada entrante. Detiene la grabación de video y audio.
  • Notificaciones con información personal del usuario.
  • Cuando la aplicación no esta en primer plano.
  • Cuando se reproduce sonido en background se detiene la grabación de audio.

Con el evento SourceSuspensionChanged podemos detectar si se ha detenido la grabacion de video y audio gracias a las propiedades IsVideoSuspended y IsAudioSuspended
respectivamente. Podemos utilizar las propiedades para notificar al
usuario que se ha detenido la grabacion. Sin embargo, para reanudar la
misma no tenemos que hacer nada.

Buenas prácticas

Para no interferir con otras aplicaciones que el usuario pueda
utilizar cuando suspende nuestra aplicación, debemos limpiar los
recursos de captura utilizados en la suspensión.

Para realizar esta tarea creamos una propiedad pública con un objeto de tipo MediaCapture en el archivo App.xaml.cs:

public MediaCapture MediaCapture { get; set; }

Establecemos la propiedad en nuestro servicio:

// Establecemos el MediaCapture de App.xaml.cs para gestionar la suspensión.
var app = Application.Current as App;
if (app != null) app.MediaCapture = _mediaCapture;

En el evento OnSuspending realizaremos la detención de la grabación y la liberación de recursos:

if (MediaCapture != null)
{
     await MediaCapture.StopRecordAsync();
 
     MediaCapture.Dispose();
}

Podéis descargar el ejemplo realizado a continuación:

Más información

[Evento CartujaDotNet] Sevilla Mobility Day: Strikes Back

El evento

Tras el éxito de registro y asistencia al primer Sevilla Mobility Day, desde CartujaDotNet no podíamos más que repetir la formula. De esta forma nos llega la segunda edición, Sevilla Mobility Day: Strikes Back.

En
esta ocasión, hemos tomado todo lo bueno del evento anterior, hemos
analizado los detalles que debíamos mejorar y el resultado creemos que
es muy interesante. Tendremos  una mañana con repleta de sesiones
técnicas hablando de como integrar Cortana con aplicaciones Windows Phone, monetización de Apps con Fortumo Mobile, integrar Windows Phone con Pebble, generación de backends con AppNow y desarrollo de Webapps. Y si te pudiese parecer poco, en esta ocasión organizamos además una mesa redonda sobre TDD.

¿Te apuntas?

Fecha

El evento tendrá lugar el próximo Sábado, 25 de Octubre de 9:00h a 14:30h. Cada charla tendrá una duración de 40 minutos con descanso intermedio de 5 minutos.

NOTA: Tras las dos primeras sesiones tendremos una pausa de 15 minutos para reponer fuerza.

Lugar

Tendrá lugar en el Cloud Pointing de Sevilla situado en el Parque Empresarial Nuevo Torneo. Tenéis la información exacta del lugar a continuación:

c Biología, 12, Edificio Vilamar 2, 3ª Planta
Parque Empresarial Nuevo Torneo
41015 Sevilla

Agenda y Ponentes

El evento cuenta con una gran variedad de ponentes de lujo:

  • 9:00h – 9:05h: Bienvenida.
  • 9:10h – 9:50h: Un servidor realiza un recorrido por todos los aspectos a tener en cuenta para integrar nuestras aplicaciones Windows Phone con Cortana.
  • 9:55h – 10:35h: Josué Yeray nos introducirá Fortumo Mobile Payments, sistema de pago en aplicaciones universales.
  • 10:50h – 11:30h: Roberto Luis Bisbé nos mostrara como conectar Windows Phone con otros dispositivos.
  • 11:35h – 12:15h: De la mano de Asier Marques tendremos una interesante sesión donde aprenderemos a realizar WebApps.
  • 12:20h – 13:00h: Tras tanto fronted nos llega el turno del backend. Pedro J. Molina nos explicará como crear backends para nuestras aplicaciones con App Now.
  • 13:05h – 15:45h: David Rodriguez nos cuenta su experiencia con GeoMotion, App móvil asociada al localizador GPS para automóviles desde su inicio hasta hoy día.
  • 13:50h – 14:30h: Finalizamos el evento con una interesante y muy divertida mesa redonda junto a Juan María Lao, ¿TDD a favor o en contra?

Más información

[Evento WPSUG] Monetización con Fortumo Mobile Payments

Introducción

Volvemos a la carga en WPSUG, grupo de usuarios hispanos de Windows Phone,
con un nuevo Hangout sobre desarrollo en Windows y Windows Phone. En
esta ocasión, trataremos un punto fundamental y prioritario como
desarrolladores de aplicaciones móviles, la monetización
de las mismas. Una forma sencilla de gestionar la monetización es
utilizando las APIs de In App Purchase de WinRT. En la mayoría de
ocasiones, no tenemos ningun problema asociado. Sin embargo, debemos
tener en cuenta que en estos casos el pago es mediante una tarjeta de
crédito asociada a la cuenta de la tienda. No todo el mundo cuenta con
tarjeta de crédito, de hecho, si pensamos en ciertos países el problema
se acentúa. En algunos países, Microsoft ya soporta pagos con el
operador móvil, pero solo contamos con 37 de los 191 países donde se
encuentra la tienda disponible. Para mejorar esta situación contamos con
Fortumo Mobile Payments, que incrementa y mejora las opciones de pago. En este evento:

  • Aprenderemos que es Fortumo Mobile Payments.
  • Analizaremos todas sus características principales.
  • Integraremos el sistema de pago en una aplicación universal.

El evento

El próximo Miércoles 22 de Octubre, a las 18:00 (GMT+1) 
tendra lugar un Hangout en el que tendremos el placer de contar con un
ingeniero de Fortumo Mobile, que nos contará de primera mano todos los
detalles relacionados con la monetización en Windows y Windows Phone con
Fortumo. La sesión sera en ingles. Sin embargo, estaremos tanto Josué Yeray como un servidor para ayudar y gestionar dudas y otros detalles en español.

¿Te apuntas?

Más información

[Evento] Material del Madrid Mobility Day

El evento

El pasado Martes, 30 de Septiembre tuve el enorme placer de participar en el Madrid Mobility Day junto a Josué Yeray, Alejandro Campos y Luis Guerrero.
El evento constaba de múltiples sesiones de desarrollo para Windows y
Windows Phone, publicación y marketing, desarrollo de videojuegos con Unity y desarrollo de aplicaciones móviles multiplataforma con Xamarin.

Las charlas

Participé con dos charlas de desarrollo:

  • Desarrollo de aplicaciones Windows Phone con Silverlight 8.1.
  • Introducción al desarrollo de apps móviles multiplataforma con Xamarin.Forms. En esta ocasión con la inestimable ayuda de Josué Yeray.

Desarrollo de aplicaciones Windows Phone con Silverlight 8.1

Con la llegada de Windows Phone 8.1 tenemos nuevas formas posibles de
desarrollar nuestras aplicaciones. Por un lado se habla de Silverlight
8.1, por otro de Windows XAML, WinJS, etc. La idea de la charla era:

  • ¿Que diferencia hay entre Silverlight 8.1 y Windows XAML?
  • ¿Si ya tengo una App Windows Phone 8.0, que uso?
  • ¿Y si es Windows Store?

En Windows Phone 8.1 podemos desarrollar con:

  • Silverlight Windows Phone 8.0: Todas las
    aplicaciones Windows Phone 8.0 funcionan en Windows Phone 8.1 aunque
    evidentemente sin tener acceso a las nuevas APIs.
  • Silverlight 8.1: Nueva versión destinada a migrar aplicaciones con rapidez y sencillez.
  • Windows XAML: Gran novedad, llega a Windows Phone
    una nueva versión de XAML, el ya usado en aplicaciones WinRT. La
    convergencia entre las paltaformas se potencia gracias a esta nueva
    opción dando lugar a los proyectos universales.
  • WinJS: Permite desarrollar aplicaciones nativas con
    HTML5, CSS y JS. Ahora además de aplicaciones Windows Store permite
    crear aplicaciones Windows Phone, incluso aplicaciones universales.

Las conclusiones básicas de la charla fueron:

  • Si tienes una aplicación Windows Phone 8.0 y no necesitas ninguna de
    las nuevas APIs disponibles en Windows Phone 8.1 no tienes que hacer
    nada. Las aplicaciones Windows Phone 8.0 funcionan en los dispositivos
    Windows Phone 8.1.
  • Si tienes una aplicación Windows Phone 8.0 y quieres utilizar las
    nuevas APIs de Windows Phone 8.1, Silverlight 8.1 es una buena opción.
    Silverlight 8.1 nos permite migrar aplicaciones con suma facilidad. Si
    tu aplicación utiliza:

    • CameraCaptureTask
    • Camera Lenses
    • Lockscreen background image provider
    • Alarmas
    • Recordatorios

Silverlight 8.1 es tu opción ya que estas opciones son exclusivas de Silverlight.

  • Sin embargo, hay opciones disponibles en Windows Phone 8.0 que no
    estan disponibles en Silverlight 8.1 como por ejemplo Background Audio.
    En este caso Windows XAML es la opción adecuada.
  • Si partimos de una aplicación Windows Store, Windows XAML es más directo.
  • Si partimos de una aplicación Windows Store desarrollada con WinJS, utilizar WinJS para Windows Phone es lo más idóneo.
  • Si partimos de cero, podemos elegir entre Windows XAML, WinJS o
    Silverlight 8.1. Todo depende de los conocimientos que tengas en los
    lenguajes y que quieras realizar. Si quieres cubrir teléfonos y tabletas
    (aplicaciones Windows Phone y Windows Store), realizar una aplicación
    universal es lo más idóneo.

Introducción al desarrollo de apps móviles multiplataforma con Xamarin.Forms

Con la reciente actualización a la versión 3 de Xamarin nos llega Xamarin.Forms. Es un toolkit para crear una abstracción sobre la interfaz de usuario de Android, iOS y Windows Phone permitiendo desarrollarla una única vez con código C# o Extensible Application Markup Language (XAML).

En esta sesión junto a Josué Yeray teníamos como objetivos:

  • Trasmitir en que consiste y como funciona Xamarin.Forms.
  • Crear y explicar una App desde cero.
  • Aplicar MVVM.
  • Comparar con alternativas como MVVMCross.

El material

Desarrollo de aplicaciones Windows Phone con Silverlight 8.1

Os dejo a continuación la presentación utilizada en esta sesión:

 

Además de los ejemplos.

Introducción al desarrollo de apps móviles multiplataforma con Xamarin.Forms

Presentación utilizada en esta sesión:

 

Y ejemplos.

Extra

No quisiera terminar sin agradecer a los chicos de DX por su colaboración,  facilitarnos la sala y en definitiva hacer que todo sea tan sencillo. También me gustaría agradecer a Cristina Guerrero, nuestra MVP Lead
por realizarnos una visita. Era la primera vez que la conocía en
persona y solo puedo decir que es aun más encantadora en persona si
cabe. Y por supuesto, como no, gracias a todos los asistentes.

Más información