A transferência de arquivos do "Android Beam" copia arquivos para um diretório especial no dispositivo receptor. Ela também verifica os arquivos copiados usando o Android Media Scanner e adiciona entradas para arquivos de mídia ao provedor MediaStore
. Esta lição mostra como responder quando a cópia do arquivo estiver concluída e como localizar os arquivos copiados no dispositivo receptor.
Responder a uma solicitação para exibir dados
Quando a transferência de arquivos do "Android Beam" termina de copiar arquivos para o dispositivo receptor, ela posta uma notificação contendo uma Intent
com a ação ACTION_VIEW
, o tipo MIME do primeiro arquivo transferido e um URI que aponta para o primeiro arquivo. Quando o usuário clica na notificação, essa intent é enviada ao sistema. Para que seu app responda a essa intent, adicione um elemento <intent-filter>
para o elemento <activity>
do Activity
que deve responder.
No elemento <intent-filter>
, adicione os seguintes elementos filhos:
-
<action android:name="android.intent.action.VIEW" />
-
Corresponde à intent
ACTION_VIEW
enviada a partir da notificação. -
<category android:name="android.intent.category.CATEGORY_DEFAULT" />
-
Corresponde a uma
Intent
que não possui uma categoria explícita. -
<data android:mimeType="mime-type" />
- Corresponde a um tipo MIME. Especifique apenas os tipos MIME que o app pode processar.
Por exemplo, o snippet a seguir mostra como adicionar um filtro de intent que aciona a atividade com.example.android.nfctransfer.ViewActivity
:
<activity android:name="com.example.android.nfctransfer.ViewActivity" android:label="Android Beam Viewer" > ... <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> ... </intent-filter> </activity>
Observação: a transferência de arquivos do "Android Beam" não é a única fonte de uma intent ACTION_VIEW
. Outros apps no dispositivo receptor também podem enviar uma Intent
com essa ação.
Esse processamento é discutido na seção Ver o diretório de um URI de conteúdo.
Solicitar permissões de arquivo
Para ler os arquivos dos quais o "Android Beam" transfere cópias para o dispositivo, solicite a permissão READ_EXTERNAL_STORAGE
. Por exemplo:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Se você quiser copiar os arquivos transferidos para a área de armazenamento do seu app, solicite a permissão WRITE_EXTERNAL_STORAGE
.
WRITE_EXTERNAL_STORAGE
inclui
READ_EXTERNAL_STORAGE
.
Observação: a partir do Android 4.2.2 (API de nível 17), a permissão READ_EXTERNAL_STORAGE
só será aplicada se o usuário optar por fazer isso. Futuras versões da plataforma podem exigir essa permissão em todos os casos. Para garantir a compatibilidade direta, solicite a permissão agora, antes que ela seja obrigatória.
Como o app tem controle sobre a própria área de armazenamento interno, você não precisa solicitar permissão de gravação para copiar um arquivo transferido para sua área de armazenamento interno.
Ver o diretório de arquivos copiados
A transferência de arquivos do "Android Beam" copia todos os arquivos em uma única transferência para um diretório no dispositivo receptor. O URI na Intent
de conteúdo enviado pela notificação de transferência de arquivos do "Android Beam" aponta para o primeiro arquivo transferido. No entanto, seu app também pode receber uma intent ACTION_VIEW
de uma origem que não seja a transferência de arquivos do "Android Beam". Para determinar como processar a Intent
recebida, você precisa examinar o esquema e a autoridade dela.
Para receber o esquema do URI, chame Uri.getScheme()
. O snippet de código a seguir mostra como determinar o esquema e processar o URI adequadamente:
Kotlin
class MainActivity : Activity() { ... // A File object containing the path to the transferred files private var parentPath: File? = null ... /* * Called from onNewIntent() for a SINGLE_TOP Activity * or onCreate() for a new Activity. For onNewIntent(), * remember to call setIntent() to store the most * current Intent * */ private fun handleViewIntent() { ... /* * For ACTION_VIEW, the Activity is being asked to display data. * Get the URI. */ if (TextUtils.equals(intent.action, Intent.ACTION_VIEW)) { // Get the URI from the Intent intent.data?.also { beamUri -> /* * Test for the type of URI, by getting its scheme value */ parentPath = when (beamUri.scheme) { "file" -> handleFileUri(beamUri) "content" -> handleContentUri(beamUri) else -> null } } } ... } ... }
Java
public class MainActivity extends Activity { ... // A File object containing the path to the transferred files private File parentPath; // Incoming Intent private Intent intent; ... /* * Called from onNewIntent() for a SINGLE_TOP Activity * or onCreate() for a new Activity. For onNewIntent(), * remember to call setIntent() to store the most * current Intent * */ private void handleViewIntent() { ... // Get the Intent action intent = getIntent(); String action = intent.getAction(); /* * For ACTION_VIEW, the Activity is being asked to display data. * Get the URI. */ if (TextUtils.equals(action, Intent.ACTION_VIEW)) { // Get the URI from the Intent Uri beamUri = intent.getData(); /* * Test for the type of URI, by getting its scheme value */ if (TextUtils.equals(beamUri.getScheme(), "file")) { parentPath = handleFileUri(beamUri); } else if (TextUtils.equals( beamUri.getScheme(), "content")) { parentPath = handleContentUri(beamUri); } } ... } ... }
Ver o diretório de um URI de arquivo
Se a Intent
recebida contiver um URI de arquivo, o URI conterá o nome absoluto de um arquivo, incluindo o caminho completo do diretório e o nome do arquivo. Na transferência de arquivos do "Android Beam", o caminho do diretório apontará para o local dos outros arquivos transferidos, se houver. Para ver o caminho do diretório, observe a parte do caminho do URI, que contém todo o URI, exceto o prefixo do file:
. Crie um File
a partir da parte do caminho e receba o caminho pai do File
:
Kotlin
... fun handleFileUri(beamUri: Uri): File? = // Get the path part of the URI beamUri.path.let { fileName -> // Create a File object for this filename File(fileName) // Get the file's parent directory .parentFile } ...
Java
... public File handleFileUri(Uri beamUri) { // Get the path part of the URI String fileName = beamUri.getPath(); // Create a File object for this filename File copiedFile = new File(fileName); // Get the file's parent directory return copiedFile.getParentFile(); } ...
Ver o diretório de um URI de conteúdo
Se a Intent
recebida contiver um URI de conteúdo, o URI poderá apontar para um diretório e nome de arquivo armazenados no provedor de conteúdo da MediaStore
. Você pode detectar um URI de conteúdo para MediaStore
testando o valor de autoridade do URI. Um URI de conteúdo do MediaStore
pode vir da transferência de arquivos do "Android Beam" ou de outro app, mas, nos dois casos, é possível recuperar um diretório e nome de arquivo para o URI de conteúdo.
Você também pode receber um intent ACTION_VIEW
de entrada que contém um URI de conteúdo para um provedor que não seja o MediaStore
. Nesse caso, o URI de conteúdo não contém o valor de autoridade MediaStore
, e o URI de conteúdo geralmente não aponta para um diretório.
Observação: para transferência de arquivos do "Android Beam", você receberá um URI de conteúdo na intent ACTION_VIEW
se o primeiro arquivo recebido tiver um tipo MIME de "audio/*", "image/*" ou "video/*", indicando que o arquivo é relacionado a mídia. A transferência de arquivos do "Android Beam" indexa os arquivos de mídia transferidos executando o Media Scanner no diretório em que armazena os arquivos transferidos. O Media Scanner grava os resultados no provedor de conteúdo MediaStore
e passa um URI de conteúdo para o primeiro arquivo de volta à transferência de arquivos do "Android Beam". Esse URI de conteúdo é aquele que você recebe na Intent
de notificação. Para ver o diretório do primeiro arquivo, recupere-o de MediaStore
usando o URI de conteúdo.
Determinar o provedor de conteúdo
Para determinar se você pode recuperar um diretório de arquivos do URI de conteúdo, determine o provedor de conteúdo associado ao URI chamando Uri.getAuthority()
para ver a autoridade do URI. O resultado tem dois valores possíveis:
-
MediaStore.AUTHORITY
-
O URI é para um arquivo ou arquivos rastreados por
MediaStore
. Recupere o nome completo do arquivo deMediaStore
e veja o diretório no nome do arquivo. - Qualquer outro valor de autoridade
- Um URI de conteúdo de outro provedor de conteúdo. Exiba os dados associados ao URI do conteúdo, mas não veja o diretório do arquivo.
Para ver o diretório de um URI de conteúdo do MediaStore
, execute uma consulta que especifique o URI de conteúdo recebido para o argumento Uri
e a coluna MediaColumns.DATA
para a projeção. O Cursor
retornado contém o caminho completo e o nome do arquivo representado pelo URI. Esse caminho também contém todos os outros arquivos que a transferência de arquivos do Android Beam acabou de copiar para o dispositivo.
O snippet a seguir mostra como testar a autoridade do URI de conteúdo e recuperar o caminho e o nome do arquivo transferido:
Kotlin
... private fun handleContentUri(beamUri: Uri): File? = // Test the authority of the URI if (beamUri.authority == MediaStore.AUTHORITY) { /* * Handle content URIs for other content providers */ ... // For a MediaStore content URI } else { // Get the column that contains the file name val projection = arrayOf(MediaStore.MediaColumns.DATA) val pathCursor = contentResolver.query(beamUri, projection, null, null, null) // Check for a valid cursor if (pathCursor?.moveToFirst() == true) { // Get the column index in the Cursor pathCursor.getColumnIndex(MediaStore.MediaColumns.DATA).let { filenameIndex -> // Get the full file name including path pathCursor.getString(filenameIndex).let { fileName -> // Create a File object for the filename File(fileName) }.parentFile // Return the parent directory of the file } } else { // The query didn't work; return null null } } ...
Java
... public String handleContentUri(Uri beamUri) { // Position of the filename in the query Cursor int filenameIndex; // File object for the filename File copiedFile; // The filename stored in MediaStore String fileName; // Test the authority of the URI if (!TextUtils.equals(beamUri.getAuthority(), MediaStore.AUTHORITY)) { /* * Handle content URIs for other content providers */ // For a MediaStore content URI } else { // Get the column that contains the file name String[] projection = { MediaStore.MediaColumns.DATA }; Cursor pathCursor = getContentResolver().query(beamUri, projection, null, null, null); // Check for a valid cursor if (pathCursor != null && pathCursor.moveToFirst()) { // Get the column index in the Cursor filenameIndex = pathCursor.getColumnIndex( MediaStore.MediaColumns.DATA); // Get the full file name including path fileName = pathCursor.getString(filenameIndex); // Create a File object for the filename copiedFile = new File(fileName); // Return the parent directory of the file return copiedFile.getParentFile(); } else { // The query didn't work; return null return null; } } } ...
Para saber mais sobre como recuperar dados de um provedor de conteúdo, consulte a seção Recuperação de dados do provedor.
Para ver mais informações relacionadas, consulte: