WIFI Direct – Comunicação direta entre dispositivos – Parte 2 – Android

On 5 de maio de 2013 by Urbano

wifi-direct-android

COMUNICAÇÃO DIRETA ENTRE DISPOSITIVOS COM WIFI
PARTE 2 – EXEMPLO DE APLICAÇÃO ANDROID

image002 image003 image004

1. EXEMPLO DE APLICAÇÃO WIFI DIRECT NO ANDROID

Para exemplificar a comunicação entre dois dispositivos com WIFI Direct utilizarei uma aplicação padrão de WIFI Direct (“WiFiDirectDemo”) contida no Android SDK 4.0.x. Esta aplicação tempo por objetivo fazer a troca de arquivos de imagens entre dois dispositivos. Foram feita algumas pequenas alterações na aplicação original. A seguir teremos a sequência das telas da aplicação rodando em dois dispositivos SUMSUNG Galaxy TAB com Android 4.0.4. As duas primeiras imagens são as telas iniciais da aplicação “Urb Wifi Direct” executando nos dispositivos “AndoidP2P4760” e “AndoidP2P9839”.

image005 image006

Figura 1 – Telas iniciais dos dispositivos 4760 (Maquina receptora de imagens) e 9839 (Maquina cliente)

Na próxima tela o dispositivo “AndoidP2P4760” inicia a “conversa” solicitando a abertura da conexão com o dispositivo “AndoidP2P9839”.

image007

Figura 2 – Iniciação da conexão – Dispositivo 4760 (Maquina receptora de imagens)

O dispositivo “AndoidP2P9839” recebe a solicitação de conexão e precisa aceitá-la par afetivar a abertura do canal de comunicação P2P.

image008

Figura 3 – Tela do dispositivo 9839 (Maquina cliente) para aceitar a conexão do 4760

Conexão estabelecida! O dispositivo “AndoidP2P4760” aceitou a conexão do dispositivo “AndoidP2P9839”.

image009

Figura 4 – Conexão estabelecida – Dispositivo 4760 (Maquina receptora de imagens)

Agora o dispositivo “AndoidP2P9839” poderá de abrir a sua galeria para compartilhar alguma imagem com o outro dispositivo.

image010

Figura 5 – Conexão estabelecida – dispositivo 9839 (Maquina cliente)

Deve-se selecionar uma imagem da galeria e esta será envia ao outro dispositivo.

image011

Figura 6 – Seleção de imagem para compartilhar – dispositivo 9839 (Maquina cliente)

Esta última tela é do dispositivo “AndoidP2P4760” no momento em que recebeu a imagem e esta foi exibida n asua tela.

image012

Figura 7 – Imagem recebida e exibida – Dispositivo 4760 (Maquina receptora de imagens)

2. VISÃO TÉCNICA – CÓDIGO FONTE

A seguir serão exibidos e comentados os principais trechos de código da aplicação acima. Começarei pela classe “WiFiDirectActivity”, que é a classe principal do aplicativo e implementa a atividade através da qual os componentes da tela são exibidos.

public class WiFiDirectActivity extends Activity implements ChannelListener, DeviceActionListener {

  . . .

  public void onCreate(Bundle savedInstanceState) {

    . . .

    startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));

    managerWifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);

    managerWifiDirect = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);

    channel = managerWifiDirect.initialize(this, getMainLooper(), null);

    managerWifi.setWifiEnabled(false);

    new CountDownTimer(2000l, 1000l) {

      public void onTick(long millisUntilFinished) {}

      public void onFinish() {

        enableP2p();

      }

    }.start();

  }

 

  private void enableP2p() {

    try {

      Method[] methods = managerWifiDirect.getClass().getMethods();

      for (Method method : methods) {

        if (method.getName().equals(“enableP2p”)) {

          method.invoke(managerWifiDirect, channel);

        }

      }

      setWifiP2pEnabled(true);

     } catch (Exception e) {

      e.printStackTrace();

    }

  }


. . .

}

Dois pontos que considero cruciais do trecho de código acima são a desativação do WIFI (linha que contem “managerWifi.setWifiEnabled(false);” no método “onCreate(..) “) e a ativação do WIFI Direct no método “enableP2p()”. O WIFI Direct só funciona desativando o WIFI. Após desativar o WIFI é preciso esperar entre 1 e 2 segundos para que esta desativação seja efetivada no sistema para então ativar o WIFI Direct. Devido a este fato é que foi preciso adicionar o objeto “new CountDownTimer(2000l, 1000l)” para iniciar o método “enableP2p()” após 2 segundos. Outra curiosidade é a ativação do WIFI Direct que precisou ser feita utilizando “reflection”. Através do código “method.invoke(managerWifiDirect, channel);” o método privado “enableP2p” da classe “WifiP2pManager” pode ser invocado para ativar o WIFI Direct.

