OBJETOS VIEW. Cristobal Raya Giner. Programació de Dispositius Mòbils (PRDM)

Documentos relacionados
Ejercicio 18. Configuración de Widgets en Android. Android Con Java. Ejercicio 18. Configuración de Widgets en Android. Curso de Android con Java

Android y Recursos. Android R.java (fichero)

Android. Cristobal Raya Giner. Programació de Dispositius Mòbils (PDMO)

Manejadores en Android LSUB, GYSC, URJC

Servicios Basados en Localización (LBS) Tema 6 Desarrollo de aplicaciones en Android

Android TAG y el principio DRY

ALMACENAMIENTOS DE DATOS EN ANDROID CON SQLITE

Android avanzado. Sesión 5: Notificaciones. Experto en Desarrollo de Aplicaciones para Dispositivos Móviles

Android Manejo de Eventos. Rogelio Ferreira Escutia

Ejercicio 3. Manejo de la Vista y Eventos en Android Ejercicio 3 Curso de Android con Java Derechos Res Dere e c rvados hos Res Gl e obal rva

Crear listas personalizadas en Android

Importar y exportar aplicaciones Para importar proyectos de Android a Android studio

Activities/Intents en Android LSUB, GSYC, URJC

Android y Java para Dispositivos Móviles

Interfaz de usuario Layout Vistas Adaptadores Eventos de interacción Estilos y temas

Layouts en Android LSUB, GSYC, URJC

Desarrollo de Aplicaciones para Android

Crear un Splash-Screen

Cursos de orientación profesional

INTRODUCCIÓN A LA PROGRAMACIÓN ANDROID. Duración en horas: 60 OBJETIVOS DEL CURSO

Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles. Plataforma Android. Sesión 1: introducción a Android

Ejercicio 4. Manejo de Layouts en Android. Android Con Java. Ejercicio 4. Manejo de Layouts en Android. Curso de Android con Java

Curso Android. ADT Bundle. Android Developer Tools. Entorno de trabajo Toolbar principal SDK Manager. Emulador de Android. Crear proyecto Android

UNA APLICACIÓN DE EJEMPLO: MIS LUGARES

GUIA DE LABORATORIO N 1

Desarrollo de un reproductor mp3

Curso de programación en Android. 19/Junio/2012 Ramón Alcarria Augusto Morales

INICIACIÓN A LA PROGRAMACIÓN PARA ANDROID

Practica. Material Design. lunes 10 de octubre de 16

Desarrollo de Aplicaciones para Android

SOLUCIÓN AL LABORATORIO DEL DÍA SÁBADO 29 DE JUNIO DE 2013

Android UI. Darío Fernando Chamorro Vela Junio 2012

Ejercicios - Introducción a Android

Introducción a la programación Android. Programación III - 6to año Escuela Técnica ORT Leo Lob -

Tareas en segundo plano AsyncTask Thread

CODIGO PROYECTO: AppPixelproServicioWeb Proyecto Android - Servicio Web

Ejercicios - AppWidgets

Ejercicios - Menús, listas y barras de progreso

Notificaciones y AppWidgets - Ejercicios

Programación Android. Alejandro Alcalde. elbauldelprogramador.com

INTRODUCCIÓN A LA PROGRAMACIÓN ANDROID

Android Creación de una aplicación sencilla: Forwarding - Página 1 -

ANDROID BÁSICO - E-LEARNING - EN LÍNEA

Sesión 4. Interfaz de Usuario en Android. Ing. Edwin Andrés Cubillos Vega Msc. Company LOGO

Taller Desarrollo. Tecnólogo Informática - 6to Semestre Montevideo

Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles. Plataforma Android

PRACTICAS DE ANDROID 12 - Lanzar un segundo "Activity" y pasar parámetros Problema:

Giovanny Fernando Vanegas Mendez Docente tutor de la UDFJC: Jonh Freddy Parra Peña

Gestión de formularios: Manual de usuario

Antes que nada se debe crear un proyecto, en este ejemplo se llama KaaxTik.

Índice. Prólogo Capítulo I. Introducción Capítulo II. Conceptos...19

Ejercicios - Introducción al diseño de interfaces gráficas en Android

Desarrollo de apps para móviles Android. Conceptos básicos de las aplicaciones Android

100x70 - PNG 24x24 - PNG

Unidad 3. PrimerProyecto. Nuestra primera aplicacio n Android

Archivos y Carpetas de un proyecto Android

Tutorial brújula controlada por voz

Temas. CopyRight emmmnmmma - All rights reserved 2

Servicios de la plataforma Android

Manual Mca006. Manual Mca006 CURSO ANDROID DESARROLLO de APLICACIONES MÓVILES, 24 horas

Unidad III.- Desarrollo de la interfaz de usuario. Diseño de layouts en Android.

Ejercicios - Intents y navegación entre actividades

Interfaz de usuario. Índice

Interfaces de usuario [Desarrollo de aplicaciones para Android]

Introducción a la programación de aplicaciones con Android. Fernando Pérez Costoya

Desarrollo de Aplicaciones para Android

Introducción a la programación de aplicaciones con Android. Fernando Pérez Costoya

Intefaz de usuario - Ejercicios

ANDseries Autor: Miró Monleón, Edgar

Manual de Usuario para. Sistema de Tickets de Soporte DOC

Android y Java para Dispositivos Móviles

BEGINNERS CURSO TALLER: años. INICIO: 15 DE SETIEMBRE Viernes de 19:00 a 22:00h y sábados 09:00 a 12:00h

Tema 2: Diseño de servicios para móviles

ANDROID INTERMEDIO - E-LEARNING - EN LÍNEA

Que es un Android Intent?

Unidad 2. Crear una Presentación (I)

Unidad 5. Interfaz de Usuario

MS EXCHANGE 2013 MANUAL DEL USUARIO...

Ficheros y acceso a datos - Ejercicios

Patricio Olivares. 25 de abril de 2017

Desarrollo de Aplicaciones para Android

MS EXCHANGE 2013 MANUAL DEL USUARIO...

Teoría Intents Fecha 2016/04/12

Android 7 Principios del desarrollo de aplicaciones Java

Aurelio López Ovando Botón de pánico (App para Android)

Manual Básico Android Studio

INTRODUCCIÓN.

Ministerio de Economía, Industria y Comercio (MEIC) -Trámites Costa Rica- Manual de usuario: Administrador Institucional. Cliente

Apunte de Gráficos Microsoft Office Excel Gráficos.

OPENOFFICE IMPRESS. Uso básico Basic usage

Servicios Web Android

Práctica 3. Android. Tutorial appfotovoz

SESIÓN 5 MANEJO DE BASES DE DATOS SQLITE

UNIDAD 6 TEMA 4: OFIMÁTICA AVANZADA. CLASE 05: Combinar correspondencia.

1 Menú lateral. 3.- Estas imágenes deber ser copiadas y pegadas en la carpeta drawable del proyecto

Practica 10. Layouts. martes 25 de octubre de 16

Universitat Oberta de Catalunya. Cuaderno de Viaje. Memoria

En nuestra actividad principal, creamos el objeto vista previa. Este objeto se creará el objeto cámara y volver a la actividad CameraDemo.

Transcripción:

OBJETOS VIEW Cristobal Raya Giner Programació de Dispositius Mòbils (PRDM)

Botón Hora Actual activity_main.xml Crearemos un botón que al pulsar actualizará la hora. Primero creamos un Layout con un botón que ocupe toda la pantalla dentro de un RelativeLayout (u otro Layout): <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" android:paddingbottom="@dimen/activity_vertical_margin tools:context=".mainactivity"> <Button android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="new Button" android:id="@+id/button" android:layout_alignparenttop="true" android:layout_alignparentleft="true" android:layout_alignparentstart="true" /> </RelativeLayout>

