Es mostren els missatges amb l'etiqueta de comentaris android. Mostrar tots els missatges
Es mostren els missatges amb l'etiqueta de comentaris android. Mostrar tots els missatges

dimarts, 16 de febrer del 2016

OpenGL

Android incluye soporte para alto rendimiento en 2D y gráficos 3D con la biblioteca de gráficos abierta (OpenGL), en concreto, la API OPENGL es una api de gráficos de plataforma cruzada que esepcifica una interfície de programario estándar para el maquinario de proceso de gráficos 3D. OPENGL es una adaptación de la especificación OpenGL destinada a dispositivos encastados.
Android es compatible con varias versiones de la API OpenGL.
Es una api que especifica como se hacen los modelos 3D... hay un jugador que mira al mundo, todo esta compuesto por triángulos, las matrices de trabajo están perfectamente definidas, forma parte de kronos, lo hicieron para los sistemas 3D.
Kronos es una fundación con ánimo de lucro, todo es libre pero se ganan dinero por el hardware. Se creó en lenguaje C, es de estado secuencial y trabaja matricialmente, era un c sin complicaciones porque estaba pensado para código máquina. La gracia es que el algoritmo de cálculo de una superficie la puede hacer o bien el hardware y si este no lo tiene implementado lo hace el software.
Entonces si tienes un programa que tiene que hacer iluminación, hay que tener en cuenta que el hardware es mucho más rápido que usar el software.
Hay varias versiones, estas hacen referencia al OpenGL a dispositivos móviles, el webGL es con javascript con navegador y unicamente OpenGL para los PCs de mesa, como Windows, Linux, Apple...
Las diferentes y más relevantes versiones de OpenGL serian:
  • OpenGL ES 1.0 y 1.1 - especificación API con soporte de android 1.0 y superior.
  • OpenGL ES 2.0 - especificación API soportado por Android 2.2 (nivel de API 8) 4.3 y superior.
  • OpenGL ES 3.0 - especificación API con soporte para android (nivel de API 18) 4.3 y superior.
L'API especifica proporcionada por Android es similar a la API J2ME JSR239 OpenGL ES, pero no es idéntica.

Hay dos clases fundamentales en Android que te permite crear y manipular gráficos con la API OpenGL ES:
  • GL.SurfaceView.
  • GL.SurfaceView.Renderer.

GL.SurfaceView

Esta clase es una View donde se puede dibujar y manipular objetos mediante llamadas a la API de OpenGL y es similar en función a un  . Se puede utilizar esta clase mediante la creación de una instancia de GLSurfaceView y añadiendo su Renderer en ella. No obstante, si queremos capturar desarrollos de pantalla táctil, se ha de ampliar la clase. GLSurfaceView para implementar los oyentes táctiles.
El GLSurfaceView es una vista especial que gestiona superficies OpenGL para nosotros y dibuja en el sistema de visión de Android. También añade una gran cantidad de características que hacen que sea más fácil de usar OpenGL, incluyendo pero no limitado a:
  • Proporciona un subproceso de representación dedicada para OpenGL porque no afecte al fin principal.
  • Nos permite dibujar siempre que queramos.
  • Se ocupa de la configuración de pantalla para nosotros, utilizando EGL, la interfície entre OpenGL y el sistema de ventanas subyacente.
Esencialmente tendremos una vista, igual que tenemos botones, imagenes y textView, tendremos un GLSurfaceView, todo lo que se dibuje ahí irá por hardware. Para utilizar OpenGL se recomiendan las APIS de java, OpenGL esta especificado en C, pero son cáculos matriciales por lo tanto no hay centenares de líneas de código, sino que son productos transformados que pueden llevar a cualquier lenguaje de programación. Con cualquier lenguaje de programación puedes hacerlo.

GLSurfaceView.Renderer

Aquesta interfície define los métodos necesarios para dibujar gráficos en un GLSurfaceView. Se tiene que proporcionar una implementación de esta interfície con una clase separada y adjuntarla a la instancia GLSurfaceView utilizando GLSurfaceView.setRenderer().
Requiere que implemente los métodos siguientes:
  • onSurfaceCreated(): El sistema llama a este método una vez, en crear el GLSurfaceView. Utilizad este método para llevar acciones que tienen que ocurrir solamente una vez, como configurar los parámetros del entorno OpenGL o el inicio de objetos gráficos OpenGL.
  • onDrawFrame(): El sistema llama a este método en cada redibujo del GLSurfaceView. Utilizad estos métodos como principal punto de ejecución para elaborar (y redibujar) objetos gráficos.
  • onSurfaceChanged(): El sistema llama a este método cuando los GLSurfaceView cambian de geometría, incluyendo cambios en el tamaño del GLSurfaceView o la orientación de la pantalla del dispositivo. Por ejemplo el sistema que llama a este método cuando el dispositivo cambia de vertical a horizontal. Utilizad este método para responder los cambios en el GLSurfaceView contenedor.
 Si la aplicación utiliza funciones de OpenGL que no estan disponibles en todos los dispositivos tiene que incluir estos requisitos dentro del archivo AndroidManifest.xml:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature android:glEsVersion="0x00030000" android:required="true" />

API OpenGL ES 3.0 es compatible con la 2.0, lo que significa que puede ser mas flexible con su implementación de OpenGL ES en la aplicación. Declarar OpenGL 2.0 es un requisito, y al comprobar la disponibilidad de la API 3.0 en tiempo de ejecución, si es compatible, utilizará esta.
Ejemplo de  código:
@Override
public void onCreate(Bundle savedInstanceState)
   {
   super.onCreate(savedInstanceState);
   mGLSurfaceView = new GLSurfaceView(this);
   // soporta OpenGL ES 2.0?
   final ActivityManager activityManager = (ActivityManager)
   getSystemService(Context.ACTIVITY_SERVICE);
   final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
   final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
   if (supportsEs2){
      // contexto compatible
      mGLSurfaceView.setEGLContextClientVersion(2);
      mGLSurfaceView.setRenderer(new NuestroRenderer());
   } else{
      // Usar OpenGL ES 1, por ejemplo
   }
   //utilizamos toda el area de la activity
   setContentView(mGLSurfaceView);
}

