El objetivo de este tutorial es implementar de forma
sencilla un mecanismo de protección para nuestra aplicación, creando una ventana de “Login” con un nombre de usuario y una
contraseña. Esta dialogo de Login también podrá ser usado o para proteger cualquier opción de menú de la aplicación
- Desarrollaremos
el tutorial para un TABLET con la versión 4.0 del SDK de Android (Ice Cream
Sandwich). Válido también para Android 2.x y 3.x.
- Veremos
cómo trabajar con las opciones de MENU de la barra de tareas. Y también con las
PREFERENCES.
- Pondremos por defecto unas credenciales para acceder a las “Preferences” (usuario, contraseña), para comenzar a trabajar y después las podremos cambiarlas.
- Mostraremos el contenido de las PREFERNCES, en el lugar de su descripción, cosa que no hace Android por defecto.
- Veremos como añadir por código objetos (Layouts, TextView y EditText) a un AlertDialog, usando la propiedad Buider del AlertDialog.
Para este tutorial vamos a utilizar IntelliJ IDEA 11.1. Después de crear el proyecto tendríamos algo
parecido a esto:
2.- Creación de un Menú para acceder a las Preferences de Android.
Comenzaremos con la creación de un menú para poder acceder a
las PREFERENCES, para ello crearemos una nueva carpeta en nuestro proyecto
dentro “res” llamada menu y dentro creamos el archivo menu.xml
con el siguiente contenido:
Insertar en el archivo de recursos “res\values\strings.xml” las siguientes líneas con el valor de las etiquetas del menú:
Settings...
Login Settings
Nos quedaría el proyecto de la siguiente forma con nuestro menu.xml:
Después nos
vamos a la clase asociada a nuestra actividad principal (MyActivity) “src\com.movalink.LoginTutorial\MainActivity” para incluir el siguiente
procedimiento que hace un Override del existente.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
return true;
}
Lanzamos un
Emulador creado con la versión 4.0 de Android (Ice Cream Sandwich).
Ahora
ejecutamos la aplicación para que corra en el Emulador y vemos que en la
esquina superior derecha aparece un botón con tres puntos verticales, es la
opción de menú por defecto que nos muestra Android. Si pulsamos en ella vemos la
opción de menú que hemos creado.
3.- Trabajando con las Preferences.
El siguiente
paso, es crear dos campos en nuestras “Preferences” para poner el ellos el
nombre de usuario y la contraseña.
Lo primero
que debemos hacer es crear una carpeta en “res” con el nombre “xml” y dentro de ella
crearemos un archivo con formato XML llamado “settings.xml” al cual añadiremos
el siguiente contenido:
Las cadenas
de caracteres usadas en este archivo ej. "@string/username_settings_title", las declaramos con su valor en “res\values\strings.xml”:
Nombre de usuario
Teclee el nombre de usuario
Nombre de usuario
Contraseña
Teclee la contraseña
Contraseña
A
continuación crearemos la clase para manipular las “Preferences”, lo podemos
hacer con clic derecho en com.movalink.LoginTutorial , en el menú contextual
vamos a “New” y pulsamos “Android Component”
En la
carpeta ““src\com.movalink.LoginTutorial\” creamos una Activity y la llamamos
Preferences, que a su vez va a heredar de PreferenceActivity (Cambiamos
Activity por PreferenceActivity) e implementar el método SharedPreferences.OnSharedPreferenceChangeListener.
Nuestra clase “Preferences.java” quedaría de la siguiente manera:
package com.movalink.LoginTutorial;
import android.content.SharedPreferences;
import android.preference.PreferenceActivity;
public class Preferences extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
//En el método onCreate de la Activity hacemos referencia a nuestro archivo de settings.xml
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
A continuación crearemos dos constantes estáticas a nuestra clase
private static final String USERNAME_SETTINGS ="USERNAME_SETTINGS";
private static final String USERNAME_SETTINGS_DEFAULT = "admin";
private static final String PASSWORD_SETTINGS = "PASSWORD_SETTINGS";
private static final String PASSWORD_SETTINGS_DEFAULT ="1234";
Nota: Tener en cuenta que el
nombre de estas constantes es el mismo que “android:key="USERNAME_SETTINGS"” en
el archivo “settings.xml”
Como se puede observar los valores por defecto son
Username: admin
Password: 1234
Ahora crearemos dos métodos públicos para poder leer el nombre de
usuario y la contraseña que pondremos en las “Preferences”.
public static String getUsernameSettingsValue(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).
getString(USERNAME_SETTINGS, USERNAME_SETTINGS_DEFAULT);
}
public static String getPasswordSettingsValue(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).
getString(PASSWORD_SETTINGS, PASSWORD_SETTINGS_DEFAULT);
}
Ahora regresamos a nuestra actividad principal MainActivity, para sobrescribir
el método que nos permite capturar el evento de selección de las
opciones de Menu, en nuestro caso solo hemos creado la opción de Settings para
acceder a las “Preferences”. Como podemos ver al seleccionar Settings lo que
hacemos es llamar a la Acividad Prferences a través de su clase.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
startActivity(new Intent(getApplicationContext(), Preferences.class));
return true;
}
return false;
}
Hasta el momento nuestro Actividad principal (MyActivity), quedaría de la siguiente manera:
package com.movalink.LoginTutorial;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
public class MyActivity extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
startActivity(new Intent(getApplicationContext(), Preferences.class));
return true;
}
return false;
}
}
4.- Mostrando el contenido de las Preferences.
Ahora ejecutamos la aplicación para que corra en el Emulador, en la esquina superior derecha pulsamos el botón
de menú por defecto que nos muestra Android con nuestros “Settings”, y vemos
una nueva ventana con los dos parámetros que hemos creados, Nombre de Usuario y
Contraseña.
Si pulsamos, por ejemplo Nombre de Usuario, nos aparece un dialogo para
introducir la información correspondiente.
Tecleamos Nombre de Usuario: movalink, y pulsamos OK, como podemos
observar no se muestra la información, de momento solo es posible si volvemos a
pulsar en las preferences el Nombre de Usuario.
Con la contraseña hacemos el mismo proceso y tecleamos Contraseña: 1234
Como mostrar el contenido de nuestras Preferences.
Para mostrar en el lugar de la descripción el contenido de las
Preferecias, crearemos un par de métodos que nos ayudaran.
En nuestra clase “Preferences” adicionamos los siguientes métodos
privados
/**
* Set the summaries of all preferences
*/
private void initSummaries(PreferenceGroup pg) {
for (int i = 0; i < pg.getPreferenceCount(); ++i) {
Preference p = pg.getPreference(i);
if (p instanceof PreferenceGroup)
this.initSummaries((PreferenceGroup) p); // recursion
else
this.setSummary(p);
}
}
/**
* Set the summaries of the given preference
*/
private void setSummary(Preference pref) {
// react on type or key
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
if (pref instanceof EditTextPreference) {
EditTextPreference editPref = (EditTextPreference) pref;
pref.setSummary(editPref.getText());
}
}
Ahora en el método onCreate de la clase hacemos el llamado a estas dos
funciones, para asi mostrar en la descripción, el contenido de las Preferences.
this.initSummaries(this.getPreferenceScreen());
this.getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
Ejecutamos la aplicación y vamos al menú de nuestras “Preferences” y
podemos ver lo siguiente:
Así quedaría nuestra clase Preferences.java
package com.movalink.LoginTutorial;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.*;
public class Preferences extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String USERNAME_SETTINGS = "USERNAME_SETTINGS";
private static final String USERNAME_SETTINGS_DEFAULT = "admin";
private static final String PASSWORD_SETTINGS = "PASSWORD_SETTINGS";
private static final String PASSWORD_SETTINGS_DEFAULT = "1234";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
this.initSummaries(this.getPreferenceScreen());
this.getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
/**
* Set the summaries of all preferences
*/
private void initSummaries(PreferenceGroup pg) {
for (int i = 0; i < pg.getPreferenceCount(); ++i) {
Preference p = pg.getPreference(i);
if (p instanceof PreferenceGroup)
this.initSummaries((PreferenceGroup) p); // recursion
else
this.setSummary(p);
}
}
/**
* Set the summaries of the given preference
*/
private void setSummary(Preference pref) {
// react on type or key
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
if (pref instanceof EditTextPreference) {
EditTextPreference editPref = (EditTextPreference) pref;
pref.setSummary(editPref.getText());
}
}
public static String getUsernameSettingsValue(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).
getString(USERNAME_SETTINGS, USERNAME_SETTINGS_DEFAULT);
}
public static String getPasswordSettingsValue(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).
getString(PASSWORD_SETTINGS, PASSWORD_SETTINGS_DEFAULT);
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
5.- Iniciar la Aplicación con el diálogo de Usuario y Contraseña.
Una vez creadas nuestras credenciales en las “Preferences”, es el
momento de comenzar a usarlas.
La idea es que cuando arranque nuestra aplicación nos muestre un
dialogo con Usuario y Contraseña, para poder acceder a la misma.
Lo primero que haremos es crear las siguientes constantes y variables
privadas en nuestra actividad principal (MyActivity):
Estas constantes son para validar de acceso y almacenar el contenido de nuestras Preferences.
private static final int LOGIN_ACTION = 0;
private static final int SETTINGS_ACTION = 1;
private boolean validUser = false;
private String userNamePreferences;
private String passwordPreferences;
A continuación hacemos un override del método onStart(), y es aquí donde obtendremos los valores guardados en las “Preferences”. Llamaremos a la
función que nos muestra el Login, en este caso pasaremos la constante LOGIN_ACTION, ya que solo vamos a validar el usuario y la contraseña para acceder a la aplicación.
@Override
protected void onStart(){
super.onStart();
if (!validUser){
userNamePreferences = Preferences.getUsernameSettingsValue(this);
passwordPreferences = Preferences.getPasswordSettingsValue(this);
//Esta es la función que nos muestra el diálogo de Login
showAccessPopUpDialog(userNamePreferences, passwordPreferences, LOGIN_ACTION);
}
}
Este procedimiento showAccessPopUpDialog(…) nos permite proteger otras
opciones de menú de la aplicación. El procedimiento lo colocamos en muestra actividad principal (MyActivity).
Al final del tutorial se incluye el contenido de este procedimiento con todo los comentarios explicativos.
6.- Protegiendo las Preferences con el diálogo de Usuario y Contraseña
En el siguiente ejemplo vamos a proteger con usuario y contraseña el
acceso a las “Preferences”
Anteriormente se accedía directamente a las “Preferences” pulsando en
Settings…, como podemos ver hemos comentado el llamado directo y ahora utilizamos
showAccessPopUpDialog(userNamePreferences, passwordPreferences,
SETTINGS_ACTION);
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
//startActivity(new Intent(getApplicationContext(), Preferences.class));
//Show popup dialog to permit access to preferences
showAccessPopUpDialog(userNamePreferences, passwordPreferences, SETTINGS_ACTION);
return true;
}
return false;
}
A continuación mostramos el contenido de los procedimientos que hacen
posible el funcionamiento de nuestra LOGIN, ambos procedimientos debemos agregarlos a nuestra
actividad principal MyActivity. showAccessPopUpDialog(…) y loginAction(...)
Así quedaría nuestro dialogo de Login Access en Android
Procedimiento: showAccessPopUpDialog(…)
showAccessPopUpDialog(final String userName, final String password, final int action) y loginAction(int action)
private void showAccessPopUpDialog(final String userName, final String password, final int action) {
final AlertDialog.Builder helpBuilder = new AlertDialog.Builder(this);
helpBuilder.setTitle("Acceso a clientes");
helpBuilder.setMessage("Introduzca usario y contraseña");
helpBuilder.setIcon(R.drawable.key_stroke_32x32);
//Creamos un TextView para la etiqueta Usuario
final TextView LabelName = new TextView(this);
LabelName.setWidth(100);
LabelName.setText("Usuario:");
//Creamos un EditText para teclear el valor del campo Usuario
final EditText inputName = new EditText(this);
inputName.setSingleLine();
inputName.setWidth(150);
inputName.setInputType(InputType.TYPE_CLASS_TEXT);
inputName.setText("");
//Creamos un TextView para la etiqueta Contraseña
final TextView LabelPass = new TextView(this);
LabelPass.setWidth(100);
LabelPass.setText("Contraseña:");
//Creamos un EditText para teclear el valor del campo Contraseña
final EditText inputPass = new EditText(this);
inputPass.setSingleLine();
inputPass.setWidth(150);
inputPass.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
inputPass.setText("");
//Definimos parametros para luego aplicar al Layout
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
//Creamos un Layout comun para agrupar la entiqueta(TexView) y el campo (EditText)
//Tanto del Usuario como de la Contraseña
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setGravity(Gravity.CENTER_HORIZONTAL);
layout.setPadding(10,5,0,5);
//Creamos un Layout para agrupar la entiqueta(TexView) y el campo (EditText)
// del Usuario
LinearLayout layoutUser = new LinearLayout(this);
// Aplicamos los parámetros del layout a nuestros objectos
layoutUser.setLayoutParams(params);
layoutUser.addView(LabelName);
layoutUser.addView(inputName);
//Creamos un Layout para agrupar la entiqueta(TexView) y el campo (EditText)
//de la Contraseña
LinearLayout layoutPass = new LinearLayout(this);
// Aplicamos los parámetros del layout a nuestros objectos
layoutPass.setLayoutParams(params);
layoutPass.addView(LabelPass);
layoutPass.addView(inputPass);
//Adicionamos al LAyout comun los dos nuevos layouts
// el del Usuario y el de la Contraseña, creados anteriormente
layout.addView(layoutUser);
layout.addView(layoutPass);
//Adicionamos el layout comun al helpBuilder
helpBuilder.setView(layout);
helpBuilder.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Do nothing but close the dialog
String inputUserTxt = inputName.getText().toString();
String inputPasswordTxt = inputPass.getText().toString();
if (inputUserTxt.equals(userName) & inputPasswordTxt.equals(password)) {
//Seleccionamos la acción a ejecutar
loginAction(action);
} else {
Toast toast = Toast.makeText(getBaseContext(), "Usuario o Contraseña no válidos. Inténtelo otra vez", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
// Si la contraseña o el usuario no son válidos volvemos a motrar el diálogo
showAccessPopUpDialog(userNamePreferences,passwordPreferences,action);
}
}
});
helpBuilder.setNegativeButton("Cancelar", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Do nothing
finish();
}
});
// Crear el diálogo no lo muestra, hay que hacer el show()
AlertDialog helpDialog = helpBuilder.create();
// Deshabilitar hacer click fuera del diálogo
helpDialog.setCanceledOnTouchOutside(false);
//Mostrar el diálogo
helpDialog.show();
//Establecer ancho y alto
helpDialog.getWindow().setLayout(400, 410);
}
Procedimiento: loginAction(...)
protected boolean loginAction(int action){
switch (action) {
case LOGIN_ACTION:
validUser = true;
Toast toast = Toast.makeText(getBaseContext(), "USUARIO Y CONTRASEÑA CORRECTOS. (:", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return true;
case SETTINGS_ACTION:
//Preferences access
startActivity(new Intent(getApplicationContext(), Preferences.class));
return true;
default:
return false;
}
}
Para descargar el código fuente de la aplicación: LoginTutorial
Recordar que para acceder por primera vez debe teclear
USUARIO: admin
CONTRASEÑA: 1234