Da mesma forma que a desativação do WIFI precisa esperar entre 1 e 2 segundos para ser efetivada, a ativação do WIFI Direct também precisa de um tempo. Devido a este fato é que foi preciso adicionar o objeto “new CountDownTimer(5000l, 1000l)” no corpo do método “postCreate()” para iniciar o método “discoverPeers()” de descoberta de “peers” após 5 segundos do início do aplicativo. Observe o trecho de código a seguir:

  . . .

  public void postCreate() {

 

    new CountDownTimer(5000l, 1000l) {

      publicvoid onTick(long millisUntilFinished) {

      }

      publicvoid onFinish() {

        discoverPeers();

      }

    }.start();

  }

  private boolean discoverPeers() {

    . . .

    return true;

  }

  . . .

A seguir temos um trecho de outra classe crucial na aplicação, a “DeviceDetailFragment”. Esta classe é responsável por controlar a interação entre os dispositivos, possibilitando o estabelecimento de conexões (método “onConnect()” ) e o tráfego de arquivos entes eles (métodos “onActivityResult(..)”, “onConnectionInfoAvailable(..)” ), entre outras funcionalidades. A classe interna “FileServerAsyncTask” também foi usada para auxiliar na transferência de arquivos entre os dispositivos.

dispositivos.

public class DeviceDetailFragment extends Fragment implements ConnectionInfoListener {

 . . .

  public void onConnect() {

    WifiP2pConfig config = new WifiP2pConfig();

    config.deviceAddress = device.deviceAddress;

    config.wps.setup = WpsInfo.PBC;

    if (progressDialog != null && progressDialog.isShowing()) {

      progressDialog.dismiss();

    }

    progressDialog = ProgressDialog.show(getActivity(),

        “Pressione voltar para cancelar”, “Conexão para :” + device.deviceAddress,
true,
true);

    ((DeviceActionListener)getActivity()).connect(config);

  }

 

  @Override
 
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    Uri uri = data.getData();

    TextView statusText = (TextView) mContentView.findViewById(R.id.status_text);

    statusText.setText(Enviando: “ + uri);

    Log.d(WiFiDirectActivity.TAG, “Intent———– ” + uri);

    Intent serviceIntent = new Intent(getActivity FileTransferService.class);

    serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);

    serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString());

    serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,

        info.groupOwnerAddress.getHostAddress());

    serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8988);

    getActivity().startService(serviceIntent);

  }

 

  @Override
 
public void onConnectionInfoAvailable(final WifiP2pInfo info) {   

    . . .

    if (info.groupFormed && info.isGroupOwner) {

      new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text)).execute();

    }     

    . . .

  }

 

  public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {

    . . .

    protected String doInBackground(Void… params) {

      try {

        ServerSocket serverSocket = new ServerSocket(8988);

        Log.d(WiFiDirectActivity.TAG, “Servidor: Socket aberto”);

        Socket client = serverSocket.accept();

        Log.d(WiFiDirectActivity.TAG, Servidor: conexão aberta);

        final File f = new File(Environment.getExternalStorageDirectory()
+
“/”

                + context.getPackageName() + “/wifip2pshared-“

                + System.currentTimeMillis() + “.jpg”);

        File dirs = new File(f.getParent());

        if (!dirs.exists()){

          dirs.mkdirs();

                   }

        f.createNewFile();

        Log.d(WiFiDirectActivity.TAG, “Servidor: copiando arquivos ” + f.toString());

        InputStream inputstream = client.getInputStream();

        copyFile(inputstream, new FileOutputStream(f));

        serverSocket.close();

        return f.getAbsolutePath();

      } catch (IOException e) {

        Log.e(WiFiDirectActivity.TAG, e.getMessage());

        return null;

      }

    }

 

    protected void onPostExecute(String result) {

      if (result != null) {

        statusText.setText(Arquivo copiado – “ + result);

        Intent intent = new Intent();

        intent.setAction(android.content.Intent.ACTION_VIEW);

        intent.setDataAndType(Uri.parse(“file://” + result), “image/*”);

        context.startActivity(intent);

      }

    }

    . . .

  } 

}

Além das duas classes principais citadas anteriormente existem mais duas que merecem ser mencionadas: “DiscoverService” e “FileTransferService”. A primeira é utilizada na tarefa de descobrir os “peers” nas imediações e a segunda é responsável por prover a infraestrutura para transferência de arquivos entre os “peers”.

One Response to “WIFI Direct – Comunicação direta entre dispositivos – Parte 2 – Android”

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *