jueves, diciembre 15, 2016

Hacer la barra de status transparente en Android.

Había estado luchando una semana para logra que mi actividad principal tuviera el statusBar transparente, y luego cuando el bottom sheet se expandiera cambiara de color. Probé de todo, poniendo en el tema las banderas de drawSystemBackground, translucentStatusBar, etc., no lograba lo que quería hasta que encontré este reminder de JimRobs en github


if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
    // Get Window
    final Window window  = getWindow();
    // Set Fullscreen
    window.getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    );
    // Set status bar color
    // ! Can also be set in style resource (/res/values-v21/styles.xml)
    // @android:color/transparent
    window.setStatusBarColor(Color.TRANSPARENT);
}

Aquí la referencia a su reminder,

Este código lo agregué en el método onActivityCreated de mi fragmento.  Quedando como resultado algo así, solo que no puedo mostrar la interfaz completa. business rules :D






martes, septiembre 20, 2016

Trabajando con Bluetooth Low Energy (BLE) en Android

Actualmente estoy desarrollando un app que requiere la comunicación con dispositivos bluetooth low energy. Todo parecía muy sencillo, pero la verdad es que hay que escribir mucho código para hacer que funcione servicios, broadcast receivers, binding a servicios, entre otros.

Mientras voy desarrollando tengo en mi gradle el minSDK de mi teléfono (Nexus 6p - SDK 24) esto con el simple hecho de compilar mas rápido.  La aplicación se espera que trabaje desde Android 4.3 SDK18 que fue cuando se introdujo BLE en Android.

Todo iba muy bien hasta que cambié el gradle a minSDK 18.. encontré que todo mi código estaba hecho para SDK21 donde hay métodos nuevos para escanear BLE devices.

Para ser mas concreto cambian los callBacks a partir del SDK 21. Lo resolví de la siguiente manera

Primero nos creamos dos métodos: scanLeDevice21 y scanLeDevice18.

  
    /**
     * Scan for BLE devices with Android API 21 and up
     *
     * @param enable Enabled scanning
     */
    @RequiresApi(21)
    private void scanLeDevice21(final boolean enable) {

        ScanCallback mLeScanCallback = new ScanCallback() {

            @Override
            public void onScanResult(int callbackType, ScanResult result) {

                super.onScanResult(callbackType, result);

                BluetoothDevice bluetoothDevice = result.getDevice();

                if (!bluetoothDeviceList.contains(bluetoothDevice)) {
                    Log.d("DEVICE", bluetoothDevice.getName() + "[" + bluetoothDevice.getAddress() + "]");
                    bluetoothDeviceArrayAdapter.add(bluetoothDevice);
                    bluetoothDeviceArrayAdapter.notifyDataSetChanged();
                }
            }

            @Override
            public void onBatchScanResults(List results) {
                super.onBatchScanResults(results);

            }

            @Override
            public void onScanFailed(int errorCode) {
                super.onScanFailed(errorCode);
            }
        };

        final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(() -> {
                mScanning = false;
                swipeRefreshLayout.setRefreshing(false);
                bluetoothLeScanner.stopScan(mLeScanCallback);
            }, SCAN_PERIOD);

            mScanning = true;
            bluetoothLeScanner.startScan(mLeScanCallback);
        } else {
            mScanning = false;
            bluetoothLeScanner.stopScan(mLeScanCallback);
        }
    }

    /**
     * Scan BLE devices on Android API 18 to 20
     *
     * @param enable Enable scan
     */
    private void scanLeDevice18(boolean enable) {

        BluetoothAdapter.LeScanCallback mLeScanCallback =
                new BluetoothAdapter.LeScanCallback() {
                    @Override
                    public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi,
                                         byte[] scanRecord) {
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                bluetoothDeviceArrayAdapter.add(bluetoothDevice);
                                bluetoothDeviceArrayAdapter.notifyDataSetChanged();
                            }
                        });
                    }
                };
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(() -> {
                mScanning = false;
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }

    }

Si observamos, el método scanLeDevice21 tiene la anotación @RequiresApi(21) que dice lo siguiente:

"Denotes that the annotated element should only be called on the given API level or higher. This is similar in purpose to the older @TargetApi annotation, but more clearly expresses that this is a requirement on the caller, rather than being used to "suppress" warnings within the method that exceed the minSdkVersion"