Antes de que nuestro procesador muestre algo, necesitamos algo que mostrar. En OpenGL ES 2, especificamos matrices de nombres. Estos números pueden representar posiciones, colores, o cualquier otra cosa. En esta demo mostraremos tres triángulos.

// Los datos estan guardados en buffer de tipo float.
private final FloatBuffer mTriangle1Vertices;
private final FloatBuffer mTriangle2Vertices;
private final FloatBuffer mTriangle3Vertices;
//nombre de bytes per float
private final int mBytesPerFloat = 4;
//Inicialitzatció.
public NuestroRenderer(){
   final float[] triangle1VerticesData= {
      // X, Y, Z,
      // R, G, B, A
      -0.5f, -0.25f, 0.0f,
      1.0f, 0.0f, 0.0f, 1.0f,

      0.5f, -0.25f, 0.0f,
      0.0f, 0.0f, 1.0f, 1.0f,

      0.0f, 0.559016994f, 0.0f,
      0.0f, 1.0f, 0.0f, 1.0f
   }
   // Inicialización de los buffers.
   mTriangle1Vertices = ByteBuffer.allocateDirect(triangle1VerticesData.length *    mBytesPerFloat).order(ByteOrder.nativeOrder()).asFloatBuffer();
   ...
   mTriangle1Vertices.put(triangle1VerticesData).position(0);
   ...
}

Es normal que la codificación este en Java en Android, pero la implementación interna de OpenGL ES 2 esta escrita en C. Antes de pasar nuestros datos por OpenGL, tenemos que convertirlo a un formato que se puedan entender. Java y el sistema operativo nativo podría no guardar sus bytes en el mismo orden, así que hace falta utilizar un conjunto especial de clases de amortiguación y crear un ByteBuffer suficientemente grande como para mantener, entre nuestros datos, y decirle que para guardar los datos utilizando la orden de bytes nativo. Entonces los convertimos en un FloatBuffer, para que podamos hacerlo servir para guardar los datos de punto flotante. Finalmente, copiamos nuestra matriz en la memoria intermedia.

Apuntes.
Ejemplo.















Reproducción de medios

Una buena experiencia de usuario es imprescindible.
Las aplicaciones multimedia tienen que ofrecer a los usuarios poder controlar el volumen de su aplicación utilizando el hardware o el software de control del volumen del dispositivo, auriculares bluetooth, o los auriculares.
De la misma manera, tiene que ser posible parar, pausar, saltar... Los medios que se están reproduciendo.
Android mantiene un flujo (mediaplayer) de audio para cada medio, notificación, llamada... que hay en el dispositivo. Se puede controlar el volumen de cada uno por separado.
La mayoría de estos flujos responden a STREAM_MUSIC, otros corresponderían como flujos del sistema, como la alarma.
Por defecto, poner las teclas del dispositivo cambia el volumen del flujo activo. Si el dispositivo no esta reproduciendo nada cambia el volumen de la llamada.
Mediante setVolumeControlStream() se puede cambiar el volumen del audio que se esta reproduciendo.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
Hace que al pulsar las teclas de volumen funcionen como se espere.
Para esto, necesitaremos los permisos:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Disponemos de la posibilidad de que responda a las teclas de pausa, reproducción... para que sea nuestra app la que lo controle, necesitará el broadcast, dentro del manifest, sería el broadcast que escuchamos. Normalmente lo lanza el sistema, nosotros normalmente usamos RemoteControlReceiver.
<receiver android:name=".RemoteControlReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
tendremos la clase broadcastReceiver que es y le hacemos hacer la acción.
y el receptor extrae la tecla que se tiene que pulsar de la siguiente manera:
public class Receptor extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
   if (
      Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())){
         KeyEvent event =(KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
      if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()){
          // tecla pulsada
         }
      }
   }
}
Android utiliza el foco de audio para moderar cuando diversas apps están reproduciendo medios. Antes que una app inicie la reproducción tiene que pedir y recibir el foco. Con requestAudioFocus() podremos pedir el foco y devolverá AUDIOFOCUS_REQUEST_GRANTED si lo ha conseguido.
Hace falta especificar que flujo se esta utilizando y si será puntual o permanente la petición, por ejemplo un aviso o reproducción de música.
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// petición del foco para reproducir música
int result = am.requestAudioFocus(afChangeListener,
   // utiliza un flujo de música
   AudioManager.STREAM_MUSIC,
   // petición permanente
   AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
   am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
   // comienza la reproducción.
}
Cada vez que cambia el foco, cambia el changelistener y le podemos decir lo que tiene que hacer.
Cada vez que la aplicación que roba el foco se dispara:
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
este va a buscar si hay alguna cosa programada.
Una vez finaliza la reproducción hace falta liberar el foco de audio con abandonAudioFocus().am.abandonAudioFocus(afChangeListener);
Esta la posibilidad de que el volumen quede bajo hasta que se vuelva a poner el foco en la app inicial, por ejemplo un navegador de rutas para un vehículo, esto se hace con:
int result = am.requestAudioFocus(afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
);

También podemos gestionar cuando un foco cambia de app:

// gestión cuando se pierde el foco, el cual depende de la manera como se pierde.
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
// Pausa
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Sigue reproduciendo.
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Para.
}
}
};


Reducir el volumen (ducking) nos permite puntualmente reducir el volumen cuando una app tiene el foco de audio sin parar la reproducción.

OnAudioFocusChangeListener afChangeListener = new
OnAudioFocusChangeListener() {
   public void onAudioFocusChange(int focusChange) {
      if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
         // Baja el volumen
      } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
         // Sube el volumen
      }
   }
};

