Bienvenidos sean a este post, hoy volveremos a nuestra aplicacion Mis Lugares, la cual hemos creado durante el tiempo que subi los posts de Android, si no lo tenes y queres hacerlo te recomiendo estos posts:

Anuncios

Hasta aca lo hemos probado, por lo menos en mis posts, en un Android por debajo de MarshMallow (la version 6.0) pero que sucede cuando lo necesitemos probar en este S.O. o superior nos devolvera el siguiente mensaje:

Esto es debido a que debemos concederle dos permisos, a partir de la version 6.0 los permisos definidos en AndroidManifest.xml solamente definen los permisos pero no los conceden, para poder concederlos debemos ir hasta la Configuracion -> Apps (o Aplicaciones) -> La aplicacion en cuestion y ceder los permisos, como vimos en este post pero no es la idea de que el usuario tenga que hacer todo eso por los permisos para la aplicacion. Para este caso tenemos una posibilidad de poder solicitar al usuario si concederle los permisos a la aplicacion, esto mismo hoy vamos a hacerlo para nuestra app Mis Lugares, primero modificaremos este bloque del metodo onCreate() de la clase MainActivity:

            if (manejador.isProviderEnabled(LocationManager.
                    GPS_PROVIDER)){
                actualizaMejorLocaliz(manejador.getLastKnownLocation(
                        LocationManager.GPS_PROVIDER));
            }
            if (manejador.isProviderEnabled(LocationManager.
                    NETWORK_PROVIDER)){
                actualizaMejorLocaliz(manejador.getLastKnownLocation(
                        LocationManager.NETWORK_PROVIDER));
            }

Lo modificaremos de la siguiente manera:

        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION)==
                PackageManager.PERMISSION_GRANTED){
            if (manejador.isProviderEnabled(LocationManager.
                    GPS_PROVIDER)){
                actualizaMejorLocaliz(manejador.getLastKnownLocation(
                        LocationManager.GPS_PROVIDER));
            }
            if (manejador.isProviderEnabled(LocationManager.
                    NETWORK_PROVIDER)){
                actualizaMejorLocaliz(manejador.getLastKnownLocation(
                        LocationManager.NETWORK_PROVIDER));
            }
        } else {
            solicitarPermisoGPS();
        }
Anuncios

En este caso, encerraremos a los condicionales en un condicional que verificara por medio de checkSelfPermission que el permiso ACCESS_FINE_LOCATION (es decir el de localizacion por medio de GPS) tiene el permiso concedido (GRANTED) en caso contrario procede a llamar a la funcion solicitarPermisoGPS(), nuestro siguiente paso sera agregar dicha funcion para ello debemos ir a alguna parte de la clase pero fuera de los otros metodos y agreguemos este metodo:

    public void solicitarPermisoGPS(){
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                0);
    }

Este metodo lo unico que va a hacer es mostrarnos el cartel de concesion de permisos para nuestra app, esto es gracias a requestPermissions() donde primero le informamos el contexto (this). luego crearemos una nueva cadena (string) donde mostraremos el nombre del permiso y por ultimo asignaremos un requestCode (en este caso innecesario porque no interceptaremos al evento) para nuestro siguiente permiso (el acceso a la memoria externa) deberemos poner el siguiente bloque dentro del metodo onCreate():

        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_EXTERNAL_STORAGE)==
                PackageManager.PERMISSION_DENIED){
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}
                    ,0);
        }

En este caso chequearemos si el permiso READ_EXTERNAL_STORAGE esta denegado (DENIED), y en caso de ser cierto nos mostrara el mismo cartel que hablamos antes pero esta vez con el mensaje para la descripcion del acceso a la memoria externa, con todas estas modificaciones realizadas procedamos a ver como quedo el codigo de MainActivity:

Anuncios
package org.example.mislugares;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;


