Permitiendo a otras aplicaciones iniciar tu actividad

Las dos lecciones anteriores se han enfocado en un lado de la historia: iniciar una actividad de otra aplicación desde tu aplicación. Pero si tu aplicación puede ejecutar una acción que puede ser útil para otra aplicación, debería estar preparada para responder a peticiones de otras aplicaciones. Por ejemplo, si desarrollas una aplicación social que pueda compartir mensajes o fotografías con los amigos del usuario, sería interesante soportar la intención ACTION_SEND de forma que los usuarios puedan iniciar una acción de "compartir" desde otra aplicación y lanzar tu aplicación para llevar a cabo la acción.

Para permitir a otras aplicaciones iniciar tu actividad, necesitas añadir en tu archivo de manifiesto un elemento <intent-filter> al elemento <activity> correspondiente.

Cuando tu aplicación se instala en un dispositivo, el sistema identifica tus filtros de intenciones y añade la información a un catálogo interno con todas las intenciones que soportan las aplicaciones instaladas. Cuando una aplicación llama a startActivity() o startActivityForResult(), con una intención implícita, el sistema comprueba qué actividad (o actividades) pueden responder a la intención.

Añadir un filtro de intención


Para poder definir apropiadamente las intenciones que puede manejar tu actividad, cada filtro de intención que añadas debería ser tan específico como sea posible en términos del tipo de acción y los datos que acepta la actividad.

El sistema puede enviar un Intent a una actividad si esa actividad tiene un filtro de intención que cumple con todos los criterios del objeto Intent:

Acción
Una cadena indicando la acción a realizar. Normalmente uno de los valores definidos por la plataforma, como ACTION_SEND o ACTION_VIEW.

Especifica la acción en tu filtro de intención con el elemento <action>. El valor que especifiques en este elemento debe ser una cadena con el nombre completo para la acción, en lugar de la constante de la API (ver ejemplos más adelante).

Datos
Una descripción de los datos asociados con la intención.

Especifica los datos en tu filtro de intención usando el elemento <data>. Utilizando uno o más atributos de este elemento puedes especificar el tipo MIME, un prefijo para la URI, un esquema para la URI, o una combinación de estas condiciones y otras que indiquen los tipos de datos que acepta la intención.

Nota: Si no necesitas indicar nada acerca de la Uri (por ejemplo si tu actividad maneja otro tipo de datos en lugar de una URI), sólo deberías especificar el atributo android:mimeType para declarar el tipo de datos que maneja tu actividad, como text/plain o image/jpeg.

Categoría
Proporciona una manera adicional de caracterizar la actividad que maneja la intención, normalmente relacionada con un gesto del usuario o la localización desde la que se inicia. El sistema soporta varias categorías, pero la mayoría no suelen utilizarse. Sin embargo, todas las intenciones implícitas se definen por defecto con una categoría CATEGORY_DEFAULT.

Especifica la categoría en tu filtro de intención con el elemento <category>.

En tu filtro de intención, puedes especificar qué criterios acepta tu actividad declarando cada uno de ellos con los correspondientes elementos XML anidados en el elemento <intent-filter>.

Por ejemplo, a continuación se muestra una actividad con un filtro de intención que maneja la intención ACTION_SEND cuando el tipo de datos es un texto o una imagen:

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>

Cada intención entrante tiene una única acción y un tipo de datos, pero es correcto declarar varias instancias de los elementos <action>, <category>, y <data> en cada <intent-filter>.

Si hay dos pares de acción y datos mutuamente exclusivos en sus comportamientos, deberías crear filtros de intenciones separados para especificar qué acciones son aceptables combinadas con qué tipos de datos.

Por ejemplo, supongamos que tu actividad puede manejar tanto texto como imágenes tanto para la intención ACTION_SEND como para ACTION_SENDTO. En este caso, debes definir dos filtros de intenciones distintos para las dos acciones porque una intención ACTION_SENDTO tiene que usar una Uri para especificar la dirección del destinatario usando el esquema de URI send o sendto. Por ejemplo:

<activity android:name="ShareActivity">
    <!-- filtro para enviar texto; acepta una acción SENDTO con esquemas de URI sms -->
    <intent-filter>
        <action android:name="android.intent.action.SENDTO"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="sms" />
        <data android:scheme="smsto" />
    </intent-filter>
    <!-- filtro para enviar texto o imágenes; acepta una acción SEND y datos tipo texto o imagen -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

Nota: Para recibir intenciones implícitas, debes incluir la categoría CATEGORY_DEFAULT en el filtro de intención. Los métodos startActivity() y startActivityForResult() tratan todas las intenciones como si estuvieran contenidas en la categoría CATEGORY_DEFAULT. Si no declaras esta categoría, no se aplicará ninguna intención implícita a tu actividad.

Para más información acerca de enviar y recibir intenciones ACTION_SEND para compartir contenido de forma social, consulta la lección Obteniendo un resultado de una actividad.

Gestionar la intención en tu actividad


Para decidir qué acción llevar a cabo en tu actividad, puedes leer el Intent que se utilizó para iniciarla.

Al iniciar tu actividad, llama a getIntent() para obtener el Intent que inició la actividad. Puedes hacer esto en cualquier momento del ciclo de vida de la actividad, pero generalmente deberías hacerlo en las primeras retrollamadas como onCreate() y onStart().

Por ejemplo:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Obtenemos la intención que inició la actividad
    Intent intent = getIntent();
    Uri data = intent.getData();

    // Comprobamos qué hacer dependiendo del tipo de intención
    if (intent.getType().indexOf("image/") != -1) {
        // Gestionamos la intención con imagen como datos ...
    } else if (intent.getType().equals("text/plain")) {
        // Gestionamos la intención con texto ...
    }
}

Devolver un resultado


Si quieres devolver un resultado a la actividad que invocó la tuya, simplemente llama a setResult() para especificar el código y el Intent de resultado. Cuando termine tu operación y el usuario deba volver a la actividad original, llama al método finish() para cerrar (y destruir) tu actividad. Por ejemplo:

// Creamos una intención para devolver algún tipo de resultado
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();

Siempre debes especificar un código de resultado. Generalmente, este suele ser RESULT_OK o RESULT_CANCELED. Una vez hecho esto puedes proporcionar datos adicionales con un Intent, en caso de que sea necesario.

Nota: Por defecto el resultado utiliza un código RESULT_CANCELED. De esta forma, si el usuario presiona el botón Volver antes de completar la acción y antes de que hayas establecido el resultado, la actividad original recibirá un resultado de "cancelada".

Si sólo necesitas devolver un entero que indique un resultado de varios posibles, puedes dar cualquier valor mayor que 0 al código de resultado. Si usas el código de resultado para devolver un entero y no necesitas incluir un Intent, puedes llamar a setResult() y pasarle sólo el código de resultado. Por ejemplo:

setResult(RESULT_COLOR_RED);
finish();

En este caso, puede haber sólo un puñado de resultados posibles, por lo que el código de resultado es un entero definido localmente (mayor que 0). Esto funciona muy bien cuando estás devolviendo un resultado a una actividad de tu propia aplicación, porque la actividad que recibe el resultado puede referenciar la constante pública que determina el valor del código resultado.

Nota: No hay necesidad de comprobar si tu actividad se ha iniciado con startActivity() o startActivityForResult(). Simplemente llama a setResult() si la intención que inició tu actividad puede estar esperando un resultado. Si la actividad inicial llamó a startActivityForResult(), el sistema le devolverá el resultado que pasaste a setResult(); en caso contrario, simplemente se ignorará.