Los usuarios pueden disponer de altavoces, auriculares, etc, y hace falta saber como conectar y gestionar cada uno de estos dispositivos.
Para saber que dispositivos se están utilizando, utilizaremos la clase AudioManager.
if (isBluetoothA2dpOn()) {
   //ajustamos para Bluetooth.
} else if (isSpeakerphoneOn()) {
   // ajustamos para altavoz
} else if (isWiredHeadsetOn()) {
   // ajustamos para auriculares
} else { 

   // no hay ninguna salida para escuchar el audio.
}
En el caso de cambiar alguno de estos dispositivos podemos tener problemas con el volumen. Dispondremos de una señal que se envía a las aplicaciones ACTION_AUDIO_BECOMING_NOISY para controlar estos casos.

private class Receptor extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

   if(AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())){
      // Hacemos una pausa
      }
   }
}
private IntentFilter intentFilter = new
IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private void startPlayback() {
   registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
}
private void stopPlayback() {
   unregisterReceiver(myNoisyAudioStreamReceiver);
}



1. Desarrolla una aplicación para Android que reproduzca una pista de música almacenada en los recursos del dispositivo. La aplicación debe disponer de botones para parar, pausar e iniciar la pista de música. Debe mostrar el tiempo de reproducción.
Solución.
Proyecto en Android Studio.
2. A partir del ejercicio anterior, crea un servicio en primer plano que realice la reproducción de música mostrando con una notificación de información al usuario en la barra de estado.
Solución.
3. Crea una aplicación móvil para Android que permita acceder a los contenidos de música de tu dispositivo, los muestre en una lista, y en seleccionar una pista la reproduzca. Crea una animación de un botón que al pulsarlo desaparezca.
Solución.


Apuntes.

Cámara en android

Hace referencia a las librerias de multimedia integradas.
En realidad no solo leemos la biblioteca, también hacemos la foto.
Uno de los recursos mas importantes son las fotos, un recurso que tiene android es poner en marcha la aplicación de cámara, la ponemos en marcha y recibimos la foto o también podemos integrarla en nuestra propia aplicación. Según como, puede marcar que esta deprecated, hay una clase que han cambiado de la 4.4 a la 5, por el tema de las cámaras que trabajan a 360º.
Hay unas cuantas consideraciones sobre el tema de utilizar cámara en cuestión:
El uso de la cámara se ha de poner en el manifest.
DIAPO3-4
Tenemos camera, surfaceView, MediaRecorder y intención.
En el manifest tenemos que poner que queremos usar la cámaraç<ues-permision...
Diapo 5
---
El acceso a la aplicación de fotos es uno de los recursos habituales, explica comousar el emulador....
Para poner en marcha la aplicación, tenemos que crear un intent, con la URI andorid.media.action.IMAGE_CAPTURE" pone en marcha la aplicación de camara y cuando hacemos el start y será el intent que se le envia.
RESULTOKEY RESULTCANCEL...

OnActivityResult será lo que se ejecutará cuando recibamos la foto hecha.



Ejemplo1:




Ejemplo2:

Ejemplo 3:




Apuntes.


Estilos y temas (Android)

Un estilo es un conjunto de propiedades que especifican el aspecto y el formato de un View o ventana, un estilo puede especificar propiedades como la altura, color de una fuente... se puede definir con un XML.
Los estilos de android comparten una filosofía similar en las hojas de estilo, permitiendo separar diseño del contenido.
Por ejemplo, podemos transformar:
<TextView
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:textColor="#00FF00"
   android:typeface="monospace"
   android:text="@string/hello" />

En:

<TextView
   style="@style/CodeFont"
   android:text="@string/hello" />

Todos los atributos relacionados con los estilos se han retirado del XML del diseño y puestos en una definición de estilo llamada CodeFont, que se aplica a continuación con el atributo style. Un tema es un estilo aplicado a toda una actividad o a una aplicación, en vez de a una única View (como el ejemplo anterior). Cuando se aplica un estilo como un tema, cada vista en la actividad o aplicación tendrán las propiedades del estilo.
Por ejemplo, se peude aplicar el mismo CodeFont estilo como un tema para una actividad y después todo el texto dentro de esta actividad tendrá una fuente senzilla de color verde.
Por lo tanto, se parecen mucho a los css, los hijos heredan los estilos, como tipografia color...
El tema se aplica automaticamente a todos los componentes, en cambio los estilos no. El tema se puede aplicar por actividades o por aplicación, por lo tanto esta definido mediante el android manifest. Si a parte de todo el tema aplicas un estilo, este prevalece.
Para definirlo se hace con un archivo xml que esta en recursos.
el nombre del fichero el que quieras, la raiz es recursos.
Para crear un conjunto de estilos, hace falta dejar un fichero XML en el directorio res/values/ del projecto, con un nombre cualquiera.
Para cada estilo que queramos crear, hará falta añadir un elemento <style> al archivo con un nombre que identifica de forma única el estilo. A continuación, hay que añadir un elemento <item> para cada propiedad de este estilo, con un nombre que declara la propiedad de estilos y un valor para asociar con ella. El valor para el <item> puede ser una cadena de palabras clave, un color hexadecimal, una referencia a otro tipo de recurso o a otro valor en función de la propiedad del estilo.
Por ejemplo:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <style name="CodeFont" parent="@android:style/TextAppearance.Medium">
   <item name="android:layout_width">fill_parent</item>
   <item name="android:layout_height">wrap_content</item>
   <item name="android:textColor">#00FF00</item>
   <item name="android:typeface">monospace</item>
 </style>
</resources>Los estilos por programación se pueden modificar. necesitaremos poner un identificador.
Nosotros podemos coger un estilo y como padre coge el textappareance, este ejemplo tenemos item android:textcolor que modificamos el color.