Botón Hora Actual MainActivity.java Añadimos el código correspondiente al fichero Kotlin.kt de la actividad principal. import android.support.v7.app.appcompatactivity import android.os.bundle import android.view.view import android.widget.button import java.util.* class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val boton:button = findviewbyid(r.id.button) boton.setonclicklistener(view.onclicklistener { boton.settext(calendar.getinstance().time.tostring()) )

Formato de la hora Realizamos varios cambios: Formateamos la hora para que se vea como: Dimecres 11/Setembre/2013, 17:14:00 Creamos una función que llamaremos al pulsar el botón Definimos el botón indicando que más tarde se inicializará (lateinit var boton:button) Para asignar el texto, en Kotlin se puede utilizar.text= x en lugar de.settext( x ) import android.support.v7.app.appcompatactivity import android.os.bundle import android.view.view import android.widget.button import java.text.simpledateformat import java.util.* class MainActivity : AppCompatActivity() { lateinit var boton:button override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) boton=findviewbyid(r.id.button) boton.setonclicklistener(view.onclicklistener { actualitzatemps() ) public fun actualitzatemps(){ boton.text=simpledateformat("eeee dd/mm/yyyy, HH:mm:ss").format(Calendar.getInstance().time) http://developer.android.com/reference/java/text/simpledateformat.html

Dos botones, dos Listeners Primero creamos un Layout con un texto y 2 botones: import android.support.v7.app.appcompatactivity import android.os.bundle import android.view.view import android.widget.button import android.widget.textview class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var texte:textview =findviewbyid(r.id.textview) val btn1:button=findviewbyid(r.id.button) val btn2:button=findviewbyid(r.id.button2) btn1.setonclicklistener(view.onclicklistener { texte.text="has polsat el primer botó" ) btn2.setonclicklistener(view.onclicklistener { texte.text= "Has polsat el segon botó" )

Dos Botones, un Listener Con el mismo layout, utilizamos solo un OnClickListener : class MainActivity : AppCompatActivity() { lateinit var texte:textview lateinit var btn1:button lateinit var btn2:button override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) texte =findviewbyid(r.id.textview) btn1 =findviewbyid(r.id.button) btn2 =findviewbyid(r.id.button2) btn1.setonclicklistener(escoltador) btn2.setonclicklistener(escoltador) val Escoltador: View.OnClickListener = object :View.OnClickListener{ override fun onclick(v: View?) { if ((v as Button).getId() === btn1.getid()) { texte.settext("has polsat el primer botó") else if (v!!.getid() === findviewbyid<view>(r.id.button2).getid()) { texte.settext("has polsat el segon botó") Los dos signos exclamación de v!!.getid() son porque se asume que v no será nulo. Sino también se podría comprobar previamente si no es nulo antes de realizar la comparación. else if (v!= null) { if (v.getid() === findviewbyid<view>(r.id.button2).getid()) { texte.settext("has polsat el segon botó")

Dos Botones Listener en Activity Con el mismo layout, ahora se implementa OnClickListener en la misma actividad: class MainActivity : AppCompatActivity(), View.OnClickListener { lateinit var texte: TextView lateinit var btn1: Button lateinit var btn2: Button override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) texte =findviewbyid(r.id.textview) btn1 =findviewbyid(r.id.button) btn2 =findviewbyid(r.id.button2) btn1.setonclicklistener(this) btn2.setonclicklistener(this) override fun onclick(v: View?) { if ((v as Button).id == btn1.getid()) { texte.settext("has polsat el primer botó") else if (v!!.id == findviewbyid<view>(r.id.button2).id) { texte.settext("has polsat el segon botó")

Alternativa Botones Existe otra alternativa a la pulsación de los botones, llamando a una función para un objeto View, mediante la propiedad On Click del botón en el layout : import android.support.v7.app.appcompatactivity import android.os.bundle import android.view.view import android.widget.textview class MainActivity : AppCompatActivity() { lateinit var texte:textview override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) texte = findviewbyid(r.id.textview) fun boto_pulsat(view : View){ texte.text="botó pulsat"

EditText Crearem un layout amb almenys 3 camps de entrada de text del tipus EditText, un de tipus TextView, i un botó. L activitat ens permetrà introduir per separat el nom i els dos cognoms, i al polsar el botó mostrarà el nom complert.

EditText import android.support.v7.app.appcompatactivity import android.os.bundle import android.view.view import android.widget.button import android.widget.edittext import android.widget.textview class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val nom: EditText =findviewbyid(r.id.editnom) val cognom1:edittext = findviewbyid(r.id.editcognom1) val cognom2:edittext = findviewbyid(r.id.editcognom2) val nomcomplert:textview = findviewbyid(r.id.nomcomplert) val btn:button = findviewbyid(r.id.button) btn.setonclicklistener(view.onclicklistener { var nomjunt:string = nom.text.tostring()+" "+cognom1.text.tostring()+" "+cognom2.text.tostring() nomcomplert.text=nomjunt ) Proveu canviar el paràmetre InputType de algún EditText, per exemple a textpassword

CheckBox Creem un layout només amb un widget Checkbox, i creem un Check Listener import android.support.v7.app.appcompatactivity import android.os.bundle import android.widget.checkbox import android.widget.compoundbutton class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val chkb:checkbox = findviewbyid(r.id.checkbox) chkb.setoncheckedchangelistener(object : CompoundButton.OnCheckedChangeListener{ override fun oncheckedchanged(buttonview: CompoundButton?, ischecked: Boolean) { if (ischecked){ chkb.text="activat" else { chkb.text="desactivat" )

CheckBox Creem un layout només amb un widget Checkbox i fem el mateix però el Listener és la pròpia activitat. import android.support.v7.app.appcompatactivity import android.os.bundle import android.widget.checkbox import android.widget.compoundbutton class MainActivity : AppCompatActivity(), CompoundButton.OnCheckedChangeListener { lateinit var cb:checkbox override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) cb = findviewbyid(r.id.checkbox) cb.setoncheckedchangelistener(this) override fun oncheckedchanged(buttonview: CompoundButton?, ischecked: Boolean) { if (ischecked){ cb.text = "CheckBox Activado" else { cb.text = "CheckBox Desactivado"

RadioButton Creamos un layout solo con un widget RadioButton import android.support.v7.app.appcompatactivity import android.os.bundle import android.widget.compoundbutton import android.widget.radiobutton class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val rb:radiobutton = findviewbyid(r.id.radiobutton) rb.setoncheckedchangelistener(object : CompoundButton.OnCheckedChangeListener{ override fun oncheckedchanged(buttonview: CompoundButton?, ischecked: Boolean) { if (ischecked){ rb.text="activat" else { rb.text="desactivat" ) Un RadioButton solo se puede desactivar mediante código: rb.ischecked=false

Radio Group Creamos un LinearLayout vertical solo con un Container RadioGroup incluyendo 4 RadioButtons, y un TextView. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val radio0:radiobutton = findviewbyid(r.id.radio0) val radio1:radiobutton = findviewbyid(r.id.radio1) val radio2:radiobutton = findviewbyid(r.id.radio2) val radio3:radiobutton = findviewbyid(r.id.radio3) val textpolsat:textview = findviewbyid(r.id.textview) radio1.ischecked = true textpolsat.text="inicialment polsat el segon" val radiogroup:radiogroup = findviewbyid(r.id.radiogroup) radiogroup.setoncheckedchangelistener { group, checkedid -> when (checkedid) { -1 -> { R.id.radio0 -> { textpolsat.text="polsat primer" R.id.radio1 -> { textpolsat.text="polsat segon" R.id.radio2 -> { textpolsat.text="polsat tercer" R.id.radio3 -> { textpolsat.text="polsat quart"

Radio Group Modifica las acciones del switch para modificar parámetros de colocación del RadioGroup. radiogroup.setoncheckedchangelistener { group, checkedid -> when (checkedid) { -1 -> { R.id.radio0 -> { textpolsat.text="polsat primer" radiogroup.orientation=linearlayout.horizontal R.id.radio1 -> { textpolsat.text="polsat segon" radiogroup.orientation=linearlayout.vertical R.id.radio2 -> { textpolsat.text="polsat tercer" radiogroup.gravity= Gravity.CENTER_HORIZONTAL R.id.radio3 -> { textpolsat.text="polsat quart" radiogroup.gravity=gravity.right Para ver el efecto del parámetro.gravity, el ancho de los RadioButton se han de ajustar al contenido: <RadioButton android:id="@+id/radio0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="primer" />

ListView Creamos un Layout con un TextView y un ListView class MainActivity : AppCompatActivity() { var llista = arrayof("siop", "SIAC", "DIAP", "MCME", "XACO", "PRDM", "SINS", "ROVI", "AUDI") lateinit var seleccio: TextView lateinit var vistallistat: ListView override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) seleccio =findviewbyid(r.id.seleccio) vistallistat = findviewbyid(r.id.llistat) vistallistat.choicemode=listview.choice_mode_single vistallistat.adapter = ArrayAdapter<String> (this, Forma alternativa de indicar singlechoice al choicemode en el código en lugar del layout android.r.layout.simple_list_item_single_choice,llista) vistallistat.onitemclicklistener = AdapterView.OnItemClickListener { arg0, arg1, pos, arg3 -> seleccio.text = "Has seleccionat: " + llista[pos] + " pos:" + pos

ListView con ListActivity (1) Creamos un Layout con un TextView y un ListView (Containers) <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/linearlayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingbottom="@dimen/activity_vertical_margin" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" tools:context=".mainactivity" > <TextView android:id="@+id/seleccio" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:choicemode="singlechoice" > </ListView> Importante!!! El id ha de ser list que ya está definido en Android @android:id/list NO @+id/list Para que quede marcada la selección se ha de indicar singlechoice al choicemode

ListView con ListActivity (2) import android.app.listactivity import android.support.v7.app.appcompatactivity import android.os.bundle import android.view.view import android.widget.arrayadapter import android.widget.listview import android.widget.textview class MainActivity : ListActivity() { Ampliación de ListActivity internal var llista = arrayof("siop", "SIAC", "DIAP", "MCME", "XACO", "PRDM", "SINS", "ROVI", "ECUS") lateinit var seleccio:textview override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) seleccio=findviewbyid(r.id.seleccio) listadapter = ArrayAdapter(this, android.r.layout.simple_list_item_single_choice, llista) override fun onlistitemclick(l: ListView, v: View, position: Int, id: Long) { super.onlistitemclick(l, v, position, id) seleccio.text = llista[position]

ListView en recursos (1) Como alternativa a la definición de la lista, podemos crearla en los recursos en lugar del código. Aprovechando el programa anterior, primero abrimos el fichero strings.xml de la carpeta /res/values, y añadimos un string-array y le ponemos el nombre y añadimos los elementos de la lista, en los cuales podemos añadir algunos parámetros con un nombre de referencia: <resources> <string name="app_name">actlist_recursos</string> <string name="hello_world">hello world!</string> <string name="action_settings">settings</string> <string-array name="assignatures"> <item >SIOP</item> <item >SIAC</item> <item >DIAP</item> <item >MCME</item> <item >XACO</item> <item name="prd Mobils">PRDM</item> <item >SINS</item> <item >ROVI</item> <item >ECUS</item> </string-array> </resources>

ListView en recursos (2) En el código, creamos el array de String y utilitzamos resources.getstringarray para asignar los datos del array: class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var llista:array<string> = resources.getstringarray(r.array.assignatures) val vistallistat: ListView=findViewById(R.id.llistat) vistallistat.choicemode=listview.choice_mode_single val seleccio:textview = findviewbyid(r.id.seleccio) vistallistat.setadapter(arrayadapter<string>(this, android.r.layout.simple_list_item_single_choice, llista)) vistallistat.setonitemclicklistener(object : AdapterView.OnItemClickListener { override fun onitemclick(arg0: AdapterView<*>, arg1: View, arg2: Int, arg3: Long) { seleccio.settext("has seleccionat: " + llista[arg2] + " pos:" + arg2) ) Se asigna dentro del método oncreate, ya que no se puede hacer una llamada a ningún método (Resources) en la definición de la clase, sino dentro de un mètode. Respecto al ejemplo anterior se ha utilizado una alternativa para la definición del adaptador y el Listener.

Lista desplegable Spinner (1) Creamos un Layout con un TextView y un Spinner <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/linearlayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingbottom="@dimen/activity_vertical_margin" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" tools:context=".mainactivity" > <TextView android:id="@+id/textview1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <Spinner android:id="@+id/spinner1" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>

Código: Lista desplegable Spinner (2) class MainActivity : AppCompatActivity() { var llista = arrayof("siop", "SIAC", "DIAP", "MCME", "XACO", "PRDM", "SINS", "ROVI", "AUDI") override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val seleccio:textview = findviewbyid(r.id.textview1) val spin:spinner=findviewbyid(r.id.spinner1) var adaptallista: ArrayAdapter<String> = ArrayAdapter<String> (this,android.r.layout.simple_spinner_item,llista) // adaptallista.setdropdownviewresource(android.r.layout.simple_spinner_dropdown_item) spin.adapter=adaptallista spin.onitemselectedlistener=object:adapterview.onitemselectedlistener{ override fun onnothingselected(parent: AdapterView<*>?) { seleccio.text="res seleccionat" override fun onitemselected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { seleccio.text=llista[position] Después de probar el código, añadir esta línea y probar el efecto

TableLayout Un TableLayout, nos permite crear un Layout en forma de Tabla, añadiendo filas con TableRow, y en cada fila podemos añadir los widgets que queramos, creando las columnas de la tabla. Se ha de tener en cuenta que si no se indican medidas, las filas y columnas se ajustan a la medida del widget más grande de la fila o columna.

TableLayout Un TableLayout sirve per a crear tablas con filas y columnas. Permite crear celdas que ocupen más de una columna o fila. <?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:stretchcolumns="*" android:background="#000000"> <TableRow android:layout_margin="2dp" android:background="#ffffff"> <TextView android:text="cel la 1.1" /> <TextView android:text="cel la 1.2" /> <TextView android:text="cel la 1.3" /> </TableRow> <TableRow android:layout_margin="2dp" > <TextView android:background="#ffffff" android:layout_margin="2dp" android:text="cel la 2.1" /> <TextView android:background="#ffffff" android:layout_margin="2dp" android:text="cel la 2.2" /> <TextView android:background="#ffffff" android:layout_margin="2dp" android:text="cel la 2.3" /> </TableRow> <TableRow > <TextView android:layout_margin="2dp" android:layout_span="2" android:background="#ffffff" android:gravity="center_horizontal" android:text="cel la 3.1" /> <TextView android:layout_margin="2dp" android:background="#ffffff" android:text="cel la 3.2" /> </TableRow> </TableLayout>

FrameLayout Un FrameLayout apila todos los controles o widgets al vértice superior izquierda del contenedor FrameLayout, uno encima del otro. En el ejemplo ponemos un botón y un texto en un FrameLayout, y hacemos que al pulsar el botón aparezca el texto y al revés. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val boto:button = findviewbyid(r.id.button1) val text:textview = findviewbyid(r.id.textview1) boto.setonclicklistener(view.onclicklistener { text.visibility=view.visible boto.visibility=view.invisible ) text.setonclicklistener(view.onclicklistener { text.visibility=view.invisible boto.visibility=view.visible )

Imágenes Para poder utilizar imágenes, estas han de estar en la carpeta /res/drawable del proyecto de Android. Si no existiera la carpeta, se crea la carpeta pulsando el botón derecho en la carpeta /res, y seleccionando New Directory. Para añadir la imagen, podemos buscar la imagen a añadir en las carpetas, pulsando el botón derecho sobre la imagen y seleccionar Copiar. Después en el árbol del proyecto en Android Studio, pulsamos el botón derecho sobre la carpeta /drawable, y seleccionamos Paste. Las imágenes han de estar en formato PNG, JPG o GIF, y solo pueden contener caracteres de a-z, 0-9 y _. No podemos tener dos imágenes con el mismo nombre, aunque sean diferente formato. Esto es debido a que una vez están las imágenes en la carpeta del proyecto, se asigna automáticamente el recurso @drawable/nombre_imagen para acceder a ellas, y no se tiene en cuenta la extensión del fichero.

ImageView Creamos una aplicación con dos botones que al pulsar cambie la imagen de un ImageView. Insertar dos imágenes en la carpeta drawable, y añadir al layout una vista ImageView. Después de añadir el ImageView, en la propietat src aparecen todos el recursos y se ha de seleccionar la imagen deseada del conjunto drawable. La imatge seleccionada els mostra: <ImageView android:id="@+id/imageview1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparenttop="true" android:layout_centerhorizontal="true" android:src="@drawable/llunatics" /> Per a modificar la imatge en el codi, utilitzem el mètode.setimageresource: var imatge : ImageView = findviewbyid(r.id.imageview1) imatge.setimageresource(r.drawable.llunatics)

ImageView Creamos un layout con un TextView, los dos Buttons, y un ImageView.

ImageView El código: class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var imatge : ImageView = findviewbyid(r.id.imageview1) var nom : TextView = findviewbyid(r.id.textview1) var btn1 : Button = findviewbyid(r.id.button1) var btn2 : Button = findviewbyid(r.id.button2) btn1.setonclicklistener(view.onclicklistener { imatge.setimageresource(r.drawable.llunatics) nom.text="imatge Llunatics UPC" ) btn2.setonclicklistener(view.onclicklistener { imatge.setimageresource(r.drawable.logos) nom.text="imatge Logos" )

Distribución de objetos Cuando se diseña un layout y se distribuyen los objetos, normalmente se ajustan a la medida de la pantalla que utilicemos. Si se cambia de medida de pantalla, los objetos quedan desajustados y no mantienen el diseño inicial. <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignparenttop="true" android:layout_alignparentleft="true" android:layout_alignparentstart="true"> <Button android:text="button 1" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button" /> <Button android:text="button 2" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button2" /> <Button android:text="button 3" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button3" /> </LinearLayout> Nexus 4 (4.7 ) Nexus 10 (10.1 )

Distribución de objetos Si al layout le indicamos la suma total de las partes en que se distribuirán los objetos mediante la propiedad weightsum, a cada objeto le indicaremos en la propiedad layout_weight, cuantas partes del total del layout ocupará, y de esta forma se distribuirán según las proporciones indicadas independientemente de la mdedida de la pantalla. <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignparenttop="true" android:layout_alignparentleft="true" android:layout_alignparentstart="true" android:weightsum="6"> 1 <Button android:text="button 1" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button" android:layout_weight="1" /> <Button android:text="button 2" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button2" android:layout_weight="2" /> 2 3 1+2+3=6 <Button android:text="button 3" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button3" android:layout_weight="3" /> Nexus 4 (4.7 ) Nexus 10 (10.1 )

Problemas al girar la pantalla Al girar la pantalla, la función OnCreate() vuelve a invocarse y la aplicación se reinicia. Esto provoca, entre otras cosas, que se puedan perder datos o que una conexión con un dispositivo Bluetooth finalice. Para a evitarlo se puede añadir al fichero AndroidManifest.xml un pequeño código para indicar que actividades queremos que no se reinicien y cuando. Se añade al tag de la actividad el atributo android:configchanges, indicando cuando no se ha de reiniciar la activitat. En el cas de girar la pantalla, también cambian las medidas y se añade android:configchanges= screensize orientation Como ejemplo, el código quedaría: <activity android:name= edu.epsevg.prdm.mainactivity" android:configchanges="screensize orientation"> Ara ya no se reiniciará la aplicación al girar la pantalla. Más completo: <activity android:name=".mainactivity" android:configchanges="keyboard keyboardhidden orientation screenlayout uimode screensize smallestscreensize">

INTENTS Llamada a otras actividades o aplicaciones Cristobal Raya Giner Programació de Dispositius Mòbils (PRDM)

Elementos principales Hay varios elementos importantes a tener en cuenta al desarrollar aplicaciones en Android Activity (Actividades): Son los bloques básicos de una aplicación, que suelen representar las pantallas de interfaz de usuario (UI) Intent (Intents): Representa la intención de llamar a otra aplicación, de la cual se puede recibir una respuesta. Por ejemplo, visualizar una página web con el navegador. Service (Serveis): Es un proceso que se ejecuta en segundo plano, sin necesidad de ninguna interacción con el usuario. Ex: servidor Web Content Providers (Proveedores de Contenido): Proveen el acceso para la compartición de datos para las aplicaciones. Ex: Agenda de Contactos Broadcast Receiver: Detecta i reacciona a mensajes o evento globales del sistema. Ex. Batería baja

Llamada a nueva actividad (1) Creamos un nuevo proyecto con una actividad, y añadimos una nueva actividad seleccionando sobre New Activity Empty Activity. Se creará automáticamente una nueva Actividad con el correspondiente código y un layout, y se añadirá al proyecto. Hay que dejar desactivada la opción Launcher Activity, ya que la llamaremos desde la actividad principal

Llamada a nueva actividad (2) Creamos el código de la actividad principal, añadiendo un botón al layout, y creando un nuevo Intent class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val boton:button = findviewbyid(r.id.button) boton.setonclicklistener(view.onclicklistener { obrir() ) fun obrir(){ var i = Intent(this, Segona_activitat::class.java) startactivity(i) Aunque la segunda actividad esté en Kotlin, debido al funcionamiento interno, se indica que la clase es de java.

Llamada a nueva actividad (2bis) Como a alternativa creamos un Intent, y después le indicamos por separado la clase del package de origen, indicando que corresponde a la que estamos (this@mainactivity) y la clase destino (***::class.java): fun obrir(){ var i = Intent(this@MainActivity, Segona_activitat::class.java) startactivity(i)

Llamada a nueva actividad (3) Creamos el código de la segunda actividad, haciendo que se cierre al pulsar el botón class Segona_activitat : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_segona_activitat) val boton: Button = findviewbyid(r.id.button) boton.setonclicklistener(view.onclicklistener { tancar() ) fun tancar(){ finish()

Llama a actividad con parámetros (1) Crearemos dos actividades entre las que se pasaran parámetros. En el primer layout añadimos un botón y un EditText donde escribiremos un texto que pasaremos a la segunda actividad, y en el segundo layout añadimos un botón y un TextView donde se mostrará el texto enviado desde la primera actividad <TextView android:id="@+id/textprimer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="primera activitat" /> <EditText android:id="@+id/entradatext1" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" > <requestfocus /> </EditText> <Button android:id="@+id/boto1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="prem per la segona" /> <TextView android:id="@+id/text2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="segona Activitat" /> <Button android:id="@+id/boto2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="torna a primera" /> <TextView android:id="@+id/dadesrebudes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="dades Rebudes" android:textappearance="?android:attr/textappearance Large" />

Llama a actividad con parámetros(2) En el código de la primera actividad añadimos el método putextra() al Intent antes de llamar a la segunda actividad para añadir el texto a compartir. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val boto1: Button =findviewbyid(r.id.boto1) var textdades:edittext = findviewbyid(r.id.entradatext1) boto1.setonclicklistener(view.onclicklistener { var i = Intent(this,Segona_activitat::class.java) i.putextra("escrit",textdades.text.tostring()) startactivity(i) )

Llama a actividad con parámetros(3) En el código de la segunda actividad añadimos el método Intent.Extras para leer el texto enviado por la primera actividad class Segona_activitat : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_segona_activitat) val rebut:textview = findviewbyid(r.id.dadesrebudes) val boto2:button=findviewbyid(r.id.boto2) var bundle=intent.extras var dades=bundle.getstring("escrit") rebut.text=dades boto2.setonclicklistener(view.onclicklistener { finish() )

Llama a actividad con parámetros(4) Ahora pasaremos una dirección web desde la primera actividad, y en la segunda se visualizará. La primera actividad es similar al ejemplo anterior. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val boto1: Button =findviewbyid(r.id.boto1) var adreca: EditText = findviewbyid(r.id.entradatext1) boto1.setonclicklistener(view.onclicklistener { var i = Intent(this@MainActivity,Segona_activitat::class.java) i.putextra("pagina",adreca.text.tostring()) startactivity(i) )

Llama a actividad con parámetros(5) En la segunda actividad añadimos una vista WebView, y le pasamos el parámetro de la página al método loadurl(), además de activar el uso de Java. Si no pusiéramos la línea navegador.webviewclient= WebViewClient(), la página web se abriría en un navegador externo y no en el WebView. class Segona_activitat : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_segona_activitat) val navegador: WebView = findviewbyid(r.id.webview1) val boto2: Button =findviewbyid(r.id.boto2) var bundle=intent.extras var pag=bundle.getstring("pagina") var navegadorconfig:websettings = navegador.settings navegadorconfig.javascriptenabled=true navegador.webviewclient= WebViewClient() navegador.loadurl("http://"+pag) boto2.setonclicklistener(view.onclicklistener { finish() )

Llama a actividad con parámetros(6) Para que funcione, solo falta dar permiso a la aplicación para que pueda acceder a Internet. Por ella se ha de abrir el fichero AndroidManifest.xml, y añadir el elemento uses-permission, para indicar el permíso android.permission.internet. <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.esaii.intent1.intents1"> <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"> <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <activity android:name=".segona_activitat"></activity> </application> <uses-permission android:name="android.permission.internet" /> </manifest>

Llama a actividad con resultado (1) Crearemos una actividad en que escribiremos dos números y al pulsar un botón, pasará los valores a una nueva actividad. En esta escribiremos un nombre, y al pulsar un botón nos retornará el nombre y la suma de los dos números a la primera actividad. Actividad principal Segunda Actividad

Llama a actividad con resultado(2) En la actividad principal, creamos un listener de la pulsación del botó i al pulsar enviamos los datos class MainActivity : AppCompatActivity() { lateinit var dadesretorn:textview lateinit var envianum1:edittext lateinit var envianum2:edittext var calculrebut: Int = 0 var nomrebut:string ="" val REQUEST_CODE =1 override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) dadesretorn=findviewbyid(r.id.textrebut) envianum1 = findviewbyid(r.id.numero) envianum2 = findviewbyid(r.id.numero2) var boto:button=findviewbyid(r.id.boto) boto.setonclicklistener(view.onclicklistener { enviadades() ) fun enviadades(){ sigue después

Llama a actividad con resultado(3) Si se han escrito los números, se envían a la segunda actividad y esta se llama añadiendo un código de control. Al recibir respuesta, el método onactivityresult, retorna un código de error, el código de control enviado por la primera, y los datos de la respuesta. sigue antes fun enviadades(){ if(envianum1.text.tostring().equals("") envianum2.text.tostring().equals("")){ dadesretorn.text="falta algún número" else { var segona = Intent (this,segona_activitat::class.java) segona.putextra("numero1",integer.valueof(envianum1.text.tostring())) segona.putextra("numero2",integer.valueof(envianum2.text.tostring())) startactivityforresult(segona,request_code) override fun onactivityresult(requestcode: Int, resultcode: Int, data: Intent?) { super.onactivityresult(requestcode, resultcode, data) if (resultcode== Activity.RESULT_OK && requestcode==request_code){ if (data!= null) { if (data.hasextra("calcul")&&data.hasextra("nom")){ calculrebut=data.extras.getint("calcul") nomrebut=data.extras.getstring("nom") dadesretorn.text="en/na "+nomrebut+" diu que la suma és: "+calculrebut

Llama a actividad con resultado(4) En la segunda actividad comprobamos si se han recibido datos, y si se han recibido se extraen y se muestran. Se espera que se pulse el botón para retornar el resultado. Al pulsar el botón, se crea un Intent para retornar el resultado, y se retornan la suma de los dos números enviados por la primera actividad, el nombre escrito, y el código de error (mediante setresult) a la primera actividad. Finalmente se cierra la actividad. class Segona_activitat : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_segona_activitat) var dadesrep:textview = findviewbyid(r.id.dadaactivitat1) var dadesnom:edittext = findviewbyid(r.id.entranom) var dadesrebudes= intent.extras if (dadesrebudes==null){ return var numerorebut1=dadesrebudes.getint("numero1") var numerorebut2=dadesrebudes.getint("numero2") dadesrep.text="he rebut els nombres: "+Integer.toString(numerorebut1)+ " i " + Integer.toString(numerorebut2) var boto2:button=findviewbyid(r.id.boto2) boto2.setonclicklistener(view.onclicklistener { var j= Intent() j.putextra("calcul",numerorebut1+numerorebut2) j.putextra("nom",dadesnom.text.tostring()) setresult(activity.result_ok,j) finish() )

Intents explícitos / implícitos Los Intents se utilizan para iniciar actividades y enviar eventos a varios destinatarios. Un Intent queda descrito por: la acció a realizar (MAIN, EDIT, VIEW, ), el dato que actúa sobre la acción (Universal Resource Indicator - URI), los extras (int, String, ) y el componente al que va dirigido (ex: edu.pdrm.holamon) Hay dos formas de llamar un Intent: Invocación explícita: Se especifica explícitamente en código que componente es el encargado de gestionar el Intent. Intent intent = new Intent(Context, Activitat.class); startactivity(intent); Invocación implícita: Es la plataforma quien determina, mediante un proceso de resolución de Intents, cual es el componente mas adecuado para gestionar el intent. Intent intent = new Intent(Intent.ACTION_DIAL, URI.parse(tel:928-76-34-26)); startactivity(intent);

Intents Intent Filter Un componente declara la capacidad para a atender un Intent mediante el tag <intent-filter> en el archivo AndroidManifest.xml. <activity android:name="edu.example.nomactivitat.mainactivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.insert" /> <category android:name="android.intent.category.default" /> <data android:mimetype="vnd.android.cursor.dir/vnd.google.note" /> </intent-filter> </activity> Para nombrar una acción normalmente se utiliza la forma.intent.action.accio. Por ejemplo, para el navegador web, la acción VIEW abre el navegador en una URL especificada; o para el marcador de teléfono, la acción CALL realiza una llamada a un número especificado. http://developer.android.com/reference/android/content/intent.html

Intents - Ejemplos Un intent esta formado por una acción, datos (representados mediante URIs), datos extra en pares clave/valor y un nombre de clase explícita, llamado nombre del componente. Abre una dirección URL en el navegador: fun invocawebbrowser(){ var intent =Intent(Intent.ACTION_VIEW) intent.data=uri.parse("http://www.upc.edu") startactivity(intent) Llama al navegador realizar una búsqueda: fun invocawebsearch(busca:string){ var intent = Intent(Intent.ACTION_WEB_SEARCH) intent.putextra(searchmanager.query, busca) startactivity(intent) Abre el marcador telefónico: fun marcadortlf(){ var intent=intent(intent.action_dial) startactivity(intent) Llama al número de teléfono indicado: @SuppressLint("MissingPermission") fun llamatlf(numtlf:string){ var intent=intent(intent.action_call) intent.data=(uri.parse("tel:"+numtlf)) startactivity(intent) Hay que insertar la siguiente línea en AndroidManifest.xml <uses-permission android:name="android.permission.call_phone"> </uses-permission> y tener el permiso de uso del teléfono activado en la aplicación. Sino hay que añadir el código para comprobar y activar el permiso. Abre Maps para mostrar la posición actual, con un zoom de 4, y busca restaurantes: fun muestramapaposactual(){ var intent=intent(intent.action_view) intent.data=(uri.parse ("geo:0,0?z=4&q=restaurantes")) startactivity(intent) http://developer.android.com/guide/appendix/g-app-intents.html

Llama a un navegador externo Ahora utilizaremos una invocación implícita a un Intent que llamará al navegador externo por defecto. Utilizamos layout con un EditText y un botón. class MainActivity : AppCompatActivity() { lateinit var URL:String override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var boto:button=findviewbyid(r.id.boto) var adreca:edittext=findviewbyid(r.id.editurl) boto.setonclicklistener(view.onclicklistener { URL=adreca.text.toString() obrenavegador(url) ) fun obrenavegador(url:string){ var intent = Intent(Intent.ACTION_VIEW) intent.data= Uri.parse("http://"+url) startactivity(intent) Alternativa a la invocación del Intent: var intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://"+url))

Llama a Maps (1) Al pulsar un botón, llamaremos a la aplicación Maps, indicando una coordenada con un zoom de 20. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var boto: Button =findviewbyid(r.id.boto) boto.setonclicklistener(view.onclicklistener { obremaps() ) fun obremaps(){ var intent= Intent(Intent.ACTION_VIEW) intent.data=(uri.parse("geo:41.22164,1.72990?z=20")) startactivity(intent) Podemos realizar la llamada indicando que etiquete las coordenadas: intent.data=(uri.parse("geo:0,0?q=41.22164,1.72990 (AI109)"))

Llama a Maps (2) Ahora llamamos a la aplicación Maps, editando las coordenadas mediante dos EditText. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var boto:button = findviewbyid(r.id.boto) var latitut:edittext = findviewbyid(r.id.editlat) var longitut:edittext = findviewbyid(r.id.editlong) var uril:textview = findviewbyid(r.id.textview1) boto.setonclicklistener( View.OnClickListener { var coordenades="geo:"+latitut.text.tostring()+","+longitut.text.tostring()+"?=20" uril.text=coordenades obremaps(coordenades) ) fun obremaps(dades:string){ var intent=intent(intent.action_view) intent.data= Uri.parse(dades) startactivity(intent)

Crida a Maps (3) - SeekBar Añadimos un SeekBar al Layout para modificar el valor del zoom mediante una barra. Añadimos el código al ejemplo anterior. var uril: TextView = findviewbyid(r.id.textview1) var valzoom:textview = findviewbyid(r.id.valorzoom) var zoom:seekbar = findviewbyid(r.id.seekbar1) zoom.setonseekbarchangelistener(object: SeekBar.OnSeekBarChangeListener{ override fun onprogresschanged(seekbar: SeekBar?, progress: Int, fromuser: Boolean) { valzoom.text = progress.tostring() override fun onstarttrackingtouch(seekbar: SeekBar?) { override fun onstoptrackingtouch(seekbar: SeekBar?) { ) boto.setonclicklistener( View.OnClickListener { var coordenades="geo:"+latitut.text.tostring()+", +longitut.text.tostring()+"?z="+valzoom.text.tostring() uril.text=coordenades obremaps(coordenades) )

Alert Dialog Para mostrar mensajes de notificaciones, no es necesario crear una aplicación y llamarla. Una de les posibilidades es utilizar los Alert Dialogs. Creamos una aplicación con un Layout que incluya dos botones y un TextView. <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="alert Dialog Simple" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="alert Dialog amb opció" /> <TextView android:id="@+id/textview1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="textview" />

Alert Dialog Pulsando un botón aparece un mensaje con un botón de salir, y pulsando el otro aparece un mensaje y dos opciones (Confirmar y Cancelar). class MainActivity : AppCompatActivity() { lateinit var text:textview lateinit var simple:button lateinit var ambretorn:button lateinit var dialogsimple:alertdialog.builder lateinit var dialogretorn:alertdialog.builder override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) simple = findviewbyid(r.id.button1) ambretorn = findviewbyid(r.id.button2) text= findviewbyid(r.id.textview1) simple.setonclicklistener(guaita) ambretorn.setonclicklistener(guaita) dialogsimple= AlertDialog.Builder(this) dialogsimple.settitle("alerta Simple") dialogsimple.setmessage("aquest és un Alert Dialog només amb un botó d'acceptar") dialogsimple.setpositivebutton("vale",null) dialogretorn= AlertDialog.Builder(this) dialogretorn.settitle("alerta amb opcions") dialogretorn.setmessage("vols acceptar o cancel lar?") dialogretorn.setcancelable(false); dialogretorn.setpositivebutton("confirmar", object: DialogInterface.OnClickListener{ override fun onclick(dialog: DialogInterface?, which: Int) { text.text = "Has polsat confirmar a l'alerta amb opcions" ) dialogretorn.setnegativebutton("cancel lar", object: DialogInterface.OnClickListener{ override fun onclick(dialog: DialogInterface?, which: Int) { text.text="has Cancel lat l'alerta amb opcions" ) sigue después

Alert Dialog Finalmente creamos el Listener común a los botones, que llamará al AlertDialog que corresponda en función del botón pulsado. sigue de antes dialogretorn.setnegativebutton("cancel lar", object: DialogInterface.OnClickListener{ override fun onclick(dialog: DialogInterface?, which: Int) { text.text="has Cancel lat l'alerta amb opcions" ) var guaita: View.OnClickListener= object: View.OnClickListener { override fun onclick(v: View?) { if ((v as Button).id==simple.id){ dialogsimple.show() text.text="has provat alerta simple" else if ((v as Button).id==ambretorn.id){ dialogretorn.show()

Toast Otra alternativa para mostrar mensaje rápidos de corta duración es utilizar la clase Toast. Podemos tener varias alternativas. Creamos el layout principal de la aplicación con tres botones, y añadimos un nuevo layout secundario que servirá para mostrar un mensaje a medida. Layout principal Layout secundario

sigue después Toast Pulsando un botón aparece un mensaje en un lugar por defecto, con el otro aparece centrado verticalmente, y con el último botón se muestra el layout secundario. class MainActivity : AppCompatActivity() { lateinit var vtexte:textview lateinit var simple:button lateinit var reubicat:button lateinit var amida:button override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) vtexte=findviewbyid(r.id.textview1) simple=findviewbyid(r.id.buttonsimple) reubicat=findviewbyid(r.id.buttonubica) amida=findviewbyid(r.id.buttonmida) simple.setonclicklistener(escoltador) reubicat.setonclicklistener(escoltador) amida.setonclicklistener(escoltador) var Escoltador : View.OnClickListener = object:view.onclicklistener{ override fun onclick(v: View?) { if((v as Button).id==simple.id){ missatge_simple() else if ((v as Button).id==reubicat.id){ missatge_reubicat() else if ((v as Button).id==amida.id) { missatge_amida() fun missatge_simple (){

Toast Para crear y mostrar los mensajes con Toast hemos creado unas funciones aparte. sigue de antes fun missatge_simple (){ var toastsimple:toast = Toast.makeText(this,"Toast normal (curta durada)",toast.length_short) vtexte.text="toast Simple polsat" toastsimple.show() fun missatge_reubicat(){ val toastreubicat = Toast.makeText(this, "Toast reubicat (llarga durada)", Toast.LENGTH_LONG) toastreubicat.setgravity(gravity.center_vertical, 0, 0) toastreubicat.show() vtexte.settext("toast Reubicat polsat") fun missatge_amida() { val inflater = getlayoutinflater() val layoutmida = inflater.inflate(r.layout.toast_a_mida, null) val toastamida = Toast(getApplicationContext()) toastamida.setgravity(gravity.center_vertical, 0, 0) toastamida.setduration(toast.length_long) toastamida.setview(layoutmida) toastamida.show() vtexte.settext("toast a mida polsat")

Android Sensores y otros servicios del sistema Cristobal Raya Giner Programació de Dispositius Mòbils (PRDM)

Lista de sensores Una forma sencilla de listar todo los sensores que incorpora el dispositivo, es extraer la lista con el método getsensorlist() del SensorManager. Creamos un TextView, al cual iremos añadiendo los diferentes sensores con el método append(), y nos mostrará el nombre del sensor y el valor máximo que puede tener. <TextView android:id="@+id/llistat" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var llistat:textview = findviewbyid(r.id.llistat) as TextView llistat.text="llista dels sensors disponibles: \n" var sensormanager = getsystemservice(context.sensor_service) as SensorManager var llistasensors=sensormanager.getsensorlist(sensor.type_all) for (sensor in llistasensors){ llistat.append(sensor.name+", Rang: "+ sensor.maximumrange.tostring()+"\n") http://developer.android.com/reference/android/hardware/sensor.html https://developer.android.com/guide/topics/sensors/sensors_overview.html

Estados de una actividad Una actividad puede estar en varios estados como creándose, iniciándose, en pausa, etc..., y para cambiar de uno a otro están los métodos correspondientes. Al pasar de un estado a otro se puede ejecutar algún código, en el método correspondiente, pero siempre se ha de llamar primero al método de la clase padre. override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) //Código override fun onresume() { super.onresume() //Código

Acelerómetro Para leer los tres ejes del acelerómetro, primero crearemos un layout con 3 TextView: <TextView android:id="@+id/textviewx" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text= ax" /> <TextView android:id="@+id/textviewy" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text= ay" /> <TextView android:id="@+id/textviewz" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text= az" /> Probaremos dos métodos: Implementando en la definición de la actividad el SensorEventListener (1), i creado el SensorEventListener dentro de la actividad (2).

Acelerómetro (1) En el código implementaremos el SensorEvenListener en la definición de la clase, para que controle los cambios de valor de los sensores, y un SensorManager que gestionará la lectura de los sensores. Un SensorEvenListener necesita tener implementados los métodos y lo realizamos manualmente, o seleccionando sobre SensorEventListener y pulsamos Ctrl+i, o en el menú Code Implement Methods class MainActivity : AppCompatActivity(), SensorEventListener { lateinit var sx:textview lateinit var sy:textview lateinit var sz:textview override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) sx=findviewbyid(r.id.textviewx) sy=findviewbyid(r.id.textviewy) sz=findviewbyid(r.id.textviewz) var sensormanager:sensormanager=getsystemservice(context.sensor_service) as SensorManager sensormanager.registerlistener(this,sensormanager.getdefaultsensor(sensor.type_accelerometer), SensorManager.SENSOR_DELAY_NORMAL) override fun onaccuracychanged(sensor: Sensor?, accuracy: Int) { override fun onsensorchanged(event: SensorEvent?) { if (event!= null) { if (event.sensor.type==sensor.type_accelerometer){ var ax: Float = event.values[0] var ay: Float = event.values[1] var az: Float = event.values[2] sx.text="aceleración X: "+ax.tostring() sy.text="aceleración Y: "+ay.tostring() sz.text="aceleración Z: "+az.tostring()

Acelerómetro (2) En el código creamos un SensorManager que leerá de los sensores, y un SensorEvenListener para que controle los cambios de valor de los sensores. class MainActivity : AppCompatActivity() { lateinit var sx: TextView lateinit var sy: TextView lateinit var sz: TextView lateinit var sensormanager:sensormanager lateinit var eventlistener: SensorEventListener override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) sx=findviewbyid(r.id.textviewx) sy=findviewbyid(r.id.textviewy) sz=findviewbyid(r.id.textviewz) sensormanager= getsystemservice(context.sensor_service) as SensorManager eventlistener= object: SensorEventListener{ override fun onaccuracychanged(sensor: Sensor?, accuracy: Int) { override fun onsensorchanged(event: SensorEvent?) { if (event!= null) { if (event.sensor.type==sensor.type_accelerometer){ var ax: Float = event.values[0] var ay: Float = event.values[1] var az: Float = event.values[2] sx.text="aceleración X: "+ax.tostring() sy.text="aceleración Y: "+ay.tostring() sz.text="aceleración Z: "+az.tostring() override fun onresume() { super.onresume() sensormanager.registerlistener(eventlistener,sensormanager.getdefaultsensor(sensor.type_accelerometer),sensormanager.sensor_delay_normal) override fun onstop() { sensormanager.unregisterlistener(eventlistener) super.onstop()

Acelerómetro y Brújula Leeremos de dos sensor: el sensor acelerómetro es una lectura directa del hardware y la brújula es un cálculo interno a partir de los acelerómetros i los magnetómetros. Utilizamos 6 TextView. class MainActivity : AppCompatActivity(), SensorEventListener { lateinit var acx:textview lateinit var acy:textview lateinit var acz:textview lateinit var brujulax:textview lateinit var brujulay:textview lateinit var brujulaz:textview override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) acx=findviewbyid(r.id.ax) acy=findviewbyid(r.id.ay) acz=findviewbyid(r.id.az) brujulax=findviewbyid(r.id.brx) brujulay=findviewbyid(r.id.bry) brujulaz=findviewbyid(r.id.brz) var sensormanager:sensormanager=getsystemservice(context.sensor_service)as SensorManager sensormanager.registerlistener(this, sensormanager.getdefaultsensor(sensor.type_accelerometer), SensorManager.SENSOR_DELAY_NORMAL) sensormanager.registerlistener(this,sensormanager.getdefaultsensor(sensor.type_orientation), SensorManager.SENSOR_DELAY_NORMAL) override fun onaccuracychanged(sensor: Sensor?, accuracy: Int) { override fun onsensorchanged(event: SensorEvent?) { continua en la página siguiente...

Acelerómetro y Brújula viene de la página anterior... sensormanager.registerlistener(this,sensormanager.getdefaultsensor(sensor.type_orientation), SensorManager.SENSOR_DELAY_NORMAL) override fun onaccuracychanged(sensor: Sensor?, accuracy: Int) { override fun onsensorchanged(event: SensorEvent?) { if (event!= null) { if (event.sensor.type==sensor.type_accelerometer){ acx.text="aceleración X: "+event.values[0] acy.text="aceleración Y: "+event.values[1] acz.text="aceleración Z: "+event.values[2] else if(event.sensor.type==sensor.type_orientation){ brujulax.text="orientación X: "+event.values[0] brujulay.text="orientación Y: "+event.values[1] brujulaz.text="orientación Z: "+event.values[2]

Acelerómetro / Orientación Utilizaremos una nueva versión de la brújula, ya que el tipo TYPE_ORIENTATION ya está obsoleto y se recomienda utilizar el SensorManager.getOrientation() que calcula la orientación del dispositivo utilizando datos de los acelerómetros y de los campos magnéticos. Utilitzaremos 3 TextView. class MainActivity : AppCompatActivity(), SensorEventListener { lateinit var acceleracions:textview lateinit var magnetismes:textview lateinit var orientacio:textview var acceleracio=floatarray (3) var magnetisme=floatarray (3) override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) acceleracions=findviewbyid(r.id.acceleracions) magnetismes=findviewbyid(r.id.magnetisme) orientacio=findviewbyid(r.id.orientacio) var sensormanager:sensormanager=getsystemservice(context.sensor_service) as SensorManager sensormanager.registerlistener(this,sensormanager.getdefaultsensor(sensor.type_accelerometer), SensorManager.SENSOR_DELAY_NORMAL) sensormanager.registerlistener(this,sensormanager.getdefaultsensor(sensor.type_magnetic_field), SensorManager.SENSOR_DELAY_NORMAL) override fun onaccuracychanged(sensor: Sensor?, accuracy: Int) { override fun onsensorchanged(event: SensorEvent?) { sigue en la página siguiente

Acelerómetro / Orientación viene de la página anterior... override fun onaccuracychanged(sensor: Sensor?, accuracy: Int) { override fun onsensorchanged(event: SensorEvent?) { if (event!= null) { if (event.sensor.type==sensor.type_accelerometer){ acceleracio=event.values acceleracions.text="acceleració X: "+acceleracio[0]+"\n"+ "Acceleració Y: "+acceleracio[1]+"\n"+ "Acceleració Z: "+acceleracio[2] if (event.sensor.type==sensor.type_magnetic_field){ magnetisme=event.values magnetismes.text="magnetic X: "+magnetisme[0]+"\n"+ "Magnetic Y: "+magnetisme[1]+"\n"+ "Magnetic Z: "+magnetisme[2] if (magnetisme!=null && acceleracio!=null){ //Importante que existan para el cálculo var matrizrotacion= FloatArray(16) var orientacion=floatarray(3) SensorManager.getRotationMatrix(matrizRotacion,null,acceleracio,magnetisme) SensorManager.getOrientation(matrizRotacion,orientacion) orientacio.text="orientació Azimuth: "+Math.toDegrees(orientacion[0].toDouble())+"\n"+ "Orientació Pitch: "+Math.toDegrees(orientacion[1].toDouble())+"\n"+ "Orientació Roll: "+Math.toDegrees(orientacion[2].toDouble())

Varios Sensores, un Listener Utilizaremos 3 TextView para mostrar el valor de los sensores de aceleración, magnéticos y de proximidad, pero solo utilizaremos un solo SensorEventListener ni implementado a la actividad. class MainActivity : AppCompatActivity() { lateinit var sensormanager :SensorManager lateinit var sensorlistener: SensorEventListener override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var accelerometres:textview = findviewbyid(r.id.accelerometres) var proximitats:textview=findviewbyid(r.id.proximitat) var magnetics:textview = findviewbyid(r.id.magnetics) sensormanager=getsystemservice(context.sensor_service) as SensorManager sensorlistener = object: SensorEventListener{ override fun onaccuracychanged(sensor: Sensor?, accuracy: Int) { override fun onsensorchanged(event: SensorEvent?) { if (event!= null) { if (event.sensor.type==sensor.type_accelerometer){ accelerometres.text="acceleració X: "+event.values[0]+"\n"+ "Acceleració Y: "+event.values[1]+"\n"+ "Acceleració Z: "+event.values[2] if (event.sensor.type==sensor.type_proximity){ proximitats.text="proximitat: "+event.values[0] if (event.sensor.type==sensor.type_magnetic_field){ magnetics.text="magnetic X: "+event.values[0]+"\n"+ "Magnetic Y: "+event.values[1]+"\n"+ "Magnetic Z: "+event.values[2] override fun onresume() { segueix pàgina següent. super.onresume()

Varios Sensores, un Listener ve de pàgina anterior... if (event.sensor.type==sensor.type_magnetic_field){ magnetics.text="magnetic X: "+event.values[0]+"\n"+ "Magnetic Y: "+event.values[1]+"\n"+ "Magnetic Z: "+event.values[2] override fun onresume() { super.onresume() sensormanager.registerlistener(sensorlistener, sensormanager.getdefaultsensor(sensor.type_accelerometer), SensorManager.SENSOR_DELAY_NORMAL) sensormanager.registerlistener(sensorlistener, sensormanager.getdefaultsensor(sensor.type_proximity), SensorManager.SENSOR_DELAY_NORMAL) sensormanager.registerlistener(sensorlistener, sensormanager.getdefaultsensor(sensor.type_magnetic_field), SensorManager.SENSOR_DELAY_NORMAL) override fun onstop() { sensormanager.unregisterlistener(sensorlistener) super.onstop()

Localización GPS Tenemos dos formas de acceder a la localización por GPS: mediante la API del propio SDK de Android mediante la clase LocationManager, y más recientemente mediante la API de Google Play Services. Con la API del SDK, podemos saber que proveedor utilizamos para la ubicación: LocationManager.GPS_PROVIDER : este proveedor determina la ubicación usando satélites. Dependiendo de las condiciones, este proveedor puede tomar un tiempo para devolver una corrección de ubicación. LocationManager.NETWORK_PROVIDER : este proveedor determina la ubicación según la disponibilidad de la torre de la celda y los puntos de acceso WiFi. Los resultados se recuperan mediante una búsqueda de red. LocationManager.PASSIVE_PROVIDER : este proveedor devolverá las ubicaciones generadas por otros proveedores. Usted recibe pasivamente actualizaciones de ubicación cuando otras aplicaciones o servicios las solicitan sin solicitarlas usted mismo. Con la API de Google Play Services, no podemos conocer que proveedor ha proporcionado la ubicación ya que utilizan un proveedor de ubicación fusionada, pero, según Google, se consigue una mayor velocidad en la adquisición de la localización, más precisión de la ubicación y el movimiento de usuario, y un mejor rendimiento de la batería. Además la API se puede actualizar en el dispositivo independientemente de la aplicación. El principal problema es que en caso de error de posición no se conoce que proveedor ha proporcionado la posición y no podemos seleccionar otro para evitar el error. https://code.i-harness.com/es/q/1f7e2c6

Localización GPS/aGPS (SDK) Para acceder a los datos de localización del GPS, necesitamos habilitar los permisos para el uso de la localización en el fichero AndroidManifest.xml. En el código, utilizaremos la clase LocationManager para crear un objeto que nos permita acceder a los datos del GPS, y la clase LocationListener, para que cada vez que cambie la localización, se actualicen los datos recibidos del GPS. Al pulsar el botón Activar se activa la localización por GPS, y al pulsar el botón Desactivar, deja de actualizarse la posición. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.esaii.kotlinsensoresgpsviejo"> <uses-permission android:name="android.permission.access_fine_location"/> <uses-permission android:name="android.permission.access_coarse_location"/> <uses-permission android:name="android.permission.internet"/> <application android:allowbackup="true" android:icon="@mipmap/ic_launcher android:label="@string/app_name" android:roundicon="@mipmap/ic_launcher_round" android:supportsrtl="true" android:theme="@style/apptheme"> <activity android:name=".mainactivity"> <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> </application> </manifest>

Localización GPS/aGPS (SDK) En el código, intentaremos utilizar tanto el GPS_PROVIDER para adquirir los datos del GPS de satélite, y el NETWORK_PROVIDER para utilizar el A-GPS de telefonía móvil como a localizador. class MainActivity : AppCompatActivity(){ lateinit var btnactualizar:button lateinit var btndesactivar:button lateinit var lbllatitud:textview lateinit var lbllongitud:textview lateinit var lblprecision:textview lateinit var lblestado:textview lateinit var lblhora:textview lateinit var locmanager:locationmanager lateinit var loclistener:locationlistener lateinit var pgps:textview lateinit var pagps:textview val PIDE_LOC:Int =1714 override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) btnactualizar=findviewbyid(r.id.btnactualizar) btndesactivar=findviewbyid(r.id.btndesactivar) lbllatitud=findviewbyid(r.id.lblposlatitud) lbllongitud=findviewbyid(r.id.lblposlongitud) lblprecision=findviewbyid(r.id.lblposprecision) lblestado=findviewbyid(r.id.lblestado) lblhora=findviewbyid(r.id.lblhora) pgps=findviewbyid(r.id.pgps) pagps=findviewbyid(r.id.pagps) btnactualizar.setonclicklistener(view.onclicklistener { leegps() ) btndesactivar.setonclicklistener(view.onclicklistener { try{locmanager.removeupdates(loclistener) catch (e:exception){-1 ) segueix pàgina següent. https://developer.android.com/guide/topics/location/index.html https://developer.android.com/guide/topics/location/strategies.html

Localización GPS/aGPS (SDK) ve de pàgina anterior... fun leegps(){ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)!= PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayof<string>(manifest.permission.access_fine_location),pide_loc) return else { activalocationmanager() @SuppressLint("MissingPermission") //Desactivamos la comprobación del permiso del locmanager ya que se se comprueba en esta misma función override fun onrequestpermissionsresult(requestcode: Int, permissions: Array<out String>, grantresults: IntArray) { super.onrequestpermissionsresult(requestcode, permissions, grantresults) if (requestcode==pide_loc){ if (grantresults.size>0 && grantresults[0]==packagemanager.permission_granted){ activalocationmanager() @SuppressLint("MissingPermission") //Se comprueba fuera de la función fun activalocationmanager(){ loclistener=object : LocationListener { override fun onlocationchanged(location: Location?) { mostrarposicion(location) override fun onstatuschanged(provider: String?, status: Int, extras: Bundle?) { lblestado.text="gps Provider Status: "+status segueix pàgina següent.

Localización GPS/aGPS (SDK) ve de pàgina anterior... @SuppressLint("MissingPermission") //Se comprueba fuera de la función fun activalocationmanager(){ loclistener=object : LocationListener { override fun onlocationchanged(location: Location?) { mostrarposicion(location) override fun onstatuschanged(provider: String?, status: Int, extras: Bundle?) { lblestado.text="gps Provider Status: "+status override fun onproviderenabled(provider: String?) { lblestado.text="gps Provider ON" override fun onproviderdisabled(provider: String?) { val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) startactivity(intent) lblestado.text="gps Provider OFF" locmanager = getsystemservice(context.location_service) as LocationManager locmanager.requestlocationupdates(locationmanager.gps_provider, 2000, 1f, loclistener) locmanager.requestlocationupdates(locationmanager.network_provider,2000,1f,loclistener) if(!locmanager.isproviderenabled(locationmanager.gps_provider)){ fun mostrarposicion(loc:location?){ if (loc!=null){ lbllatitud.text="latitud: "+loc.latitude lbllongitud.text="longitud: "+loc.longitude lblprecision.text="precisión: "+loc.accuracy lblhora.text="hora GPS: "+ SimpleDateFormat("EEEE dd/mm/yyyy, HH:mm:ss").format(loc.time) else{ lbllatitud.text="latitud: (sin datos)" lbllongitud.text="longitud: (sin datos)" lblprecision.text="precision: (sin datos" lblhora.text="hora GPS: (sin datos)"

Localización GPS/aGPS (SDK) Añadir dos TextView y el siguiente código para comprobar cual de los proveedores de localización del dispositivo está activado. La activación de los proveedores de localización se realiza desde los ajustes de ubicación del dispositivo, en el apartado Modo. En el modo Alta precisión se activan ambos, en modo Ahorro de batería solo el A-GPS, y en el modo Solo dispositivo solo el GPS de satélite. (Puede ser que en función de la versión de Android y del dispositivo, la forma de activar los proveedores sea diferente) locmanager.requestlocationupdates(locationmanager.gps_provider, 2000, 1f, loclistener) locmanager.requestlocationupdates(locationmanager.network_provider,2000,1f,loclistener) if(!locmanager.isproviderenabled(locationmanager.gps_provider)){ pgps.text="gps desactivat" else { pgps.text="gps activat" if(!locmanager.isproviderenabled(locationmanager.network_provider)){ pagps.text="a-gps desactivat" else { pagps.text="a-gps activat"

Localización GPS (Play Services) En este ejemplo utilizaremos las librerías de localización de Google Play Services. Esto implica instalar estas librerías desde la pestaña SDK Tools del SDK Manager, y configurar el proyecto para poder utilizar las llibrerias, incluyendo la configuración de Gradle. Primero se ha de añadir al fichero build.gradle (Module:app) la dependencia a la librería de Google Play Services. Podemos conocer y añadir la última versión instalada mediante File Project Structure -Modules-app Dependencies + Library dependency dependencies {... compile 'com.google.android.gms:play-services:11.8.0' A partir de la versión 6.5 del Google Play Services, podemos solo instalar las librerías necesarias en lugar de todo el paquete, y se recomienda solo instalar las necesarias para evitar errores de memoria en la compilación. dependencies {... compile 'com.google.android.gms:play-services-location:11.8.0' https://developers.google.com/android/guides/setup#add_google_play_services_to_your_project

Localización GPS (Play Services) Primero configuramos el uso de las librerías de Google Services, añadiendo las librerías correspondientes al fichero build.gradle (Module:app) apply plugin: 'com.android.application' dependencies {.. compile 'com.google.android.gms:play-services-location:11.8.0' Añadimos el permiso de acceso al GPS y a internet para el A-GPS al fichero AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" <uses-permission android:name="android.permission.access_fine_location"/> <uses-permission android:name="android.permission.internet"/> <application </application> </manifest>

Localización GPS (Play Services) Configuramos el Layout con varios TextView y un TobbleButton para activar/desactivar la actualización de la localización

Localización GPS (Play Services) En este ejemplo implementaremos en la propia aplicación en el fichero los objetos: GoogleApiClient.OnConnectionFailedListener GoogleApiClient.ConnectionCallbacks LocationListener Utilizaremos LocationServices.FusedLocationApi, aunque indiquen es está obsoleta. import android.manifest import android.annotation.suppresslint import android.app.activity import android.content.intent import android.content.intentsender import android.content.pm.packagemanager import android.location.location import android.support.v7.app.appcompatactivity import android.os.bundle import android.support.v4.app.activitycompat import android.util.log import android.view.view import android.widget.textview import android.widget.togglebutton import com.google.android.gms.common.connectionresult import com.google.android.gms.common.api.googleapiclient import com.google.android.gms.common.api.pendingresult import com.google.android.gms.common.api.resultcallback import com.google.android.gms.common.api.status import com.google.android.gms.location.* import java.text.simpledateformat class MainActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,LocationListener { lateinit var latitud:textview

Localización GPS (Play Services) class MainActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,LocationListener { lateinit var latitud:textview lateinit var longitud:textview lateinit var precision:textview lateinit var hora:textview lateinit var altura:textview lateinit var velocidad:textview lateinit var orientacion:textview lateinit var btnactualizar:togglebutton lateinit var apiclient:googleapiclient lateinit var locationrequest: LocationRequest val PIDE_LOCALIZACION:Int=119 val PIDE_CONFIG_UBICACION:Int=1714 override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) latitud=findviewbyid(r.id.lblposlatitud) longitud=findviewbyid(r.id.lblposlongitud) precision=findviewbyid(r.id.lblposprecision) hora=findviewbyid(r.id.lblhora) altura=findviewbyid(r.id.lblaltura) velocidad=findviewbyid(r.id.lblspeed) orientacion=findviewbyid(r.id.lblorientacion) btnactualizar=findviewbyid(r.id.btnactualizar) apiclient= GoogleApiClient.Builder(this).enableAutoManage(this,this).addConnectionCallbacks(this).addApi(LocationServices.API).build() btnactualizar.setonclicklistener(view.onclicklistener {

Localización GPS (Play Services) btnactualizar.setonclicklistener(view.onclicklistener { if (btnactualizar.ischecked){ activaactualizacioneslocation() else desactivaactualizacioneslocation() ) fun activaactualizacioneslocation(){ locationrequest=locationrequest().setinterval(2000).setfastestinterval(1000).setpriority(locationrequest.priority_high_accuracy) var locationsettingsrequest:locationsettingsrequest=locationsettingsrequest.builder().addlocationrequest(locationrequest).build() var result:pendingresult<locationsettingsresult> = LocationServices.SettingsApi.checkLocationSettings (apiclient,locationsettingsrequest) result.setresultcallback(resultcallback<locationsettingsresult>(){ var status: Status =it.status //it es la variable por defecto del ResultCallback<> when (status.statuscode){ LocationSettingsStatusCodes.SUCCESS -> { iniciaactualizacionubicacion() Log.i("Android-Localiza", "Configuración correcta") LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try { status.startresolutionforresult(this@mainactivity, PIDE_CONFIG_UBICACION) Log.i("Android-Localiza", "Se requiere actuación del usuario") catch (e: IntentSender.SendIntentException) { btnactualizar.ischecked = false Log.i("Android-Localiza", "Error al intentar solucionar configuración de ubicación") LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> { Log.i("Android-Localiza", "No se puede cumplir la configuración de ubicación necesaria") btnactualizar.ischecked = false ) fun desactivaactualizacioneslocation(){

Localización GPS (Play Services) fun desactivaactualizacioneslocation(){ LocationServices.FusedLocationApi.removeLocationUpdates(apiClient,this) fun iniciaactualizacionubicacion(){ if (ActivityCompat.checkSelfPermission(this, android.manifest.permission.access_fine_location)!= PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayof<string>(manifest.permission.access_fine_location),pide_localizacion) else { LocationServices.FusedLocationApi.requestLocationUpdates(apiClient,locationRequest,this) Log.i("Android-Loaliza","Inicio de recepción de ubicaciones") @SuppressLint("MissingPermission") //El permiso se verifica en propia función override fun onrequestpermissionsresult(requestcode: Int, permissions: Array<out String>, grantresults: IntArray) { super.onrequestpermissionsresult(requestcode, permissions, grantresults) if (requestcode==pide_localizacion){ if (grantresults.size == 1 && grantresults[0] == PackageManager.PERMISSION_GRANTED) { //Permiso concedido val lastlocation = LocationServices.FusedLocationApi.getLastLocation(apiClient) actualizalocalizaciones(lastlocation) else { //Permiso denegado: //Deberíamos deshabilitar toda la funcionalidad relativa a la localización. Log.e("Android-Localiza", "Permiso denegado") //Implements de GoogleApiClient.ConnectionCallbacks *********** override fun onconnected(p0: Bundle?) {

Localización GPS (Play Services) //Implements de GoogleApiClient.ConnectionCallbacks *********** override fun onconnected(p0: Bundle?) { if (ActivityCompat.checkSelfPermission(this, android.manifest.permission.access_fine_location)!= PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayof<string>(manifest.permission.access_fine_location),pide_localizacion) else { var lastlocation: Location = LocationServices.FusedLocationApi.getLastLocation(apiClient) actualizalocalizaciones(lastlocation) Log.i("Android-Localiza", "Conectado") override fun onconnectionsuspended(p0: Int) { Log.e("Android-Localiza", "Se ha interrumpido la conexión con Google Play Services") //Implements de GoogleApiClient.OnConnectionFailedListener ************* override fun onconnectionfailed(p0: ConnectionResult) { Log.e("Android-Localiza", "Error grave al conectar con Google Play Services") //Implement de LocationListener override fun onlocationchanged(p0: Location?) { actualizalocalizaciones(p0) fun actualizalocalizaciones(lastloc:location?){ if (lastloc!=null){ latitud.text="latitud: "+lastloc.latitude longitud.text="longitud: "+lastloc.longitude

Localización GPS (Play Services) fun actualizalocalizaciones(lastloc:location?){ if (lastloc!=null){ latitud.text="latitud: "+lastloc.latitude longitud.text="longitud: "+lastloc.longitude precision.text="precisión: "+lastloc.accuracy hora.text="hora GPS: "+ SimpleDateFormat("EEEE dd/mm/yyyy, HH:mm:ss").format(lastLoc.time) altura.text="altura: "+lastloc.altitude velocidad.text="velocidad: "+lastloc.speed orientacion.text="orientacion: "+lastloc.bearing else{ latitud.text="latitud: (desconocida)" longitud.text="longitud: (desconocida)" precision.text="precisión: (desconocida)" hora.text="hora GPS: (desconocida)" altura.text="altura: (desconocida)" velocidad.text="velocidad: (desconocida)" orientacion.text="orientacion: (desconocida)" override fun onactivityresult(requestcode: Int, resultcode: Int, data: Intent?) { super.onactivityresult(requestcode, resultcode, data) when (requestcode) { PIDE_CONFIG_UBICACION -> when (resultcode) { Activity.RESULT_OK -> iniciaactualizacionubicacion() Activity.RESULT_CANCELED -> { Log.i("Android-Localiza", "El usuario no ha realizado los cambios de configuración necesarios") btnactualizar.ischecked = false

Android Datos Cristobal Raya Giner Programació de Dispositius Mòbils (PRDM)

Internacionalización - Manual Normalmente cada usuario tiene configurado su dispositivo Android con su idioma, que se puede cambiar en el menú de ajustes del dispositivo Android. Para realizar una aplicación adaptada al idioma del usuario, se trabaja con las etiquetas de Strings del fichero string.xml. Creamos un Layout con varios TextView, con el texto asignado mediante etiquetas. <TextView android:id="@+id/textview0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <TextView android:id="@+id/textview1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/imtrying" /> <TextView android:id="@+id/textview2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/language" />

Internacionalización - Manual Creamos una carpeta para cada idioma con el formato values-xx donde XX es la abreviatura del idioma según el código ISO 639-1. Dentro de cada carpeta hay un fichero string.xlm donde está la misma etiqueta para cada idioma, pero con el texto correspondiente al idioma. Las etiquetas que se utilizarán en los idiomas que, serán las etiquetes del fichero de Strings de la carpeta por defecto values. Para especificar el idioma según la localización, diferenciando el inglés de Gran Bretanya (GB) del inglés de Australia (AU), las carpetas utilizan el formato values-xx-ryy donde YY utiliza el código ISO 3166-1: <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">canvi_idioma</string> <string name="action_settings">ajustes</string> <string name="hello_world">hola Mundo!</string> <string name="imtrying">estoy probando</string> <string name="language">idioma Castellano</string> </resources> values-en-rgb.xml, values-en-rau.xml ca ISO 639-1 Català <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello_world">hola mon!</string> <string name="imtrying">estic provant</string> <string name="language">idioma Català</string> </resources> <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">change Language</string> <string name="action_settings">settings</string> <string name="hello_world">hello world!</string> <string name="imtrying">i\'m trying</string> <string name="language">english Language</string> </resources> es en eu fr de ga gl Castellà Anglés Eusquera Francés Alemany Irlandés Gallec

Aquí volvemos a pulsar el icono del globo terráqueo y nos aparece un listado con los diferentes idiomas disponibles. Seleccionamos el que queremos y se añadirá a la lista del editor de las traducciones. Internacionalización Android Studio En Android Studio se facilita la internacionalización de idioma. En la pantalla de diseño de la interfície, pulsamos sobre el icono del globo terráqueo y seleccionamos Edit Translations.

Internacionalización Android Studio En el editor nos aparecerá la variable ( Key ) del texto, el valor por defecto, y podremos introducir la correspondiente traducción en cada idioma. En la estructura del proyecto aparecerá un fichero string.xml para cada uno de los idiomas, y en la carpeta real del proyecto, aparecerá una carpeta para cada idioma con el formato values-xx donde XX es la abreviatura del idioma según el código ISO 639-1. Dentro de cada carpeta hay un fichero string.xlm donde está la misma etiqueta para cada idioma, pero con el texto correspondiente al idioma

Almacenamiento de datos Android nos facilita varias posibilidades para almacenar datos permanentemente para que no se borren cuando se apague la aplicación. Los principales métodos proporcionados son: Classe SharedPreferences: Para una cantidad limitada de datos como configuraciones de las aplicaciones, puntos o niveles de un juego, etc... Archivos de Texto: Para una mayor cantidad de datos, que se guardará en una archivo en el almacenamiento interno del dispositivo o la tarjeta SD Bases de datos: Para almacenar datos en forma organizada utilizando bases de datos basadas en SQL Lite. XML: Archivo de texto en formato XML. Utiliza SAX o DOM. Proveedores de contenidos: Ex. Contactes Internet: En la nube...

SharedPreferences Con la clase SharedPreferences, se pueden guardar conjuntos de datos en la memoria interna del dispositivo. Los datos quedan almacenadas incluso reiniciando el dispositivo, como datos de la aplicación. Hay varios modos de compartición de los datos: MODE_PRIVATE solo la aplicación puede acceder a los datos. Las siguientes están obsoletas y no se recomiendan actualmente. Aconsejan utilizar otros mecanismos como ContentProvider, BroadcastReceiver, o Service. MODE_WORLD_READABLE otras aplicaciones pueden acceder y leer los datos. (<API17) MODE_WORLD_WRITEABLE otras aplicaciones pueden acceder a los datos para leerlos y modificarlos. (<API17) MODE_MULTI_PROCESS varios procesos pueden acceder. (> API9, <API23) Crearemos una aplicación que nos permita leer y guardar un String (nom), un Integer (edat) y un Float (alçada), mediante dos botones.

SharedPreferences Guardamos los tres datos en el grupo datos en el MODE_PRIVATE para que solo la aplicación pueda tener acceso. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var Nom:EditText=findViewById(R.id.nom) var Edat:EditText=findViewById(R.id.edat) var Alcada:EditText=findViewById(R.id.alcada) val btllegeix:button=findviewbyid(r.id.llegeix) val btguarda:button=findviewbyid(r.id.guarda) btllegeix.setonclicklistener(view.onclicklistener { var llegeixprefe: SharedPreferences=getSharedPreferences("dades", Context.MODE_PRIVATE) Nom.setText(llegeixprefe.getString("nomguarda","")) Edat.setText(llegeixprefe.getInt("edatguarda",0).toString()) Alcada.setText(llegeixprefe.getFloat("alcadaguarda",0f).toString()) ) btguarda.setonclicklistener(view.onclicklistener { var escriureprefe: SharedPreferences=getSharedPreferences("dades", Context.MODE_PRIVATE) var editor:sharedpreferences.editor=escriureprefe.edit() editor.putstring("nomguarda",nom.text.tostring()) editor.putint("edatguarda",edat.text.tostring().toint()) editor.putfloat("alcadaguarda",alcada.text.tostring().tofloat()) editor.apply() )

Preference Activity Como a alternativa a introducir datos SharedPreferences, podemos utilizar una PreferenceActivity para mostrar una pantalla para la introducción de los datos. (En las nuevas APIs comienza a estar en desuso) Primero crear la carpeta /res/xml si no existe. Pulsando sobre la nueva carpeta xml con el botón derecho, crear un nuevo fichero.xml de tipo Resource Type: New XML resource file. Aparece un elemento PreferenceScreen Dentro del elemento principal, podemos separar las preferéncias en categorías, y añadir diferentes elementos. Entre otros, podemos tener: CheckBoxPreference: Selección de verdadero o falso EditTextPreference: Texto simple (pueden ser números) ListPreference: Selección de un valor de una lista En nuestro ejemplo, añadimos dos categorias. En la primera un CheckBoxPreference y un EditTextPreference, y en la segunda un ListPreference y un CheckBoxPreference. A continuación, en la siguiente diapositiva, crearemos el fichero con la lista de valores que solicita el ListPreference.

Preference Activity Para los valores de la lista, crearemos un nuevo fichero xml de valores. Sobre la carpeta vàlues, polsar con el botón derecho New Values resource file Añadimos 2 Strings Arrays y los diferentes elementos de la lista <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="acronim"> <item>prdm</item> <item>audi</item> <item>siop</item> <item>siac</item> </string-array> <string-array name="asignatura"> <item>programació de Dispositius Mòbils</item> <item>automatització i Digitalització Industrial</item> <item>simulació i Optimització</item> <item>sistemes Avançats de Control</item> </string-array> </resources>

Preference Activity Ahora podemos introducir todos los parámetros y etiquetas al fichero de preferencias. La etiqueta key indica la variable o propiedad donde se guardará el valor de la preferencia. La etiqueta title indica texto del título de la preferencia. La etiqueta summary indica la descripción de la preferencia. En la lista las etiquetas entries indica la lista de valores, de los cuales el seleccionado se guardará, y entryvalues la descripción. <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="primera Categoría"> <CheckBoxPreference android:defaultvalue="false" android:key="check1" android:summary="descripción del primer check" android:title="titol check 1" /> <EditTextPreference android:defaultvalue="default value" android:key="texte1" android:selectallonfocus="true" android:singleline="true" android:summary="escribe alguna cosa" android:title="títol Edit Text" /> </PreferenceCategory> <PreferenceCategory android:title="segunda Categoria"> <ListPreference android:defaultvalue="1" android:entries="@array/asignatura" android:entryvalues="@array/acronim" android:key="llista" android:summary="selecciona una opción de la lista" android:title="lista de valores" /> <CheckBoxPreference android:defaultvalue="false" android:key="check2" android:summary="clica para cambiar" android:title="check box preference" /> </PreferenceCategory> </PreferenceScreen>

Preference Activity Para mostrar la pantalla de preferencias, creamos una nueva clase en el proyecto (New Kotlin File/Class) que sea una extensión de la clase PreferenceActivity. En ella añadimos el método oncreate() y enlazamos el fichero de preferencias con el método addpreferencesfromresource(). package edu.upc.epsevg.prdm.kotlindatospreferenceactivity import android.os.bundle import android.preference.preferenceactivity /** * Created by Cristu on 28/02/2018. */ class PantallaOpcions: PreferenceActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) addpreferencesfromresource(r.xml.opcions) Hemos de añadir la nueva Actividad al fichero AndroidManifest.xml </activity> <activity android:name=".pantallaopcions"></activity> </application> </manifest>

Preference Activity Ya tenemos configurada la parte de las preferencias. Ahora configuramos la actividad principal del ejemplo creando un Layout con dos botones (para leer y escribir las preferencias) y un texto (para mostrar las preferencias leídas). Para que aparezca la pantalla de preferencias creamos un Intent a la Activitat creada, y para leer las preferencias, utilizamos el objeto SharedPreferences package edu.upc.epsevg.prdm.kotlindatospreferenceactivity import android.content.intent import android.content.sharedpreferences import android.support.v7.app.appcompatactivity import android.os.bundle import android.preference.preferencemanager import android.view.view import android.widget.button import android.widget.textview class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var dades:textview=findviewbyid(r.id.textview1) var llegir:button=findviewbyid(r.id.button1) var escriure:button=findviewbyid(r.id.button2) escriure.setonclicklistener(view.onclicklistener { var i= Intent(this@MainActivity,PantallaOpcions::class.java) startactivity(i) ) llegir.setonclicklistener(view.onclicklistener { var preferencies:sharedpreferences=preferencemanager.getdefaultsharedpreferences(this@mainactivity) dades.text="opció check1 = "+preferencies.getboolean("check1",false)+ "\nopció texte1 = "+preferencies.getstring("texte1","")+ "\nopció llista = "+preferencies.getstring("llista","")+ "\nopció check2 = "+preferencies.getboolean("check2",false) )

SettingsActivity El uso de una PreferenceActivity ya no se recomiendan ya que existen mejores alternativas que facilitan la interacción con el usuario. Coma alternativa equivalente, Android Studio proporciona la SettingsActivity. Creamos un nuevo proyecto con la actividad principal, y añadimos una nueva actividad del tipo SettingsActivity. Al configurar los parámetros de la nueva actividad, añadimos en Hierarchical Parent, la actividad principal para que al pulsar la flecha de volver que aparece en la actividad de configuración, vuelva a la principal.

SettingsActivity Nos creará un fichero kotlin con unos apartados de ejemplo por defecto que podemos utilizar de base, unos ficheros xml para configurar la key y los parámetros de configuración, y dentro del fichero strings.xml las listas y sus elementos para seleccionar. strings.xml

SettingsActivity Para añadir un nuevo ítem al menú general, creamos un nuevo fichero.xml del tipo PreferenceScreen, y le añadimos los campos deseados. Importante indicar el key ya que es la referencia al dato guardado. <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to dismiss it. --> <!-- NOTE: ListPreference's summary should be set to its value by the activity code. --> <!-- This preference simply launches an intent when selected. Use this UI sparingly, per design guidelines. --> <EditTextPreference android:selectallonfocus="true" android:singleline="true" android:title="nombre" android:key="nomsh" android:inputtype="textpersonname" /> <EditTextPreference android:selectallonfocus="true" android:singleline="true" android:title="edad" android:key="edatsh" android:inputtype="number" /> </PreferenceScreen>

SettingsActivity Para añadir datos propios, añadimos al fichero SettingsActivity.kt una nueva clase PreferenceFragment con la nueva referencia del fichero xml, e indicando las nuevas keys, y modificamos el método isvalidfragment() añadiendo la nueva clase. override fun isvalidfragment(fragmentname: String): Boolean { return PreferenceFragment::class.java.name == fragmentname GeneralPreferenceFragment::class.java.name == fragmentname DataSyncPreferenceFragment::class.java.name == fragmentname NotificationPreferenceFragment::class.java.name == fragmentname MisdatosPreferenceFragment::class.java.name==fragmentName /** * This fragment shows general preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) class MisdatosPreferenceFragment : PreferenceFragment() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) addpreferencesfromresource(r.xml.pref_misdatos) sethasoptionsmenu(true) // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindpreferencesummarytovalue(findpreference("nomsh")) bindpreferencesummarytovalue(findpreference("edatsh")) override fun onoptionsitemselected(item: MenuItem): Boolean { val id = item.itemid if (id == android.r.id.home) { startactivity(intent(activity, SettingsActivity::class.java)) return true return super.onoptionsitemselected(item)

SettingsActivity Al fichero pref_headers.xml le añadimos el elemento PrefefenceFragment creado con el icono y el título que queramos. <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <!-- These settings headers are only used on tablets. --> <header android:fragment="edu.upc.epsevg.esaii.prdm.sharedpref.settingsactivity$generalpreferencefragment" android:icon="@drawable/ic_info_black_24dp" android:title="@string/pref_header_general" /> <header android:fragment="edu.upc.epsevg.esaii.prdm.sharedpref.settingsactivity$notificationpreferencefragment" android:icon="@drawable/ic_notifications_black_24dp" android:title="@string/pref_header_notifications" /> <header android:fragment="edu.upc.epsevg.esaii.prdm.sharedpref.settingsactivity$datasyncpreferencefragment" android:icon="@drawable/ic_sync_black_24dp" android:title="@string/pref_header_data_sync" /> <header android:fragment="edu.upc.epsevg.esaii.prdm.sharedpref.settingsactivity$misdatospreferencefragment" android:icon="@drawable/ic_sync_black_24dp" android:title="mis Datos" /> </preference-headers>

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.esaii.kotlindatossettingsactivity.mainactivity"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="configura preferencies" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="llegeix Preferencies" tools:layout_editor_absolutex="146dp" tools:layout_editor_absolutey="288dp" /> <TextView android:id="@+id/nom" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="textview" /> <TextView android:id="@+id/edat" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="textview" /> </LinearLayout>

SettingsActivity Para llamar a la activitat SettingsActivity utilitzamos un Intent en la actividad principal, y para leer los datos guardados, utilizamos un objeto SharedPreferences indicando las keys a leer. class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var Nom:TextView=findViewById(R.id.nom) var Edat:TextView=findViewById(R.id.edat) var btconfigura:button=findviewbyid(r.id.button) btconfigura.setonclicklistener(view.onclicklistener { var i:intent = Intent (this@mainactivity,settingsactivity::class.java) startactivity(i) ) var btleepref:button=findviewbyid(r.id.button2) btleepref.setonclicklistener(view.onclicklistener { var leeshpr:sharedpreferences =PreferenceManager.getDefaultSharedPreferences(this@MainActivity) Nom.text=leeshpr.getString("nomsh","") Edat.text=leeshpr.getString("edatsh","0") ) @+id/button Layout del MainActivity @+id/nom @+id/edat @+id/button2

Archivos de texto internos Otra alternativa para almacenar datos, es mediante ficheros de texto en la memoria de almacenamiento interna del dispositivo. Suelen ser ficheros privados de la aplicación que se almacenan a la carpeta privada /data/data/nombre.proyecto.aplicacion/files, o en la carpeta del usuario /data/user/0/nombre.proyecto.aplicacion/files. Crearemos una aplicación que nos permitan leer y guardar un fichero de texto. Creamos un TextView, un EditText y un botón. El EditText lo configuramos multi-línea y para que muestre la barra vertical de desplazamiento. <EditText android:id="@+id/textev" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentleft="true" android:layout_below="@+id/textview1" android:ems="10" android:inputtype="textmultiline" android:lines="6" android:scrollbars="vertical" > <requestfocus /> </EditText>

Archivos de texto internos En el código se verifica si existe el fichero; si existe lo lee y muestra el contenido para modificarlo. Al pulsar el botón, se graba el texto en el fichero. class MainActivity : AppCompatActivity() { lateinit var texte: EditText lateinit var grava: Button override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) var carpeta = findviewbyid(r.id.textview1) as TextView texte = findviewbyid(r.id.textev) as EditText grava = findviewbyid(r.id.grava) as Button val archivos :Array<String> = filelist() carpeta.text = filesdir.tostring() if (existeixfitxer(archivos, "notas.txt")) llegeixfitxer("notas.txt") grava.setonclicklistener(view.onclicklistener { gravafitxer("notas.txt") ) private fun existeixfitxer(archivos: Array<String>, archbusca: String): Boolean { for (f in archivos.indices) if (archbusca == archivos[f]) return true return false fun llegeixfitxer(nomarx:string){ try { val archivo = InputStreamReader(openFileInput(nomarx))

Archivos de texto internos fun llegeixfitxer(nomarx:string){ try { val archivo = InputStreamReader(openFileInput(nomarx)) val br = BufferedReader(archivo) var linea: String? = br.readline() var todo = "" while (linea!= null) { todo = todo + linea + "\n" linea = br.readline() br.close() archivo.close() texte.settext(todo) catch (e: IOException) { // No gestionamos errores fun gravafitxer(nomarx: String) { try { val archivo = OutputStreamWriter(openFileOutput(nomarx, Activity.MODE_PRIVATE)) archivo.write(texte.text.tostring()) archivo.flush() archivo.close() catch (e: IOException) { val t = Toast.makeText(this, "Les dades s han gravat", Toast.LENGTH_SHORT) t.show()

Archivos de texto internos El TextView se ha añadido para indicar la carpeta interna donde se graba el fichero : Para comprobarlo, necesitamos poner en marcha el Android Device Monitor, que nos permite interactuar con parámetros internos del emulador. Entonces podemos buscar y ver en el apartado File Explorer donde se ha grabado el fichero. Activar antes Enable ADB Integration

Archivos de texto en SD También se pueden almacenar ficheros de texto en la memoria SD del dispositivo, que no necesariamente ha de ser una tarjeta SD. Los ficheros son accesibles desde cualquier aplicación. Crearemos una aplicación que nos permita leer y guardar un fichero de texto a la SD. Creamos un TextView, dos EditText y dos botones. Modificamos los permisos en el fichero AndroidManifest.xml para poder escribir en la SD: </application> <uses-permission android:name="android.permission.write_external_storage" /> </manifest>

Archivos de texto en SD En el código, al pulsar en el botón de grabar, lee la carpeta por y graba los datos. class MainActivity : AppCompatActivity() { lateinit var nomfitxer: EditText lateinit var dades: EditText lateinit var gravar: Button lateinit var llegir: Button val PIDE_PERMISO:Int=1714 override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) nomfitxer = findviewbyid(r.id.nomf) dades = findviewbyid(r.id.textev) gravar = findviewbyid(r.id.grava) llegir = findviewbyid(r.id.llegeix) gravar.setonclicklistener { val nomarxiu = nomfitxer.text.tostring() val dadesfitxer = dades.text.tostring() Log.e("SD","gravant") if (ActivityCompat.checkSelfPermission(this,android.Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, arrayof<string>(android.manifest.permission.write_external_storage),pide_permiso) else { try { val carpeta = Environment.getExternalStorageDirectory() val file = File(carpeta.absolutePath, nomarxiu) val osw = OutputStreamWriter(FileOutputStream(file)) osw.write(dadesfitxer) osw.flush() osw.close() Toast.makeText(this@MainActivity, "Datos grabados en "+carpeta.tostring(), Toast.LENGTH_SHORT).show()

Archivos de texto en SD Al pulsar el botón de leer, lee la carpeta por defecto y lee línea a línea. osw.write(dadesfitxer) osw.flush() osw.close() Toast.makeText(this@MainActivity, "Datos grabados en "+carpeta.tostring(), Toast.LENGTH_SHORT).show() dades.settext("") catch (ioe: IOException) { Toast.makeText(this@MainActivity, ioe.message, Toast.LENGTH_SHORT).show() llegir.setonclicklistener { val nomarxiu = nomfitxer.text.tostring() val carpeta = Environment.getExternalStorageDirectory() val file = File(carpeta.absolutePath, nomarxiu) try { val fin = FileInputStream(file) val archivo = InputStreamReader(fIn) val br = BufferedReader(archivo) var linea: String? = br.readline() var todo = "" while (linea!= null) { todo = todo + linea + "" linea = br.readline() br.close() archivo.close() dades.settext(todo) catch (e: IOException) { Toast.makeText(this@MainActivity, e.message, Toast.LENGTH_SHORT).show()

Archivos de texto en SD Como alternativas a grabar el fichero en una carpeta diferente, podemos tener (entre otras) estas: La carpeta de almacenamiento por defecto: /mnt/sdcard val carpeta = Environment.getExternalStorageDirectory() val file = File(carpeta.getAbsolutePath(), nomarxiu) Directamente indicar una carpeta: /mnt/sdcard/download val file = File("/mnt/sdcard/Download", nomarxiu) Indicar la carpeta a partir del camino por defecto: /mnt/sdcard/download val targeta = Environment.getExternalStorageDirectory() val file = File(targeta.absolutePath + "/Download", nomarxiu) Indicar la carpeta per defecto para un determinado tipo: /mnt/sdcard/download val targeta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val file = File(targeta.absolutePath, nomarxiu) En caso de utilizar una tarjeta externa tipo microsd, el camino cambia a /mnt/extsdcard. Se puede comprobar el estado (o existencia) de las carpetas con el método Environment.getExternalStorageState()

Path por defecto del sistema A continuación se enumeran los caminos por defecto del sistema Android, pero estos pueden ser otros en función de la versión del sistema y el usuario Method Environment.getDataDirectory() Environment.getDownloadCacheDirectory() Environment.getRootDirectory() Environment.getExternalStorageDirectory() Environment.getExternalStoragePublicDirectory(DIRECTORY_ALARMS) Environment.getExternalStoragePublicDirectory(DIRECTORY_DCIM) Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS) Environment.getExternalStoragePublicDirectory(DIRECTORY_MOVIES) Environment.getExternalStoragePublicDirectory(DIRECTORY_MUSIC) Environment.getExternalStoragePublicDirectory(DIRECTORY_NOTIFICATIONS) Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES) Environment.getExternalStoragePublicDirectory(DIRECTORY_PODCASTS) Environment.getExternalStoragePublicDirectory(DIRECTORY_RINGTONES) Resultat /data /cache /system /storage/sdcard0 /storage/sdcard0/alarms /storage/sdcard0/dcim /storage/sdcard0/download /storage/sdcard0/movies /storage/sdcard0/music /storage/sdcard0/notifications /storage/sdcard0/pictures /storage/sdcard0/podcasts /storage/sdcard0/ringtones

Path per defecto de aplicaciones Method getcachedir() getfilesdir() getfilesdir().getparent() getexternalcachedir() getexternalfilesdir(null) getexternalfilesdir(directory_alarms) getexternalfilesdir(directory_dcim) getexternalfilesdir(directory_downloads) getexternalfilesdir(directory_movies) getexternalfilesdir(directory_music) getexternalfilesdir(directory_notifications) getexternalfilesdir(directory_pictures) getexternalfilesdir(directory_podcasts) getexternalfilesdir(directory_ringtones) Resultat /data/data/package/cache /data/data/package/files /data/data/package /storage/sdcard0/android/data/package/cache /storage/sdcard0/android/data/package/files /storage/sdcard0/android/data/package/files/alarms /storage/sdcard0/android/data/package/files/dcim /storage/sdcard0/android/data/package/files/download /storage/sdcard0/android/data/package/files/movies /storage/sdcard0/android/data/package/files/music /storage/sdcard0/android/data/package/files/notifications /storage/sdcard0/android/data/package/files/pictures /storage/sdcard0/android/data/package/files/podcasts /storage/sdcard0/android/data/package/files/ringtones

Bases de datos internas SQL Lite Otra opción para almacenar datos, es utilizar bases de datos internas mediante comandos SQL. Crearemos una actividad que nos permita almacenar teléfonos de contactos. La base de datos la llamaremos DadesContacte.db con una tabla llamada contactes, que contendrá los campos nom, telefon, mail i categoria.

Bases de datos internas SQL Lite Antes de escribir el código kotlin necesitamos crear una clase heredera de SQLiteOpenHelper, para que permita crear y modificar la estructura de la Base de datos. import android.content.context import android.database.sqlite.sqlitedatabase import android.database.sqlite.sqliteopenhelper class GestorSQLiteOpenHelper(context: Context, name: String, factory: SQLiteDatabase.CursorFactory?, version: Int): SQLiteOpenHelper(context, name, factory, version) { // SQLiteOpenHelper(context, name, factory, version) es el contructor de la clase padre // oncreate se ejecuta al crear la base de datos override fun oncreate(db: SQLiteDatabase?) { if (db!= null) { db.execsql("create TABLE contactes (nom TEXT, telefon INTEGER, mail TEXT, categoria TEXT)") // onupgrade se ejecuta al actualizar la estructura de la base de datos. // En el ejemplo se borra y se vuelve a crear nueva override fun onupgrade(db: SQLiteDatabase?, oldversion: Int, newversion: Int) { if (db!= null) { db.execsql("drop TABLE IF EXISTS contactes") db.execsql("create TABLE contactes (nom TEXT, telefon INTEGER PRIMARY KEY, mail TEXT, categoria TEXT)")

Bases de datos internas SQL Lite En la primera parte del código realizamos los enlaces entre el Layout y los objetos, y asignamos las acciones correspondientes a los botones, además creamos la constante con el nombre de la base de datos nombase= DadesContacte.db class MainActivity : AppCompatActivity() { lateinit var nom: EditText lateinit var telefon: EditText lateinit var email: EditText lateinit var categoria: EditText lateinit var balta: Button lateinit var bbaixa: Button lateinit var bmodifica: Button lateinit var bconsulta: Button lateinit var totalregbd: TextView val nombase="dadescontacte.db" override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) nom = findviewbyid(r.id.editnom) telefon = findviewbyid(r.id.editelefon) email = findviewbyid(r.id.editmail) categoria = findviewbyid(r.id.editcateg) balta = findviewbyid(r.id.buttonalta) bbaixa = findviewbyid(r.id.buttonbaixa) bmodifica = findviewbyid(r.id.buttonmod) bconsulta = findviewbyid(r.id.buttoncons) totalregbd = findviewbyid(r.id.totalregbd) balta.setonclicklistener(view.onclicklistener { alta() ) bconsulta.setonclicklistener(view.onclicklistener { sigue después

Bases de datos internas SQL Lite Tras las acciones de los botones, añadimos una función que permitirá realizar una consulta del total de registros que contiene la bases de datos mediante el comando SQL: SELECTcount(*) FROM tabla continua de código anterior bconsulta = findviewbyid(r.id.buttoncons) totalregbd = findviewbyid(r.id.totalregbd) balta.setonclicklistener(view.onclicklistener { alta() ) bconsulta.setonclicklistener(view.onclicklistener { consultatlf() ) bmodifica.setonclicklistener(view.onclicklistener { modifica() ) bbaixa.setonclicklistener(view.onclicklistener { baixatlf() ) fun totalregistres(db: SQLiteDatabase): String { val statement = db.compilestatement("select count(*) FROM contactes") val contador = statement.simplequeryforlong() return contador.tostring() fun alta(){ val gestor=gestorsqliteopenhelper(this,nombase,null,1) val bd=gestor.writabledatabase val bdnom=nom.text.tostring() sigue después

Bases de datos internas SQL Lite Continuamos con las diferente funciones. La función alta() guarda todos los campos en la tabla contactes de la base de dato DadesContacte.db : continua de código anterior return contador.tostring() fun alta(){ val gestor=gestorsqliteopenhelper(this,nombase,null,1) val bd=gestor.writabledatabase val bdnom=nom.text.tostring() val bdtelefon=telefon.text.tostring().toint() val bdmail=email.text.tostring() val bdcategoria=categoria.text.tostring() val registre=contentvalues() registre.put("nom",bdnom) registre.put("telefon",bdtelefon) registre.put("mail", bdmail) registre.put("categoria", bdcategoria) bd.insert("contactes", null, registre) totalregbd.settext("total Registres " + totalregistres(bd)) bd.close() nom.settext("") telefon.settext("") email.settext("") categoria.settext("") Toast.makeText(this, "Dades guardades", Toast.LENGTH_SHORT).show() fun consultatlf(){ //Consulta por telefono val gestor = GestorSQLiteOpenHelper(this,nombase,null,1) sigue después

Bases de datos internas SQL Lite Continuamos con las diferentes funciones. La función consultatlf() busca el contacto que tinga el número de teléfono indicado: continua de código anterior Toast.makeText(this, "Dades guardades", Toast.LENGTH_SHORT).show() fun consultatlf(){ //Consulta por telefono val gestor = GestorSQLiteOpenHelper(this,nombase,null,1) val bd = gestor.getwritabledatabase() val bdtelefon = Integer.valueOf(telefon.getText().toString()) val fila = bd.rawquery("select nom, mail,categoria FROM contactes WHERE telefon=$bdtelefon", null) if (fila.movetofirst()){ nom.settext(fila.getstring(0)) email.settext(fila.getstring(1)) categoria.settext(fila.getstring(2)) else Toast.makeText(this, "No existeix el telefon", Toast.LENGTH_SHORT).show() fun baixatlf(){ // Baja por telefono val gestor = GestorSQLiteOpenHelper(this, nombase, null, 1) sigue después

Bases de datos internas SQL Lite Continuamos con las diferentes funciones. La función baixatlf() borra el contacto con el número de teléfono indicado: continua de código anterior Toast.makeText(this, "No existeix el telefon", Toast.LENGTH_SHORT).show() fun baixatlf(){ // Baja por telefono val gestor = GestorSQLiteOpenHelper(this, nombase, null, 1) val bd = gestor.getwritabledatabase() val bdtelefon = telefon.text.tostring().toint() val err = bd.delete("contactes", "telefon="+bdtelefon, null) //val err = bd.delete("contactes", "telefon=$bdtelefon", null) //También válido totalregbd.text="total Registres"+totalregistres(bd) bd.close() if (err == 1){ nom.settext("") telefon.settext("") email.settext("") categoria.settext("") Toast.makeText(this, "S'ha esborrat el contacte", Toast.LENGTH_SHORT).show() else Toast.makeText(this, "No existeix el contacte", Toast.LENGTH_SHORT).show() fun modifica(){ val gestor = GestorSQLiteOpenHelper(this, nombase, null, 1) sigue después

Bases de datos internas SQL Lite Finalizamos con la función modifica() que modifica el contacto con el número de teléfono indicado, con los datos actuales: continua de código anterior Toast.makeText(this, "No existeix el contacte", Toast.LENGTH_SHORT).show() fun modifica(){ val gestor = GestorSQLiteOpenHelper(this, nombase, null, 1) val bd = gestor.getwritabledatabase() val bdnom=nom.text.tostring() val bdtelefon=telefon.text.tostring().toint() val bdmail=email.text.tostring() val bdcategoria=categoria.text.tostring() val registre=contentvalues() registre.put("nom",bdnom) registre.put("telefon",bdtelefon) registre.put("mail", bdmail) registre.put("categoria", bdcategoria) val err = bd.update("contactes", registre, "telefon=$bdtelefon", null) bd.close() if (err == 1) Toast.makeText(this, "S'ha modificat el contacte", Toast.LENGTH_SHORT).show() else Toast.makeText(this, "No existeix el contacte", Toast.LENGTH_SHORT).show()

Bases de datos internas SQL Lite Desde el emulador, o si tenemos acceso root en el dispositivo, podemos ver que la la base de datos se guarda en la carpeta: /data/data/nombre.aplicación/database Si extraemos el fichero de la base de datos, podemos ver el contenido mediante programas adecuadoscomo DB Browser for SQLite (http://sqlitebrowser.org/) Con el mismo programa, también podemos preparar la base de datos desde el ordenador, y añadir la base de datos creada al proyecto Android para su uso. En el siguiente enlace podemos ver un ejemplo: http://www.javahelps.com/2015/04/import-and-use-external-database-in.html

Android Varios Cristobal Raya Giner Programació de Dispositius Mòbils (PRDM)

Log para depuración Los Logs, sirven para mostrar mensajes durante la depuración de las aplicaciones en Android Studio en la ventana LogCat. Según el tipo de Log indicado (e,w,i,d,v,wtf), aparece el mensaje en un color diferente. El Tag de la instrucción import android.support.v7.app.appcompatactivity import android.os.bundle import android.util.log class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) Log.wtf("Tag del log","mensaje de error grave (What a Terrible Failure)") Log.e("Tag del Log", "Mensaje de error (ERROR)") Log.w("Tag del Log", "Mensaje de alarma (WARN)") Log.i("Tag del Log", "Mensaje de información (INFO)") Log.d("Tag del Log", "Mensaje de depuración (DEBUG)") Log.v("Tag del Log", "Mensaje de visualización (VERBOSE)") Log, sirve para poder agrupar y filtrar los diferentes mensajes.

Gestión de errores Para gestionar los errores en tiempo de ejecución de una aplicación, y evitar que aparezca una ventana indicando error y finalice la aplicación, podemos capturar los errores con las sentencias try, catch, finally. Se comienza con la sentencia try, donde se ubica el código normal a ejecutar donde se puede producir el error. Seguidamente podemos tener una o varias sentencias catch, donde en función del tipo de error se ejecutaré el código correspondiente a la gestión del error. Finalmente, y de forma opcional, la sentencia finally permite ejecutar un código independientemente de si ha habido error, después de la captura del error. try { // Código normal a executar catch (e:ioexception) { // Código en caso de IOException catch (e:malformedurlexception) { // Código en caso de MalformedURLException catch (e:exception) { // Código en caso de Exception generica catch (e: OtrosTiposDeExcepcion) { // Código en cas de otro tipo de Exception.... finally { // Código a ejecutar independentemente de si hay o no error

Notificaciones A partir de la API 26 (Android 8.0), se ha de crear primero un canal de notificaciones para incluir las notificaciones en el. Se ha de añadir el fichero del icono si queremos mostrarlo, con un tamaño de 32x32. class MainActivity : AppCompatActivity() { lateinit var notificationmanager:notificationmanager lateinit var notificationchannel: NotificationChannel lateinit var notificationbuilder: NotificationCompat.Builder val NOTIFICATION_CHANNEL_ID:String="Canal 1" override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val boton:button=findviewbyid(r.id.button) notificationmanager=getsystemservice(context.notification_service) as NotificationManager if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ //Necesario para compatibilidad API>=26 notificationchannel= NotificationChannel(NOTIFICATION_CHANNEL_ID,"Canal Notificaciones", NotificationManager.IMPORTANCE_HIGH) // Configura el canal de notificaciones. Según que dispositivo, el color de las luces no cambia notificationchannel.description="canal unico" notificationchannel.enablelights(true) notificationchannel.lightcolor= Color.argb(255,255,0,255) notificationchannel.vibrationpattern= longarrayof(0,1000,500,1000) notificationchannel.enablevibration(true) notificationmanager.createnotificationchannel(notificationchannel) notificationbuilder=notificationcompat.builder(this,notification_channel_id) notificationbuilder.setdefaults(notification.default_all) //Configura inicialmente opciones por defecto.setautocancel(true) //Se desactiva cuando el usuario la quita del panel.setwhen(system.currenttimemillis()) //La notificación se muestra inmediatamente sigue después

Notificaciones sigue antes notificationbuilder=notificationcompat.builder(this,notification_channel_id) notificationbuilder.setdefaults(notification.default_all) //Configura inicialmente opciones por defecto.setautocancel(true) //Se desactiva cuando el usuario la quita del panel.setwhen(system.currenttimemillis()) //La notificación se muestra inmediatamente.setsmallicon(r.drawable.logo_epsevg) //logo 32x32.setContentTitle("Título de la notificación").setcontenttext("texto de la noficicación inicial").setcolor(color.green) notificationmanager.notify(1,notificationbuilder.build()) boton.setonclicklistener(view.onclicklistener { notificationbuilder.setcontenttext("notificación inicial modificada") notificationmanager.notify(1,notificationbuilder.build()) notificationbuilder.setcontenttext("esta es una nueva notificación").setsubtext("subtexto junto a nombre aplicación").setcolor(color.red) notificationmanager.notify(2,notificationbuilder.build()) ) Antes de pulsar el botón Después de pulsar el botón

Reproducción de sonidos Android puede reproducir por defecto ficheros de sonido del tipo mp3, ogg y wav. Los ficheros de sonido se han de encontrar en la carpeta /res/raw, y el nombre solo puede contener letras minúsculas de (a-z), números (0-9) y el guion bajo (_). Para la reproducción de un sonido se utiliza la librería android.media.mediaplayer: class MainActivity : AppCompatActivity() { override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val boton: Button =findviewbyid(r.id.button1) boton.setonclicklistener(view.onclicklistener { sonidotada() ) fun sonidotada(){ val mp = MediaPlayer.create(this, R.raw.tada) mp.start()

fun pausa(){ if (mp!=null && mp.isplaying){ posicion=mp.currentposition mp.pause() fun continua(){ Control de reproducción de sonido Se puede controlar cuando se inicia, se para, se pausa y se continua un archivo de sonido. class MainActivity : AppCompatActivity() { var posicion:int=0 var mp:mediaplayer=mediaplayer() override fun oncreate(savedinstancestate: Bundle?) { super.oncreate(savedinstancestate) setcontentview(r.layout.activity_main) val binici:button=findviewbyid(r.id.inici) val bpara:button=findviewbyid(r.id.para) val bpausa:button=findviewbyid(r.id.pausa) val bcontinua:button=findviewbyid(r.id.continua) binici.setonclicklistener(view.onclicklistener { iniciar() ) bpara.setonclicklistener(view.onclicklistener { parar() ) bpausa.setonclicklistener(view.onclicklistener { pausa() ) bcontinua.setonclicklistener(view.onclicklistener { continua() ) fun iniciar(){ if (mp!=null){ mp.release() mp=mediaplayer.create(this,r.raw.balkan_brass_gummy_bear) mp.start() mp.islooping=false