Luego, cada vez que necesitamos escanear un dispositivo preguntamos en cuál API estamos y utilizamos el método correspondiente. Por ejemplo, tengo mi lista de dispositivos dentro de un RefreshLayout.

    /**
     * Refresh listener
     */
    private void refreshScan() {
        if (!hasFineLocationPermissions()) {
            swipeRefreshLayout.setRefreshing(false);
            requestFineLocationPermission();
        } else {
            swipeRefreshLayout.setRefreshing(true);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                scanLeDevice21(true);
            } else {
                scanLeDevice18(true);
            }
        }
    }
Y ya, eso es todo! con esto tenemos nuestra api funcional para las diferentes versiones de Android.

lunes, agosto 22, 2016

Android Nougat 7.0 desde hoy!

Si señores, se vino la nueva versión.
A partir de hoy empieza a el despliegue de Android Nougat 7.0. Para los que tenemos dispositivos Nexus, ya sea Nexus 6, 6P, 5X, Pixel C, en cualquier momento del día aparecerá la notificación para descargar la actualización. Esta versión, será más personal, con controles rápidos de configuración, soporte para varios entornos locales por ejemplo si hablamos varios idiomas, los resultados de las búsquedas se mostraran en los idiomas que tengamos en configurados. El soporte multi ventana, es cierto que Samsung y otros fabricantes lo tenían, pero ahora es nativo.
Más batería, más immersive y más seguro.
A la espera por que se instale. 
Saludos.
Para más información https://android.googleblog.com/2016/08/android-70-nougat-more-powerful-os-made.html

jueves, agosto 11, 2016

Parcelable en Español

Parcelable

Interfaz para clases cuya instancias pueden ser escritas y restauradas de un Parcel.

Parcel

Paquete, grupo o montón. Contenedor para un mensaje (data y referencias de objeto) que puede ser enviado a través de IBinder. 

Bien ¿y que hacemos con eso?

Cuando pasamos parámetros a un Intent, o un fragmento o actividad dentro de un Bundle podemos pasar todo un objeto, ¿cómo?  implementando Parcelable en nuestra clase.  Anteriormente utilizaba Serializable, pero es recomendable utilizar Parcelable  en vez de Serializable sencillamente porque es mucho más rápido. Se pueden leer este artículo de Philippe Breaul Ingeniero de Software en Google Parcelable vs Serializable para más  detalle sobre las diferencias de ambos.

Supongamos que vamos a enviar parámetros a un IntentService para un Login por ejemplo,

LoginRequest loginRequest = new LoginRequest(this,
                    mEmailView.getText().toString(),
                    mPasswordView.getText().toString());

Intent loginService = new Intent(this, LoginIntentService.class);
loginService.putExtra(LoginIntentService.PARAM_LOGIN, loginRequest);


El método putExtra acepta un Parcelable, en este caso tengo un objeto loginRequest con mi usuario y contraseña pero, para que eso se pueda hacer LoginRequest tiene que implementar Parcelable, así:


public class LoginRequest implements Parcelable {


    @SuppressWarnings("unused")
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        @Override
        public LoginRequest createFromParcel(Parcel in) {
            return new LoginRequest(in);
        }

        @Override
        public LoginRequest[] newArray(int size) {
            return new LoginRequest[size];
        }
    };

    private String email;
    private String password;

    /**
     * Default private request
     */
    private LoginRequest() {
    }

    /**
     * Constructor of this class
     *
     * @param context  Android context
     * @param email    Email
     * @param password Password
     */
    public LoginRequest(Context context, String email, String password) {
        this.email = email;
        this.password = password;
        this.device = new Device(DeviceManager.getDeviceName(), DeviceManager.getDeviceID(context));
    }

    /**
     * Constructor for Parcel
     *
     * @param in in parce
     */
    private LoginRequest(Parcel in) {
        email = in.readString();
        password = in.readString();
        device = (Device) in.readValue(Device.class.getClassLoader());
    }


    /**
     * Implementation of describeContent of Parcelable interface
     *
     * @return 0
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * WriteToParce implementation
     *
     * @param dest  destination
     * @param flags flags
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(email);
        dest.writeString(password);
        dest.writeValue(device);
    }
}

Los métodos del Parcelable  están en negritas y todos son importantes y necesarios. Se podría pensar que es mucho código, y lo es, más aún si tenemos muchos campos en nuestra clase. Afortunadamente Android Studio nos hace todo el trabajo. Vale mencionar que uso la versión 2.2 Beta.

Lo único que tenemos que hacer es escribir nuestra clase LoginRequest implements Parcelable y los miembros de la clase, algo así:



Nos va marcar que algo está mal, en Mac presionamos alt + enter en el nombre de la clase.



Seleccionamos Add Parcelable implementation y automáticamente nos genera todos los métodos necesarios.

Quedando como resultado 


Saludos, espero empiecen a utilizar Parcelable de ahora en adelante para pasar todo un objeto y no parámetro por parámetro como he visto en algunos códigos en Internet. 



jueves, julio 28, 2016

Cómo aprender más Android, usa Android Lint.

Siempre me han gustado las cosas buenas (los últimos gadgets tecnológicos del mercado, buena ropa, buenos autos, etc) en el código soy igual. Una de las herramientas que me ha ayudado muchísimo en cuanto al aprendizaje de Android es Android Lint, acá el link para más detalles.

En resumen, Android List es una herramienta que te ayuda a verificar tu código, estructura, buenas practicas entre muchas otras sin necesidad siquiera de correr tu aplicación.

Ayer, mientras analizaba el código viejo de una de mis apps, la cual estoy actualizando a una nueva versión, aprendí por ejemplo, sobre las clases estáticas y el Context de Android.

Un fragmento de ejemplo de un singleton.

public class MyClass {

    private static Context context;
    private static MyClass myClassInstance;

    /**
     * Return an instance of this class
     */

    public static MyClass getInstance(Context c) {

        context = c;

        if (myClassInstance == null) {
            myClassInstance = new MyClass();
        }

        return myClassInstance;
    }
}


El método getInstance retorna la instancia de esa clase, pero si vemos en el constructor, estamos pasando Context como parámetro y la asignamos a la variable global context para tenerla accesible siempre.

Esto parece que no causa daño alguno pero al analizar este código con Android Lint, vemos lo siguiente.

"Do not place Android context class in static fields, this is a memory leak (and also breaks Insta Run)" en plano Castellano dice: No coloque la clase de contexto de Android en campos estáticos, esto es una pérdida de memoria (y también puede romper Insta Run).

¿Cómo obtuve esto?

Ok, acá les enseño cómo correr Android Lint y obtener este error.

Android Studio


Con Android Studio seleccionado (compartimiento en Mac) vamos al menú que dice Analyze -> Inspect Code.


Venta de ámbito de la inspección

Nos aparece la ventana preguntando el ámbito de la inspección, las opciones son:

Whole project: Va a verificar TODO cuando digo todo , es todo el projecto, librerías, etc, dependiendo de sus máquinas y el tamaño del proyecto puede tardar un rato en finalizar.

Module 'app' en mi caso aparece 'app'  porque tengo seleccionado el módulo en el explorador de proyecto.

Current file, sólo el archivo que tengo abierto en el editor, o que tiene el cursor activo (esto si tenemos varios abiertos a la vez en vistas divididas)

Custom scope, un ámbito personalizado - nunca me meto ahí, pero es para personalizar lo que quieres analizar.

Inspection profile. Dejen lo en default

Para este ejemplo en particular del singleton y el Context seleccioné "Current File".



Al finalizar, nos va a mostrar la sección de "Inspection" usualmente aparece abajo. Si no está abierta (que la abre automáticamente - pues, dale clic).

A la izquierda, tenemos  los resultados de la inspección
A la derecha, la explicación de lo que significa la inspección seleccionada y en la mayoría de los casos cómo solucionarlo.

Para el caso de Context no dice qué hacer, pero podemos Googlear un poco y leer cómo solucionarlo.

La solución es tan simple como eliminar el parámetro Context del método getInstance, volarnos la variable global, porque no es necesaria tenerla global, y agregar el parámetro a el(los) método(s) dónde vayamos a usar el context. Un ejemplo sería.