Todos los hijos de <resources> hacen un objeto de recurso de aplicación en tiempo de compilación, se puede hacer referencia por el nombre <style>
El atributo parent al elemento <style> es opcional y especifica la ID del recurso de otro estilo del cual este estilo tiene que heredar propiedades. A continuación puedes anular las propiedades de estilo heredadas si quieres.
Un estilo que se quiere utilizar como una actividad o un tema de aplicación se define en XML exactamente lo mismo para un estilo que para una vista. Un estilo como el que se ha definido antes se puede aplicar como un estilo para una vista única o tema de una actividad o aplicación entera.
Un ejemplo de la herencia de estilos:
<style name="textVerd" parent="@android:style/TextAppearance">
    <item name="android:textColor">#00FF00</item>
</style>
En el caso de heredar de un estilo propio, la sintaxis es algo diferente:
<style name="CodeFont.Rojo">
    <item name="android:textColor">#FF0000</item>
</style>
<style name="CodeFont.Rojo.Gran">
    <item name="android:textSize">30sp</item>
</style>
Permite crear un estilo propio, nombre codefont de tipo rojo, después tenemos un subtipo.
Para aplicar el estilo ponemos style y le aplicamos el código fuente. Si lo queremos hacer para toda la aplicación tiene que ser en nivel de theme, muchos estilos empaquetados definen un tema.
Por lo tanto, hay dos maneras de configurar un estilo:
  • Para vista individual, añadiendo el atributo style a un elemento View al XML por su diseño.
  • Para toda una actividad o aplicación, añadiendo el atributo android:theme al activity o element <application> en el manifest de Android.
<TextView style="@style/CodeFont" android:text="@string/hello" />
<application android:theme="@style/CustomTheme">
<activity android:theme="@android:style/Theme.Dialog">

Android también ofrece otros recursos incorporados, hay muchos temas predefinidos que se pueden utilizar para evitar escribir tu mismo.

<color name="custom_theme_color">#b0b0ff</color>
<style name="CustomTheme" parent="android:Theme.Light">
   <item name="android:windowBackground">@color/custom_theme_color</item>
   <item name="android:colorBackground">@color/custom_theme_color</item>
</style>

En este caso, para crear un tema se hereda de un tema existente y se le hace las modificaciones que queremos.


Android, theme.Light es uno claro, con android studio se pueden ver los temas fácilmente, y podemos ver un color que esta predefinido. Los estilos se crean de la misma manera que los estilos de vista pero se usa el color standard.


Ejemplo.

diumenge, 31 de gener del 2016

Animaciones y gráficos


Android nos permite trabajar a nivel gráfico de dos maneras, a nivel de cocina, que es con el ndk que puedes programar un mix entre java y c, para hacer gráficos de alto rendimiento, y con sdk, haciéndolo en android que hace llamadas a la cpu, depende con el nivel de gráficos que queramos trabajar.

Podemos coger una imagen y hacer una batería de imágenes, podemos definir por xml o programación este proceso.

Una misma animación se pude hacer de varias formas, podemos definir la durada de la animación, la interpolación (si el movimiento es lineal o hay un cambio), si se tiene que repetir la animación, si se tiene que reproducir al inreves, si son un conjunto animados de elementos, también podremos indicar fotogramas por segundo...
La clase ValueAnimator mantiene la pista de la animación (como por ejemplo, cuanto tiempo llevamos animando un objeto y el valor actual de la propiedad que se esta animando, esta clase encapsula TimeInterpolator, que se encarga de la interpolación de la animación y TypeEvaluator para determinar como se han de calcular los valores (enteros reales...)), con start se inicia.





Diferencia con ViewAnimation
ViewAnimation solo sirve para animar los objetos que heredan de View (ProgressBar, TextView, etc), como un canvas.
Además no expone todas las propiedades de estos objetos.

La mayoría de estas clases se encuentran en el paquete android.animation.
La clase Animator dispone de la infraestructura básica para crear animaciones, pero normalmente trabajamos con sus subclases:
  • ObjectAnimator: es una subclase de ValueAnimator que le permite establecer un objeto de destinación y la propiedad de un objeto que desea animar. Esta clase actualiza la propiedad en consecuencia cuando se calcula un nuevo valor para la animación. Podemos utilizar ObjetAnimator la mayor parte del tiempo, porque hace que el proceso de animación de los valores en objetos de destinación sean mucho mas fáciles. No obstante, hay veces que es mejor utilizar ValueAnimator directamente porque ObjetAnimator tiene mas restricciones, como la exigencia de métodos específicos accesorios en el objeto de destinación.
  • AnimatorSet: Proporciona el mecanismo para hacer un grupo de animaciones juntos, para que se ejecuten el uno con el otro. Podemos configurar animaciones de objetos juntos, de manera secuencial, o después de un retraso determinado. Es decir, determinar ejes X y Y.
  • ValueAnimator.
Los evaluadores dicen como se han de calcular los valores de las propiedades que se están animando. Disponen de IntEvaluator, para las propiedades int, float Evaluator para propiedades float, ArgbEvaluator para propiedades de color y TypeEvaluator que es una interficie.

Los interpoladores indican como se tienen que calcular los valores con el paso del tiempo. AccelerateDecelerateInterpolator, AccelerateInterpolator, LinearInterpolator, son ejemplos de interpoladores.

AccelerateDecelerateInterpolator

public float getInterpolation(float input){
   return (float) (Math.cos((input+1)*Math.PI) /2.0f) + 0.5f;
}

LinearInterpolator
pubic float getInterpolation(float input){
   return input;
}

ms Lineal acc/deacc
0 0 0
200 .2 .1
400 .4 .345
600 .6 .8
800 .8 .9
1000 1 1

Permite animar la propiedad que se le pasa como argumento.
Le ponemos set<propiedad>() y get<propietat> para obtener valores.
Si el objeto no tiene set, podemos añadirlo, podemos hacer una clase envoltorio o crear ValueAnimator. Si se especifica un solo valor, se entiende que es el final. El objeto tiene que tener un get<propiedad> para obtener el valor incial.
Ejemplo AnimatorSet:
AnimatorSet bouncer = new AnimatorSet();

bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(pilota, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);

animatorSet.start();

Dispondremos de un conjunto de listeners para saber que esta pasando en la animación y programar si queremos callbacks, onAnimationStart(), onAnimationEnd(), onAnimationUpdate(), onAnimationRepeat(), etc. esto nos permitirá responder por ejemplo al final de una animación (onAnimationEnd()).

ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(pilota, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
   public void onAnimationEnd(Animator animation) {
      pilotes.remove(((ObjectAnimator)animation).getTarget());
   }
}

La animación por llaves consiste en especificar llaves formadas por tiempo/valor. Cada valor tiene su propio interpolador para controlar el comportamiento de la animación en el intervalo definido.
Se hacen servir métodos ofFloat(), etc.

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder rotacio = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator animacio = ObjectAnimator.ofPropertyValuesHolder(target, rotacio)
animacio.setDuration (5000ms);


Los objetos heredan de View (prácticamente todos los estudiados) disponen de propiedades translationX, translationY, rotation, rotationX, rotationY, alpha, etc... para ser manipulados con mayor facilidad. Por ejemplo:

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

La clase ViewPropertyAnimator permite animar varias propiedades en paralelo, hay tres maneras de hacer lo mismo:
Con ObjetcAnimator:
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

Con PropertyValuesHolder:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x",50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
Con ViewPropertyAnimator (los hace de forma simultanea):
myView.animate().x(50f).y(100f);

También podemos poner las animaciones en un XML en res/anim/, por ejemplo:
animacion.xml
<set android:ordering="sequentially">
   <set>
      <objectAnimator
         android:propertyName="x"
         android:duration="500"
         android:valueTo="400"
         android:valueType="intType"/>
      <objectAnimator
         android:propertyName="y"
         android:duration="500"
         android:valueTo="300"
         android:valueType="intType"/>
 </set>
      <objectAnimator
         android:propertyName="alpha"
         android:duration="500"
         android:valueTo="1f"/>
</set>


En el programa tendremos que poner:
AnimatorSet set = (AnimatorSet)
AnimatorInflater.loadAnimator(myContext,R.anim.animacion);
set.setTarget(myObject);
set.start();

Animaciones de vistas

Se puede utilizar el sistema de animaciones de vistas para realizar animaciones interpoladas de controles de vista.
Una animación de interpolación puede realizar una serie de transformaciones simples (posición, medida, rotación y transparencia) en el contenido de un objeto View. Por lo tanto, si por ejemplo tenemos un objeto TextView, se puede mover, girar, crecer o reducir la medida del texto. Si se tiene una imagen de fondo, la imagen de fondo será transformada juntamente con el texto. El paquete animation ofrece todas las clases que se utilizan en una animación de interpolación.
Una secuencia de instrucciones de animación define la animación de interpolación, definida por cualquier XML o código Java. Igual que con la definición de un diseño, se recomienda un archivo XML porque es mas facil de leer, reutilizable...
Las instrucciones de animaciones definen las transformaciones que se desean producir, cuando van a ocurrir y cuanto tiempo tienen que adoptar para la aplicación. Las transformacioens pueden ser secuenciales o simultanias, por ejemplo, puede hacer que el contenido de un TextView se mueva de izquierda a derecha y después girar 180 grados, o hacerlo de forma simultanea.
Cada transformación necesita un conjunto de parámetros específicos para esta transformación (medida inicial, angulo inicial, final del angulo, final de la medida final, etc.), y también un conjunto de parámetros comunes (por ejemplo, hora de inicio y de paro). Para hacer varias transformaciones que se sucedan simultaneamente, se les da la misma hora de inicio, pero para que sean secuenciales, hace falta calcular el tiempo de inicio más la durada de la transformación anterior.
El archivo de animación XML pertenece al res/anim/ directorio del projecto Android.
El archivo tiene que tener un elemento raiz, será único: <alpha>,<scale>,<translate>,<rotate>, elemento interpolador  o <set>, elemento que tiene grupos de elementos (que pueden incluir otro <set>). Por defecto, todas las instrucciones de animaciones se aplican simultaneamente. Para hacerlos se producen de forma secuencial, se tiene que especificar el startOffset atributo.
Por ejemplo:

set android:shareInterpolator="false">
   <scale
   android:interpolator="@android:anim/accelerate_decelerate_interpolator"

   android:fromXScale="1.0"
   android:toXScale="1.4"
   android:fromYScale="1.0"
   android:toYScale="0.6"
   android:pivotX="50%"
   android:pivotY="50%"
   android:fillAfter="false"
   android:duration="700" />
   <set android:interpolator="@android:anim/decelerate_interpolator">
      <scale
        android:fromXScale="1.4"
        android:toXScale="0.0"
        android:fromYScale="0.6"
        android:toYScale="0.0"
       android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="700"
        android:duration="400"
        android:fillBefore="false" />
      <rotate
        android:fromDegrees="0"
        android:toDegrees="-45"
        android:toYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="700"

        android:duration="400" />
   </set>
</set>


Con este XML guardado como salto.xml en res/anim del directorio del proyecto, el siguiente código hará referencia a él y aplicará a una ImageView el objeto de la disposición.
ImageView imatge = (ImageView) findViewById (R.id.imatge);
Animation a = AnimationUtils.loadAnimation (això, R.anim.salt);
imatge.startAnimation (a);

Animaciones de recursos draw

Android permite cargar una serie de recursos Drawable uno tras otro, para crear una animación. Esta es una animación tradicional en el sentido que se crea con una secuencia de imagenes diferentes, como el rollo de una película. La clase AnimationDrawable es la base para las animaciones Drawable.
El archivo XML de este tipo de animaciones pertenece al directorio res/drawable/ del proyecto de android. En este caso, las instrucciones estan en orden y la duración para cada cuadro de animación.
El archivo XML consiste en un elemento <animation-list> como el nodo raiz y la serie de nodos hijos <item> que definen cada uno un marco: un recurso dibujable para el marco y la durada para cada frame.
fondo.xml
<animation-list
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:oneshot="true">
   <item
      android:drawable="@drawable/rocket_thrust1"
      android:duration="200" />
   <item
      android:drawable="@drawable/rocket_thrust2"
      android:duration="200" />
   <item
      android:drawable="@drawable/rocket_thrust3"
      android:duration="200" />