public class MainActivity extends AppCompatActivity
        implements AdapterView.OnItemClickListener,
        LocationListener {

    public CursorAdapter adaptador;
    private LocationManager manejador;
    private Location mejorLocaliz;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Lugares.inicializaDB(this);
            adaptador = new AdaptadorCursorLugares(this,Lugares.listado());
        /* adaptador = new SimpleCursorAdapter(this,
                R.layout.elemento_lista,
                Lugares.listado(),
                new String[] { "nombre","direccion" },
                new int[] { R.id.nombre, R.id.direccion },
                0); */
            ListView listavista = (ListView) findViewById(R.id.ListaVista);
            listavista.setAdapter(adaptador);
            listavista.setOnItemClickListener(this);
        manejador = (LocationManager) getSystemService(
                LOCATION_SERVICE);
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION)==
                PackageManager.PERMISSION_GRANTED){
            if (manejador.isProviderEnabled(LocationManager.
                    GPS_PROVIDER)){
                actualizaMejorLocaliz(manejador.getLastKnownLocation(
                        LocationManager.GPS_PROVIDER));
            }
            if (manejador.isProviderEnabled(LocationManager.
                    NETWORK_PROVIDER)){
                actualizaMejorLocaliz(manejador.getLastKnownLocation(
                        LocationManager.NETWORK_PROVIDER));
            }
        } else {
            solicitarPermisoGPS();
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_EXTERNAL_STORAGE)==
                PackageManager.PERMISSION_DENIED){
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}
                    ,0);
        }
    }

    public void onItemClick(AdapterView<?> parent, View vista,
                               int posicion, long id){
        Intent i = new Intent(this,VistaLugar.class);
        i.putExtra("id", id);
        startActivityForResult(i,0);
    }

    public boolean onCreateOptionsMenu(Menu menu){
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    public void lanzarAcercaDe(View view){
        Intent i = new Intent(this,AcercaDe.class);
        startActivity(i);
    }

    public void lanzarVistaLugar(View view){
        final EditText entrada = new EditText(this);
        entrada.setText("0");
        new AlertDialog.Builder(this)
                .setTitle("Seleccion del Lugar")
                .setMessage("Indica su id")
                .setView(entrada)
                .setPositiveButton("Ok",
                        new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog,
                                        int whichButton) {
                        long id = Long.parseLong(entrada.getText().toString());
                        Intent i = new Intent(MainActivity.this,
                                VistaLugar.class);
                        i.putExtra("id",id);
                        startActivity(i);
                    }
                })
                .setNegativeButton("Cancelar",null)
                .show();
    }

    public boolean onOptionsItemSelected(MenuItem item){
        int id = item.getItemId();
        if (id == R.id.config){
            return true;
        }
        if (id == R.id.buscar){
            lanzarVistaLugar(null);
            return true;
        }
        if (id == R.id.about){
            lanzarAcercaDe(null);
        }
        if (id == R.id.menu_mapa){
            Intent intento = new Intent(this, Mapa.class);
            startActivityForResult(intento,0);
        }
        if (id == R.id.accion_nuevo){
            long id2 = Lugares.nuevo();
            Intent i = new Intent(this, EdicionLugar.class);
            i.putExtra("nuevo",true);
            i.putExtra("id",id2);
            startActivityForResult(i,0);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onResume(){
            super.onResume();
            activarProveedores();
    }

    private void activarProveedores(){
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION)==
                PackageManager.PERMISSION_GRANTED) {

            if (manejador.isProviderEnabled(LocationManager.
                    GPS_PROVIDER)) {
                manejador.requestLocationUpdates(LocationManager.
                        GPS_PROVIDER, 20 * 1000, 5, this);
            }

            if (manejador.isProviderEnabled(LocationManager.
                    NETWORK_PROVIDER)) {
                manejador.requestLocationUpdates(LocationManager.
                        NETWORK_PROVIDER, 10 * 1000, 10, this);
            }
        }
    }

    @Override
    protected void onPause(){
            super.onPause();
            manejador.removeUpdates(this);
    }

    @Override
    public void onLocationChanged(Location location){
        Log.d(Lugares.TAG, "Nueva Localizacion: " + location);
        actualizaMejorLocaliz(location);
    }

    @Override
    public void onProviderDisabled(String proveedor){
        Log.d(Lugares.TAG,"Se deshabilita: " + proveedor);
        activarProveedores();
    }

    @Override
    public void onProviderEnabled(String proveedor){
        Log.d(Lugares.TAG,"Se habilita: " + proveedor);
        activarProveedores();
    }

    @Override
    public void onStatusChanged(String proveedor, int estado,
                                Bundle extras){
        Log.d(Lugares.TAG,"Cambia estado: " + proveedor);
        activarProveedores();
    }

    private static final long DOS_MINUTOS = 2 * 60 * 1000;

    private void actualizaMejorLocaliz(Location localiz){
        if(localiz != null && (mejorLocaliz == null
        || localiz.getAccuracy() < 2 * mejorLocaliz.getAccuracy()
        || localiz.getTime() - mejorLocaliz.
                getTime() > DOS_MINUTOS)) {
            Log.d(Lugares.TAG,"Nueva mejor ubicacion");
            mejorLocaliz = localiz;
            Lugares.posicionActual.setLatitud(
                    localiz.getLatitude());
            Lugares.posicionActual.setLongitud(
                    localiz.getLongitude());
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data){
        super.onActivityResult(requestCode,resultCode,data);
        actualizaLista();
    }

    public void actualizaLista(){
        ListView listView = (ListView) findViewById(R.id.ListaVista);
        AdaptadorCursorLugares adaptador = (AdaptadorCursorLugares)
                listView.getAdapter();
        adaptador.changeCursor(Lugares.listado());
    }

    public void solicitarPermisoGPS(){
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}
                    ,0);
    }
}
Anuncios

Como pueden ver ahora tenemos un codigo mas compatible con los distintos dispositivos porque para las versiones por debajo de MarshMallow al estar declarado en el Manifiesto (AndroidManifest.xml) le es suficiente para conceder el permiso, en cambio para las versiones mas nuevas nos mostrara el mensaje de notificacion para concederlo o no, en lugar de tener que obligar al usuario a meterse en Configuraciones y buscar la aplicacion para conceder los permisos, si lo probamos deberemos tener una salida semejante a como se ve en el siguiente video

Como se puede ver, perdon por la espera, al momento de instalarlo como no tenemos ningun permiso habilitado nos pregunta por si queremos concederlo o no, tanto para el acceso a la memoria externa como a la ubicacion.

Anuncios

En resumen, hoy hemos repasado permisos en MarshMallow, hemos visto como aplicarlo sobre una app que esta desarrollada, tambien hemos visto la falla que nos genero al principio, y como lo solucionamos al final con muy pocas modificaciones, recuerden siempre tener en cuenta estos detalles especialmente en este momento que Android ya hace varias versiones que modifico el tema de los permisos, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00