MyClass.getInstance().myMethod(context)


Listo!!! un posible error menos en nuestro proyecto.

Espero sus comentarios.

Saludos.

viernes, junio 10, 2016

Build Variants | Variantes de compilación de Android Studio.

Android Studio es una herramienta maravillosa con muchas características que facilitan el desarrollo de nuestras aplicaciones.

Hoy les quiero hablar sobre las variantes de compilación, o Build Variants en inglés. Quizá no sea la mejor traducción pero es la que me parece correcta.

Las variantes de compilación te permiten generar diferentes versiones de tu aplicaciones según sea la necesidad de tu proyecto. El ejemplo que tiene la documentación de Android sería una aplicación que tiene la versión full y la versión demo. Voy a crear estas dos variantes de compilación en el siguiente tutorial.

Una vez creado nuestro proyecto, lo primero que vamos a hacer es abrir la configuración del módulo de la aplicación. Hacemos clic derecho en app -> Open Module Settings o en Mac, presionamos Command + Flecha hacia abajo.

Open Module Settings

Esto nos mostrará el dialogo de la estructura del proyecto.

Project Structure

Este dialogo tiene las pestañas Properties, Signing, Flavors, Build Types y Dependencies. Voy a explicar un poco para qué es cada pestaña

Properties

Sirve para configurar las propiedades del proyecto.

Compile SDK Version. Aquí seleccionamos la versión del SDK de compilación, para este ejemplo estoy usando 6.0 Marshmallow.
Build Tools Version. La versión de Android build tools.
Library Repository. Esto no se qué hace. Lo dejamos en blanco
Ignore Assets Pattern. Tampoco sé qué hace. Lo dejamos en blanco
Incremental Dex, true o false para activar o desactivar la compilación incremental dex
Source compatibility, Es la versión de java mínima.
Target compatibility, Es la versión de java que se usará en el proyecto. 

Estas dos últimas por defecto son la 1.7 pero si queremos por ejemplo desarrollar para android N y java 8, podríamos seleccionar target compatibility en 1.8 

Signing 

Sirve para configurar los certificados con los que se firmará la aplicación. Les describo un ejemplo de su uso.

Para la empresa donde trabajo uno de sus clientes tiene configurado su perfil de desarrollador en Google Play, y la compañía también. Cuando el cliente sube la aplicación a Google Play hay que firmar la app con el certificado que ellos usaron inicialmente. En la empresa tenemos la misma aplicación para propósitos de pruebas pero firmada con otro certificado. Recuerden que una vez subida una aplicación a Google Play siempre se tiene que firmar la app con el mismo certificado, sino Google Play nos va mostrar un error como este


Dicho esto, vamos a tener el caso hipotético que necesitamos que la versión full tenga un certificado y la versión demo tenga otro. 

Para agregar los certificados, le damos clic al botón más y llenamos los datos que se pide.

Certificado para la versión demo

Certificado para la versión Full
Key Alias, es el alias del certificado
Key Password, el password del certificado
Store File, la ubicación del certificado, en este caso la agregué dentro del directorio app/ luego esto se reemplazará, en el .gradle
Store password, el password del key store, usualmente utilizo el mismo que el key password.

Para saber como crear los certificados desde Android Studio ve el post Crear certificados desde Android Studio (aún no lo he escrito)

Flavors



Aquí viene lo divertido, es donde crearemos los sabores o Flavors de nuestra aplicación. Hay una fórmula que dice.
Flavor + Build Type = Build Variant.
La fórmula lo que quiere decir es que por cada Flavor y Build Type obtendremos un Build Variant. 

Comenté que la aplicación tendría dos variantes: Demo y Full. En esta pestaña definimos estos valores, por defecto todos los proyectos tienen un Flavor llamado defaultConfig es importante saber que NO debemos borrar este Flavor, puesto que los demás van a heredar de defaultConfig.

Para agregar un Flavor, hacemos clic en el botón de más y llenamos los datos que nos pide.

Flavor demo

Flavor full

 Cada campos significa lo siguiente. 