</animation-list>

Código:
AnimationDrawable a;
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
   ImageView imatge = (ImageView) findViewById(R.id.imatge);
   imatge.setBackgroundResource(R.drawable.fons);
   a = (AnimationDrawable) imatge.getBackground();
}
public boolean onTouchEvent(MotionEvent event) {
   if (event.getAction() == MotionEvent.ACTION_DOWN) {
      a.start();
      return true;
   }
   return super.onTouchEvent(event);
}

4. Desarrolla una aplicación que muestre una animación en forma de secuencia repetitiva en la que un texto siga una forma de recuadro. Hazlo con programación Java y con código XML.

5. Crea una animación de una imagen que va rebotando dentro de un contenedor.

Soluciones (Cambiar el android manifest para las diferentes actividades).


PDF

Para mas detalles, consultad Android developers.




Utilización de librerias multimedia integradas Media Playback y Servicios

Media Playback

El framework multimedia de android incluye soporte para la reproducción de varios tipos de medios, de manera que se le puede integrar fácilmente audio, vídeo e imágenes en las aplicaciones.
Los recursos van en el directorio RAW.
El audio tiene más juego que el video... ¿Si se intenta hacer un streaming por bluetooth como marcas prioridad para el audio? Tenemos el AudioManager que permite manipular todo lo que afecta al tema de audio.

En ambos casos (audio o video) hay que poner permisos si queremos hacer streaming.
<uses-permission android:name="android.permission.INTERNET" />

Si la aplicación tiene que mantenerse en pantalla se puede usar MediaPlayer.setScreenOnWhilePlaying() o los métodos MediaPlayer.setWakeMode(), con sus permisos:
<uses-permission android:name="android.permission.WAKE_LOCK" />

La clase MediaPlayer permite obtener, decodificar y reproducir audio y video. Una URL internas, listas de audio, fotos... y URLs externas (streaming).

Los formatos soportados se pueden ver en:

Si queremos reproducir un fichero en local (RAW) tendremos que guardarlo en el directorio /res/raw:

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.audio1);
mediaPlayer.start();

Si queremos usar el tema del streaming, tendremos que poner:

String url = "http://........";
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // puede tardar en cargar en el buffer.
mediaPlayer.start();

El método prepare() no se puede llamar nunca desde el hilo de la IGU (Interficie Grafica de Usuario). Imaginate que haces una sopa de letra y quieres música de fondo, si lo haces directamente en la activity bloquearía la interficie hasta que se cargue el buffer, la solución es meterlo en un servicio.

Hay un método llamado prepareAsync() que crearía un servicio de forma automática. Hará falta un listener, que llamará un callback y se disparará cuando este cargado.
El MediaPlayer funciona como una máquina de estados.

http://cfile23.uf.tistory.com/original/191F6F184C1E1BBE07D17F

Una vez se ha utilizado un medio, se necesita liberar con el método release(), es importante que se tenga en cuenta que cuando el usuario cambia la orientación se  vuelve a crear un objeto MediaPlayer, porque se vuelve a llamar a onCreate(), por eso se necesita liberar los recursos.

media.release();
media=null;

Si no queremos este comportamiento podemos guardar el estado y gestionarlo de manera manual.
Haciendo que cuando pasa un cambio de horientación o el teclado se oculta, entonces ejecuta el método por defecto que detecta cambios de configuración (onConfigurationChanged()) y se disparará teniendolo puesto en la activity. El objeto newConfig tendrá la información que podrás preguntar el estado.
Podiendo mirar la horientación podremos hacer condicionales y permite detectar que se disparará cuando hay un cambio.
Después llamará al onCreate().

Por ejemplo, para hacer un cambio de horientación:


















Código:

<manifest package="es.com.blogspot.fmesasc.cambiohorientacion">

<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">

<activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:label="@string/app_name">

<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

</activity>

</application>

</manifest>


Como se puede ver, hemos añadido android:configChanges="orientation|keyboardHidden|screenSize" para que detecte la rotación de pantalla o la ocultación de teclado en este caso, para que esto funcione tendremos que sobreescribir una función:

package es.com.blogspot.fmesasc.cambiohorientacion;
import android.content.res.Configuration;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
        } else if (newConfig.orientation ==
                Configuration.ORIENTATION_PORTRAIT){
            Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
        }
    }
}


onConfigurationChanged únicamente funcionará si esta declarado en el manifest, de esta manera, podemos comprobar la nueva orientación y la comparamos para saber si es horizontal o vertical (Landscape o Portrait). De esta manera mostramos el toast del ejemplo inicial indicando el tipo de orientación.

Descargar.

Servicios

Los servicios son componentes de una aplicación que realizan operaciones de larga duración que no requieren la interacción de un usuario, o que ofrecen funcionalidades para otras aplicaciones. Normalmente envian correos, sincronizan datos o reproducen medios.
Igual que hay una activity en el manifest, tendremos que declarar también los servicios en el manifest. La comunicación es similar al sistema de comunicación que tienen actividades, los intents. Los servicios heredan de services o subclase de este. No tienen nunca interficie.
Cada servicio se declarará en el AndroidManifest.xml con <service>.
Los servicios se inician con:
Context.startService() y Context.bindService().
Los servicios se ejecutan como hilo principal del proceso. Eso implica que si consume muchos recursos se recomiende hacer uno nuevo.
La clase IntentService es una implementación estandard de Service que funciona como un hilo propio.
Entonces, un servicio no es un proceso separado. Se ejecuta en el mismo proceso que la aplicación. Tampoco es un hilo separado.
Los servicios se utilizan para hacer tareas en segundo plano, notificando cuando esta realizado. Se inicia con Context.startService(). Este concepto es muy similar al de activityResult.
Existe la posibilidad de exponer a otras aplicaciones parte de una aplicación en concreto. Se utiliza el método de clase Context.bindService().
Podemos especificar que el servicio este asociado a un otro proceso con la anotación de dos puntos (:). Los dos puntos indican que el proceso será privado a la aplicación, sino será global para las aplicaciones.
Por ejemplo:
<service
   android:name="WordService"
   android:process=":proces1"
   android:icon="@drawable/icon"
   android:label="@string/nom_servei"
   >