Name, nombre del Flavor
Min SDK version, al estar definido en defaultConfig, los demás Flavors no tienen por qué llenarse a menos, que estemos creando una versión de la aplicación específica para una versión de Android.
Application Id, para que nuestra app se compile con diferente id. Si se fijan en las dos imágenes anteriores, los id son com.pedrovarela.android.demo com.pedrovarela.android.full 
Proguard File, es el archivo Pro Guard que se usa para reducir el tamaño de la aplicación eliminado código y recursos que no se utilizan para más información lee Shrink Your Code and Resources.
Signing Config, el certificado con el que se firmara cada versión, estos los creamos anteriormente.
Target Sdk Version, la versión máxima de android en la que correrá nuestra app, la dejamos en blanco puesto que ya está definida en defaultConfig, a menos claro, que sea un caso específico. 
Test Instrumentation Runner, esto es nuevo pero es para configurar pruebas unitarias 
Test Application Id, el id de la app para las pruebas.
Version Code, el código de versión.
Version Name, el nombre de la versión.
Version Name Suffix, el sufijo del nombre de la versión.

Les comenté sobre la compañía donde trabajo y uno des sus clientes, version code y version name pueden ser diferentes para cada caso, la versión de producción del cliente es las 2.0 pero nuestra versión interna iba por la versión 12, esto lo pueden modificar aquí, si van a mantener la misma versión para todas las variantes sencillamente se modifica en defaultConfig y dejamos la de los Flavors en blanco.

Build Types


Los Build Types son los tipos de compilado, siempre tendremos estos dos, no hay necesidad de agregar más. Tenemos debug, que se usa para las versiones para debug, por ejemplo la app mostraría la información del log si usamos adb, y la tipo release que se usa para la versión de producción.

No hay necesidad de cambiar nada aquí, a menos que seas un usuario avanzado y sepas lo que estás haciendo. 

Dependencies

Las dependencias y librerías de nuestro proyecto


Bien, ya tenemos configurado nuestro proyecto para trabajar con build variants, pero, eso no est todo amigos!!

Android studio no crea la estructura de directorios necesaria para que las variantes funcionen correctamente, lo que quiere decir que hay que agregarlas manualmente. Para esto, hacemos lo siguiente:


Cambiamos la vista del proyecto de Android a Project Files


Seleccionamos src, hacemos click derecho, y creamos un nuevo directorio. 


Para este ejemplo tenemos dos Flavours, así que serían dos directorios. Los directorios se tienen que llamar igual que los Flavours, es decir demo y full, quedando lo así.


Listo, ahora si tenemos todo casi listo para que nuestro proyecto funcione con Build Variants. En la imagen anterior vemos un archivo que se llama build.gradle.  Este archivo contiene todo lo que acabamos de configurar en el dialogo de la estructura del proyecto al abrirlo veremos algo como esto.



Si se fijan, tenemos todo los definido signingConfig, defaultConfig, buildTypes, productFlavors y dependencies. 

Bien, ahora cómo usamos todo esto. 

Supongamos que los nombres de nuestras aplicaciones tienen que ser diferentes para cada variante. Demo, se llamará Aplicación Demo, y Full se llamará Aplicación Full. 

Cada flavor puede tener sus propios archivos de strings, drawables, inclusive reemplazar actividades, fragmentos y clases. Para este ejemplo sencillo solo vamos a cambiar el nombre de la aplicación. ¿Qué hacemos? copiamos y pegamos los archivos que necesitamos en cada directorio del flavor, en este caso sería strings.xml. Es importante saber que todos los flavor tienen que reemplazar el archivo strings.xml. Por cierto, si hay algo que no queremos reemplazar o que se mantenga igual en ambos flavours, el directorio main es el principal (qué sería el que estuviésemos usando si no usamos los build variants) 

Una vez copiados y pegados los recursos que queremos abrimos cada strings.xml y modificamos el nombre,  quedando lo siguiente.



Para verificar que está funcionando, buscamos el panel que se llama Build Variants, yo lo tengo a la izquierda de Android Studio. Al abrirlo, vamos a ver dos columnas, Module y Build Variant. Aquí se aplica la fórmula que les comente anteriormente. Flavor + BuildType = BuildVariant. Tenemos entonces demoDebug, demoRelease, fullDebug, fullRelease.  Al seleccionar un Build Variant podemos ver automáticamente cambia todo. Abran el archivo main.xml y cambien de variant en variant para que vean como cambia el texto Hello World y el título de la actividad.

Aplicación Demo

Aplicaión Full

Listo ya esta todo funcional, si quieren correr la aplicación en su equipo, tienen que ver qué BuildVariant está seleccionada. La variante seleccionada es la que va a instalarse.

Al correr las dos variantes vemos en el equipo los dos iconos.



 


¿Cómo compilar las Build Variants?


Fácil, abrimos el terminal y escribimos (esto en Mac) ./gradlew assembleRelease


El resultado será los apk de las variantes de compilación. Los buscamos en

RutaDelProyecto/app/build/outputs/apk



Saludos, espero sus comentarios y les sea de utilidad. Código Fuente Aquí

miércoles, marzo 09, 2016

Android Developers Blog: First Preview of Android N: Developer APIs & Tools

Android Developers Blog: First Preview of Android N: Developer APIs & Tools





Android N precie ya está disponible para todos los desarrolladores, la imagen estará disponible sólo para nexus 6, 5x y 6p (ya me toca comprar nuevo teléfono), o usar el emulador.

viernes, enero 15, 2016

Cambios en Google Play Services | Compilación de API selectiva

Si reciben este error luego de actualizar parte del SDK de Android
Error:Execution failed for task ':app:compileReleaseJavaWithJavac'. java.io.FileNotFoundException: C:....\intermediates\exploded-aar\com.google.android.gms\play-services\8.4.0\jars\classes.jar (The system cannot find the path specified)
Quiere decir que deben aplicar cambios en las dependencias de sus proyectos. A partir de la versión 6.5 de Google Play services (GPS) los paquetes de la API se compilan selectivamente, esto quiere decir que hay que agregar sólo lo que nos interesa para nuestro proyecto, esto ayuda a reducir el limite de los 65.536 métodos que seguramente les pasó luego de agregar la librería de GPS. Entonces, ahora en vez de compilar
compile 'com.google.android.gms:play-services:8.4.0
Puedes incluir, como en mi caso sólo Google Cloud Messaging
com.google.android.gms:play-services-gcm:8.4.0
A continuación una tabla con cada uno de los paquetes de la API de GPS. Table 1. Individual APIs and corresponding build.gradle descriptions.

Table 1 shows a list of the separate APIs that you can include when compiling your app, and how to describe them in your build.gradle file. Some APIs do not have a separate library; include them by including the base library. (This lib is automatically included when you include an API that does have a separate library.)

Table 1. Individual APIs and corresponding build.gradle descriptions.

Google Play services API Description in build.gradle
Google+ com.google.android.gms:play-services-plus:8.4.0
Google Account Login com.google.android.gms:play-services-auth:8.4.0
Google Actions, Base Client Library com.google.android.gms:play-services-base:8.4.0
Google Address API com.google.android.gms:play-services-identity:8.4.0
Google App Indexing com.google.android.gms:play-services-appindexing:8.4.0
Google App Invites com.google.android.gms:play-services-appinvite:8.4.0
Google Analytics com.google.android.gms:play-services-analytics:8.4.0
Google Cast com.google.android.gms:play-services-cast:8.4.0
Google Cloud Messaging com.google.android.gms:play-services-gcm:8.4.0
Google Drive com.google.android.gms:play-services-drive:8.4.0
Google Fit com.google.android.gms:play-services-fitness:8.4.0
Google Location, Activity Recognition, and Places com.google.android.gms:play-services-location:8.4.0
Google Maps com.google.android.gms:play-services-maps:8.4.0
Google Mobile Ads com.google.android.gms:play-services-ads:8.4.0
Mobile Vision com.google.android.gms:play-services-vision:8.4.0
Google Nearby com.google.android.gms:play-services-nearby:8.4.0
Google Panorama Viewer com.google.android.gms:play-services-panorama:8.4.0
Google Play Game services com.google.android.gms:play-services-games:8.4.0
SafetyNet com.google.android.gms:play-services-safetynet:8.4.0
Google Wallet com.google.android.gms:play-services-wallet:8.4.0
Android Wear com.google.android.gms:play-services-wearable:8.4.0

Saludos, para ver la información completa ve a https://developers.google.com/android/guides/setup