</service>


Otro ejemplo:
public class ServeiMP extends Service implements
MediaPlayer.OnPreparedListener {
    private static final ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mMediaPlayer = null;
     public int onStartCommand(Intent intent, int flags, int startId) {
     ...
     if (intent.getAction().equals(ACTION_PLAY)) {
     mMediaPlayer = ... // inicialització
     mMediaPlayer.setOnPreparedListener(this);
     mMediaPlayer.prepareAsync(); }
     }
     /** cridat quan MediaPlayer està llest */
     public void onPrepared(MediaPlayer player) {
     player.start();
     }
}

Será necesario controlar los errores que se producen de manera asíncrona.
En onStartCommand le pasamos un intent, con la pista de audio que queremos que suene, con el ACTION_PLAY tendremos que sabemos si esta sonando o no la música. Al pasarle el intent, este le envía la pista de audio que nosotros queremos reproducir. Una de lsa cosas a tener en cuenta que podemos tener errores, por lo que hay otra interfaz que se llama Media.Player.OnErrorListener, haciendo override en onError podremos configurarlo.

Puedes bajarte un ejemplo de un servicio que permite descargar:
Descargar.

public class Servei extends Service implements MediaPlayer.OnErrorListener{
   MediaPlayer mMediaPlayer;
   public void initMediaPlayer() {
      // inicia MediaPlayer
      mMediaPlayer.setOnErrorListener(this);
   }
 @Override
 public boolean onError(MediaPlayer mp, int what, int extra) {
      // The MediaPlayer esta en estado de error.
    }
}


Tendrá un boton que dice descargas, y un toast, mientras tanto podemos hacer lo que queremos, cuando este descargado, el servició terminará. Si le das otra vez el botón la descarga se vuelve a realizar.

Mira el código o descárgate el zip.

Primero tenemos el IntentService.
En el onCreate solo llamamos al layout.
En el onCLick hacemos un intent del servicio, creamos un mensaje que le pasamos un handler y este se encargará si esta descargado o no. Eso es porque el handle es asincrono, por lo tanto, no bloquea nada. Cuando reciba el mensaje se disparará el handleMessage, si el resultado esta bien saldrá correcto, solo cuando recibe.
En el intent le pasamos un mensaje y el mensajero, en el intent también le pasamos un setData, que se utiliza para obtener el nombre del fichero. El putExtra será precisamente para poder indicar el path para saber donde tiene que guardar.

El servicio tiene un entero, result, que si todo va bien le pondremos okey en vez de result_canceled. en el onHandleINtent, que es asincrono y obtenemos el urlpath y de esta manera ponemos el nombre del fichero y hacemo sun fichero output para guardar. sino lo borraremos.
La lectura la haremos con el inputStreamReader, en un principio a fluxEntrada y fos serán iguales. Técnicamente lo que hace es byte a byte escribirlos, cuando es -1 significa que hay que cerrar el archivo.

Ponemos la ruta, conexión, y el InputStreamReader va poniendo los bytes y los convierte en UNICODE. Si es pdf o algo hay que anular los readers que los convierten a UNICODE. Normalmente se llaman fis y fos.
Después tenemos un while que lee carácter a carácter y si no es igual a menos 1 escribe (Para un pdf necesitaremos eliminarlo).

Cuando acaba le ponemos result_ok y en el .java veremos que ha devuelto RESULT_OK. Si hay problemas hay un catch, y el finally se ejecuta porque finaliza correctamente o hay un fallo.

Cuando ya esta, cogemos el mensaje y le ponemos como argumento 1 que todo ha ido correctamente y como objeto le ponemos la ruta del objecto.
Si hay algún problema te envia la respuesta.

Un servicio puede estar encendido mientras la actividad esta en pause, pero la CPU funcionaria, el wifi no, entonces podemos programarle que queremos que haga. Para desactivarlo o cambiarlo tenemos que poner wifiLock.acquire() o wifiLock.release(); de esta manera controlamos si funciona o no. Se pondria setWakeMode para indicar que tiene que hacer.

Si queremos también se puede mostrar una notificación. Se programa con Notification, para hacerlo se tienen que enviar mediante un intent especial, con PendingIntent. Allí podremos poner la información.

Actividades:
  1. Desarrolla una aplicación para android que reproduzca una pista de música guardada en los recursos del dispositivo. La aplicación tiene que tener botones para parar, pausar y iniciar la pista de música. Tiene que mostrar el tiempo de reproducción.
    Solución 1.
    Solución profe.
  2. A partir del ejercicio anterior, crea un servicio en primer plano que realice la reproducción de música mostrando con una notificación de información al usuario en la barra de estado.
    Solución.


Apuntes.
Ejercicios.

Para más información, consultad:
http://developer.android.com/guide/topics/manifest/manifest-intro.html

dimarts, 15 de desembre del 2015

Instalar android studio via PPA

Android studio, la propia IDE de Google para el desarrollo de Android, una buena alternativa a Eclpise con el plugin ADT. Android studio se puede instalar desde el código fuente, pero a continuación veremos como instalarlo en Ubuntu a través de un PPA.
Recomiendo instalar Oracle JDK.

Instalar android studio en Ubuntu, de manera oficial.
Se puede instalar android studio desde Ubuntu Make. Para realizar la instalación tendremos que instalar ubuntu make:
sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make
sudo apt-get update 
sudo apt-get install ubuntu-make
Finalmente para instalar android studio lo pondremos de esta forma:
umake android
En el caso de querer desinstalarlo deberemos poner:
umake android --remove
 
 
Instalar android studio en Ubuntu, de manera no oficial.

tenemos un PPA que se puede utilizar para instalar fácilmente Android Estudio en Ubuntu 14.04, 13.10, Linux Mint y otras distribuciones basadas en Ubuntu. Ten en cuenta que se descargará alrededor de 650 MB de datos.
Utilizaremos los siguientes comandos:
sudo apt-add-repository ppa:paolorotolo/android-studio
sudo apt-get update
sudo apt-get install android-studio

Para desinstalar:
sudo apt-get remove android-studio
sudo ppa-purge ppa:paolorotolo/android-studio

En el caso de no tener instalado purge, se puede instalar mediante el comando:
sudo apt-get install ppa-purge


dilluns, 7 de desembre del 2015

Sopa de lletres Android

PRÀCTICA ANDROID M08UF1
1. Una primera versió del joc tindrà una activitat inicial on mostra una pantalla de benvinguda, i es mostren les puntuacions en la llista, i amb un botó per jugar.
En aquesta versió, es mostra la sopa de lletres i l'usuari ha d'internar resoldre'l. Les lletres estan emmagatzemades en una matriu bidimensional. En cap cas es tracta d'implementar un algorisme de resolució de sopa de lletres ni de generació de les mateixes.
Consisteix doncs en una matriu o col·lecció de caràcters definides com a constants. Visualment s'indica les lletres seleccionades i les paraules trobades. El temps no intervé i no hi ha cap algorisme de puntuació. (4 punts)

Pantalla inicial:

En un fitxer xml esta declarat el disseny, al codi només trobem el codi del que ha de fer quan es selecciona al boto, o a opcions… Enmig es poden veure les puntuacions que estan en una base de dades, en aquest exercici però, no sortiria cap degut  que no hem implementat cap algoritme per a la resolució amb puntuacions.
Aquí podem observar la creació en el codi:
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_inici);
  Button Juga= (Button) findViewById(R.id.bJuga);
  listPuntuacions = (ListView) findViewById(R.id.listPuntuacions);
  Juga.setOnClickListener(
          new OnClickListener() {
              public void onClick(View v) {
                  Intent intent = new Intent(inici.this, Sopa_Lletres.class);
                  startActivity(intent);
              }
          }
  );
}







JOC

Screenshot_2015-11-29-16-29-46.png


L’algorisme que afecta a la puntuació esta implementat, però si igualem els punts a 0 es com si no estigues, això esta fet per a que sigui mes senzill demostrar que funciona sense puntuació.
ONCREATE
chronometer = (Chronometer) findViewById(R.id.chronometer);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.stop();
grid = (GridLayout) findViewById(R.id.layout);
grid.setColumnCount(columna);
grid.setRowCount(fila);
paraulesTrobades=(GridLayout) findViewById(R.id.ParaulesTrobades);
vDefineixArrayList();
vFicaParaules(Paraules);
vCrear(texts);
Puntuacion = (TextView) findViewById(R.id.Puntuacio);
//eliminar bd
PuntsH=0;
PuntsV=0;
PuntsR=0;

public void vDefineixArrayList()
Tenim vDefinexArrayList que afegeix a la llista Paraules les paraules que volem, d’aquesta manera podem continuar amb la següent funció:

public void vFicaParaules(ArrayList<String>)
La funció vFicaParaules requereix d’un ArrayList, aquesta funció fica les paraules que s’han d’introduïr en una matriu, en aquest cas serà l’ArrayList de Paraules.

public void vCrear(TextView[][])
Finalment copiem les paraules ficades en el textView que trobem al grid, d’aquesta manera si no hem posat cap lletra en un punt posem una al atzar.
Els punts els igualem a 0, en el codi ja es troba implementat d’una activitat posterior per tant desprès serà explicat el funcionament, igualant a 0 no funcionarà.

2. Es millora el joc externalitzant les paraules de la sopa de lletres en un descriptor de cadenes XML.
D'aquesta manera es poden modificar les paraules amb més facilitat. (1 punts)
Afegim al OnCreate eliminant vDefineixArrayList():
String [] items = getResources().getStringArray(R.array.items);
for(String paraula : items){
  Paraules.add(paraula);
}

Screenshot_2015-11-29-16-31-48.png
Paraules XML:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string-array name="items">
      <item>Francisco</item>
      <item>Marc</item>
      <item>Jenny</item>
      <item>Calomarde</item>
      <item>Montuliu</item>
      <item>Sergi</item>
      <item>Laura</item>
      <item>Collados</item>
  </string-array>
</resources>

3. S'incorpora una lògica de puntuació i es desa en la base de dades SQLite. Aquesta versió desa les puntuacions. En començar el joc apareix una pantalla (Activity) mostrant totes les puntuacions, i la data en la qual s'ha obtingut. (2 punts)

vGuardarEnDB()
Aquesta funció fa que es desi a la base de dades SQLite les puntuacions i la data.


4. En aquesta versió, el lloc obté els mots de l'agenda de contactes de l'usuari. (1,5 punts)

public ArrayList<String> ObtenirContactes()

Agafa l’arraylist de la llista de contactes.

Screenshot_2015-11-29-16-35-22.png

5. S'incorpora un botó Ajuda que explica el funcionament del joc. Aquesta ajuda està en fitxers HTML dins del mateix empaquetat i es mostra amb la classe WebView. Aquesta ajuda es troba en una barra d'acció i s'obre una nova pantalla amb l'ajuda (1,5 punt)

private void obrirWebView()

Obre el WebView en un dialog.

Screenshot_2015-11-29-16-44-50.png

Screenshot_2015-11-29-16-44-55.png