Visão geral do Wi-Fi Direct (ponto a ponto ou P2P)

O Wi-Fi Direct (P2P) permite que dispositivos com o hardware adequado se conectem diretamente uns aos outros via Wi-Fi sem um ponto de acesso intermediário. Com essas APIs, você pode descobrir e se conectar a outros dispositivos quando cada um deles tem suporte ao Wi-Fi P2P e, em seguida, se comunicar por uma conexão rápida em distâncias por muito mais tempo do que uma conexão Bluetooth. Isso é útil para aplicativos que compartilham dados entre usuários, como um jogo multiplayer ou um aplicativo de compartilhamento de fotos.

As APIs de Wi-Fi P2P são constituídas das seguintes partes principais:

  • Métodos que permitem descobrir, solicitar e se conectar a pares, que são definidos na classe WifiP2pManager.
  • Listeners que permitem que você seja notificado sobre o sucesso ou a falha de chamadas de método WifiP2pManager. Ao chamar métodos WifiP2pManager, cada método pode receber um listener específico transmitido como um parâmetro.
  • Intents que notificam você sobre eventos específicos detectados pelo framework do Wi-Fi P2P, como uma conexão interrompida ou um ponto recém-descoberto.

Com frequência, você usará esses três componentes principais das APIs juntos. Por exemplo, é possível fornecer um WifiP2pManager.ActionListener para uma chamada para discoverPeers() para que os métodos ActionListener.onSuccess() e ActionListener.onFailure() possam notificar você. Uma intent WIFI_P2P_PEERS_CHANGED_ACTION também será transmitida se o método discoverPeers() descobrir que a lista de peerings mudou.

Visão geral da API

A classe WifiP2pManager oferece métodos para que você possa interagir com o hardware de Wi-Fi no dispositivo para realizar ações como descobrir e se conectar a apps semelhantes. As seguintes ações estão disponíveis:

Tabela 1. Métodos de Wi-Fi P2P

Método Description
initialize() Registra o aplicativo com a biblioteca Wi-Fi. Chame esse método antes de chamar qualquer outro método Wi-Fi P2P.
connect() Inicia uma conexão ponto a ponto com um dispositivo com a configuração especificada.
cancelConnect() Cancela qualquer negociação de grupo ponto a ponto em andamento.
requestConnectInfo() Solicita informações de conexão de um dispositivo.
createGroup() Cria um grupo ponto a ponto com o dispositivo atual como proprietário do grupo.
removeGroup() Remove o atual grupo ponto a ponto.
requestGroupInfo() Solicita informações do grupo ponto a ponto.
discoverPeers() Inicia a descoberta de pontos.
requestPeers() Solicita a lista atual de pontos descobertos.

Os métodos WifiP2pManager permitem transmitir um listener para que o framework do Wi-Fi P2P possa notificar sua atividade sobre o status de uma chamada. As interfaces de listener disponíveis e as chamadas de método WifiP2pManager correspondentes que usam os listeners são descritas na Tabela 2.

Tabela 2. Listeners de Wi-Fi P2P

Interface do listener Ações associadas
WifiP2pManager.ActionListener connect(), cancelConnect(), createGroup(), removeGroup() e discoverPeers()
WifiP2pManager.ChannelListener initialize()
WifiP2pManager.ConnectionInfoListener requestConnectInfo()
WifiP2pManager.GroupInfoListener requestGroupInfo()
WifiP2pManager.PeerListListener requestPeers()

As APIs de Wi-Fi P2P definem intents que são transmitidas quando determinados eventos de Wi-Fi P2P acontecem, por exemplo, quando um novo peering é descoberto ou quando o estado do Wi-Fi de um dispositivo muda. Faça o registro para receber essas intents no seu aplicativo criando um broadcast receiver que processe essas intents:

Tabela 3. Intents de Wi-Fi P2P

Intent Description
WIFI_P2P_CONNECTION_CHANGED_ACTION Transmite quando o estado da conexão Wi-Fi do dispositivo muda.
WIFI_P2P_PEERS_CHANGED_ACTION Transmitir quando você chamar discoverPeers(). Geralmente, você chamará requestPeers() para ver uma lista atualizada de pares se processar essa intent no seu aplicativo.
WIFI_P2P_STATE_CHANGED_ACTION Transmitido quando o Wi-Fi P2P está ativado ou desativado no dispositivo.
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION transmitir quando os detalhes de um dispositivo forem alterados, como o nome;

Criar um broadcast receiver para intents de Wi-Fi P2P

Um broadcast receiver permite que você receba intents transmitidas pelo sistema Android para que seu app possa responder a eventos em que você tem interesse. As etapas básicas para criar um broadcast receiver e processar intents de Wi-Fi P2P são as seguintes:

  1. Crie uma classe que estenda a BroadcastReceiver. Para o construtor da classe, você usará parâmetros para WifiP2pManager, WifiP2pManager.Channel e a atividade em que esse broadcast receiver será registrado. Isso permite que o broadcast receiver envie atualizações para a atividade, além de ter acesso ao hardware de Wi-Fi e a um canal de comunicação, se necessário.

  2. No broadcast receiver, verifique as intents em que você tem interesse no método onReceive(). Realize as ações necessárias, dependendo da intent recebida. Por exemplo, se o broadcast receiver receber uma intent WIFI_P2P_PEERS_CHANGED_ACTION, você poderá chamar o método requestPeers() para acessar uma lista dos pontos descobertos no momento.

O código a seguir mostra como criar um broadcast receiver típico. O broadcast receiver usa um objeto WifiP2pManager e uma atividade como argumentos e usa essas duas classes para realizar corretamente as ações necessárias quando o broadcast receiver recebe uma intent:

Kotlin

/**
* A BroadcastReceiver that notifies of important Wi-Fi p2p events.
*/
class WiFiDirectBroadcastReceiver(
       private val manager: WifiP2pManager,
       private val channel: WifiP2pManager.Channel,
       private val activity: MyWifiActivity
) : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       val action: String = intent.action
       when (action) {
           WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> {
               // Check to see if Wi-Fi is enabled and notify appropriate activity
           }
           WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
               // Call WifiP2pManager.requestPeers() to get a list of current peers
           }
           WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {
               // Respond to new connection or disconnections
           }
           WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> {
               // Respond to this device's wifi state changing
           }
       }
   }
}

Java

/**
* A BroadcastReceiver that notifies of important Wi-Fi p2p events.
*/
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {

   private WifiP2pManager manager;
   private Channel channel;
   private MyWiFiActivity activity;

   public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
           MyWifiActivity activity) {
       super();
       this.manager = manager;
       this.channel = channel;
       this.activity = activity;
   }

   @Override
   public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();

       if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
           // Check to see if Wi-Fi is enabled and notify appropriate activity
       } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
           // Call WifiP2pManager.requestPeers() to get a list of current peers
       } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
           // Respond to new connection or disconnections
       } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
           // Respond to this device's wifi state changing
       }
   }
}

Em dispositivos com o Android 10 e versões mais recentes, as intents de transmissão abaixo são não fixas:

WIFI_P2P_CONNECTION_CHANGED_ACTION
Os aplicativos podem usar requestConnectionInfo(), requestNetworkInfo() ou requestGroupInfo() para recuperar as informações de conexão atuais.
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
Os aplicativos podem usar requestDeviceInfo() para recuperar as informações de conexão atuais.

Criar um aplicativo Wi-Fi P2P

A criação de um aplicativo Wi-Fi P2P envolve a criação e o registro de um broadcast receiver para o aplicativo, a descoberta de pontos, a conexão a um peering e a transferência de dados para um peering. As seções a seguir descrevem como fazer isso.

Configuração inicial

Antes de usar as APIs de Wi-Fi P2P, confira se o aplicativo pode acessar o hardware e se o dispositivo oferece suporte ao protocolo Wi-Fi P2P. Se oferecer suporte ao Wi-Fi P2P, você poderá acessar uma instância de WifiP2pManager, criar e registrar seu broadcast receiver e começar a usar as APIs de Wi-Fi P2P.

  1. Solicite permissão para usar o hardware de Wi-Fi no dispositivo e declare que seu aplicativo tem a versão mínima correta do SDK no manifesto do Android:

    <uses-sdk android:minSdkVersion="14" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- If your app targets Android 13 (API level 33)
         or higher, you must declare the NEARBY_WIFI_DEVICES permission. -->
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
                     <!-- If your app derives location information from
                          Wi-Fi APIs, don't include the "usesPermissionFlags"
                          attribute. -->
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     <!-- If any feature in your app relies on precise location
                          information, don't include the "maxSdkVersion"
                          attribute. -->
                     android:maxSdkVersion="32" />
    

    Além das permissões anteriores, as seguintes APIs também exigem que o modo de localização esteja ativado:

  2. Verifique se o Wi-Fi P2P está ativado e é compatível. Um bom lugar para verificar isso é no broadcast receiver quando ele recebe a intent WIFI_P2P_STATE_CHANGED_ACTION. Notifique sua atividade do estado do Wi-Fi P2P e reaja de acordo:

    Kotlin

    override fun onReceive(context: Context, intent: Intent) {
    ...
    val action: String = intent.action
    when (action) {
       WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> {
           val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)
           when (state) {
               WifiP2pManager.WIFI_P2P_STATE_ENABLED -> {
                   // Wifi P2P is enabled
               }
               else -> {
                   // Wi-Fi P2P is not enabled
               }
           }
       }
    }
    ...
    }
    

    Java

    @Override
    public void onReceive(Context context, Intent intent) {
    ...
    String action = intent.getAction();
    if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
       int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
       if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
           // Wifi P2P is enabled
       } else {
           // Wi-Fi P2P is not enabled
       }
    }
    ...
    }
    
  3. No método onCreate() da atividade, receba uma instância de WifiP2pManager e registre seu aplicativo com o framework Wi-Fi P2P chamando initialize(). Esse método retorna um WifiP2pManager.Channel, que é usado para conectar seu aplicativo ao framework do Wi-Fi P2P. Você também precisa criar uma instância do broadcast receiver com os objetos WifiP2pManager e WifiP2pManager.Channel, além de uma referência à sua atividade. Isso permite que o broadcast receiver notifique sua atividade sobre eventos interessantes e a atualize de forma adequada. Ela também permite manipular o estado do Wi-Fi do dispositivo, se necessário:

    Kotlin

    val manager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) {
       getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
    }
    
    var channel: WifiP2pManager.Channel? = null
    var receiver: BroadcastReceiver? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    
       channel = manager?.initialize(this, mainLooper, null)
       channel?.also { channel ->
           receiver = WiFiDirectBroadcastReceiver(manager, channel, this)
       }
    }
    

    Java

    WifiP2pManager manager;
    Channel channel;
    BroadcastReceiver receiver;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState){
       ...
       manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
       channel = manager.initialize(this, getMainLooper(), null);
       receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
       ...
    }
    
  4. Crie um filtro de intent e adicione as mesmas intents que o broadcast receiver verifica:

    Kotlin

    val intentFilter = IntentFilter().apply {
       addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)
       addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
       addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
       addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)
    }
    

    Java

    IntentFilter intentFilter;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState){
       ...
       intentFilter = new IntentFilter();
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
       ...
    }
    
  5. Registre o broadcast receiver no método onResume() da sua atividade e cancele o registro no método onPause() da atividade:

    Kotlin

    /* register the broadcast receiver with the intent values to be matched */
    override fun onResume() {
       super.onResume()
       receiver?.also { receiver ->
           registerReceiver(receiver, intentFilter)
       }
    }
    
    /* unregister the broadcast receiver */
    override fun onPause() {
       super.onPause()
       receiver?.also { receiver ->
           unregisterReceiver(receiver)
       }
    }
    

    Java

    /* register the broadcast receiver with the intent values to be matched */
    @Override
    protected void onResume() {
       super.onResume();
       registerReceiver(receiver, intentFilter);
    }
    /* unregister the broadcast receiver */
    @Override
    protected void onPause() {
       super.onPause();
       unregisterReceiver(receiver);
    }
    
  6. Depois de receber um WifiP2pManager.Channel e configurar um broadcast receiver, seu app pode fazer chamadas de método Wi-Fi P2P e receber intents de Wi-Fi P2P.

  7. Implemente o aplicativo usando os recursos de Wi-Fi P2P chamando os métodos em WifiP2pManager.

As próximas seções descrevem como realizar ações comuns, como descobrir e conectar-se a pontos.

Descobrir pontos

Chame discoverPeers() para detectar os peerings disponíveis que estão dentro do alcance e disponíveis para conexão. A chamada para essa função é assíncrona, e um sucesso ou falha é comunicado ao aplicativo com onSuccess() e onFailure() se você tiver criado um WifiP2pManager.ActionListener. O método onSuccess() só informa que o processo de descoberta foi bem-sucedido e não fornece nenhuma informação sobre os pares reais descobertos, se houver. O exemplo de código a seguir mostra como configurar isso.

Kotlin

manager?.discoverPeers(channel, object : WifiP2pManager.ActionListener {

   override fun onSuccess() {
       ...
   }

   override fun onFailure(reasonCode: Int) {
       ...
   }
})

Java

manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
   @Override
   public void onSuccess() {
       ...
   }

   @Override
   public void onFailure(int reasonCode) {
       ...
   }
});

Se o processo de descoberta for bem-sucedido e detectar peering, o sistema transmitirá a intent WIFI_P2P_PEERS_CHANGED_ACTION, que pode ser detectada em um broadcast receiver para uma lista de peerings. Quando seu aplicativo recebe a intent WIFI_P2P_PEERS_CHANGED_ACTION, é possível solicitar uma lista dos peerings descobertos com requestPeers(). O código a seguir mostra como configurar isso.

Kotlin

override fun onReceive(context: Context, intent: Intent) {
   val action: String = intent.action
   when (action) {
       ...
       WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
           manager?.requestPeers(channel) { peers: WifiP2pDeviceList? ->
               // Handle peers list
           }
       }
       ...
   }
}

Java

PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

   // request available peers from the wifi p2p manager. This is an
   // asynchronous call and the calling activity is notified with a
   // callback on PeerListListener.onPeersAvailable()
   if (manager != null) {
       manager.requestPeers(channel, myPeerListListener);
   }
}

O método requestPeers() também é assíncrono e pode notificar sua atividade quando uma lista de pares está disponível com onPeersAvailable(), que é definido na interface WifiP2pManager.PeerListListener. O método onPeersAvailable() fornece um WifiP2pDeviceList, que pode ser iterado para encontrar o peering ao qual se conectar.

Conectar pontos

Depois de ter uma lista de possíveis pares e selecionar um dispositivo para se conectar, chame o método connect() para se conectar ao dispositivo. Essa chamada de método requer um objeto WifiP2pConfig que contenha informações sobre o dispositivo a ser conectado. WifiP2pManager.ActionListener pode notificá-lo de uma conexão bem-sucedida ou falha. O código a seguir mostra como criar uma conexão com um dispositivo.

Kotlin

val device: WifiP2pDevice = ...
val config = WifiP2pConfig()
config.deviceAddress = device.deviceAddress
channel?.also { channel ->
   manager?.connect(channel, config, object : WifiP2pManager.ActionListener {

       override fun onSuccess() {
           //success logic
       }

       override fun onFailure(reason: Int) {
           //failure logic
       }
   }
)}

Java

//obtain a peer from the WifiP2pDeviceList
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
manager.connect(channel, config, new ActionListener() {

   @Override
   public void onSuccess() {
       //success logic
   }

   @Override
   public void onFailure(int reason) {
       //failure logic
   }
});

Transferir dados

Depois que uma conexão for estabelecida, você poderá transferir dados entre os dispositivos com soquetes. Veja as etapas básicas da transferência de dados:

  1. Crie um ServerSocket. Esse soquete aguarda uma conexão de um cliente em uma porta especificada e fica bloqueada até que ela aconteça. Portanto, faça isso em uma linha de execução em segundo plano.
  2. Crie um cliente Socket. O cliente usa o endereço IP e a porta do soquete do servidor para se conectar ao dispositivo do servidor.
  3. Envie os dados do cliente para o servidor. Quando o soquete do cliente se conectar ao soquete do servidor, será possível enviar dados do cliente para o servidor com streams de bytes.
  4. O soquete do servidor aguarda uma conexão do cliente (com o método accept()). Essa chamada é bloqueada até que um cliente se conecte. Portanto, faça a chamada em outra linha de execução. Quando ocorre uma conexão, o dispositivo servidor pode receber os dados do cliente.

O exemplo a seguir, modificado da Demonstração de Wi-Fi P2P, mostra como criar essa comunicação de soquete cliente-servidor e transferir imagens JPEG de um cliente para um servidor com um serviço. Para conferir um exemplo completo, compile e execute a demonstração.

Kotlin

class FileServerAsyncTask(
       private val context: Context,
       private var statusText: TextView
) : AsyncTask<Void, Void, String?>() {

   override fun doInBackground(vararg params: Void): String? {
       /**
        * Create a server socket.
        */
       val serverSocket = ServerSocket(8888)
       return serverSocket.use {
           /**
            * Wait for client connections. This call blocks until a
            * connection is accepted from a client.
            */
           val client = serverSocket.accept()
           /**
            * If this code is reached, a client has connected and transferred data
            * Save the input stream from the client as a JPEG file
            */
           val f = File(Environment.getExternalStorageDirectory().absolutePath +
                   "/${context.packageName}/wifip2pshared-${System.currentTimeMillis()}.jpg")
           val dirs = File(f.parent)

           dirs.takeIf { it.doesNotExist() }?.apply {
               mkdirs()
           }
           f.createNewFile()
           val inputstream = client.getInputStream()
           copyFile(inputstream, FileOutputStream(f))
           serverSocket.close()
           f.absolutePath
       }
   }

   private fun File.doesNotExist(): Boolean = !exists()

   /**
    * Start activity that can handle the JPEG image
    */
   override fun onPostExecute(result: String?) {
       result?.run {
           statusText.text = "File copied - $result"
           val intent = Intent(android.content.Intent.ACTION_VIEW).apply {
               setDataAndType(Uri.parse("file://$result"), "image/*")
           }
           context.startActivity(intent)
       }
   }
}

Java

public static class FileServerAsyncTask extends AsyncTask {

   private Context context;
   private TextView statusText;

   public FileServerAsyncTask(Context context, View statusText) {
       this.context = context;
       this.statusText = (TextView) statusText;
   }

   @Override
   protected String doInBackground(Void... params) {
       try {

           /**
            * Create a server socket and wait for client connections. This
            * call blocks until a connection is accepted from a client
            */
           ServerSocket serverSocket = new ServerSocket(8888);
           Socket client = serverSocket.accept();

           /**
            * If this code is reached, a client has connected and transferred data
            * Save the input stream from the client as a JPEG file
            */
           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();
           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;
       }
   }

   /**
    * Start activity that can handle the JPEG image
    */
   @Override
   protected void onPostExecute(String result) {
       if (result != null) {
           statusText.setText("File copied - " + result);
           Intent intent = new Intent();
           intent.setAction(android.content.Intent.ACTION_VIEW);
           intent.setDataAndType(Uri.parse("file://" + result), "image/*");
           context.startActivity(intent);
       }
   }
}

No cliente, conecte-se ao soquete do servidor com um soquete do cliente e transfira os dados. Este exemplo transfere um arquivo JPEG no sistema de arquivos do dispositivo cliente.

Kotlin

val context = applicationContext
val host: String
val port: Int
val len: Int
val socket = Socket()
val buf = ByteArray(1024)
...
try {
   /**
    * Create a client socket with the host,
    * port, and timeout information.
    */
   socket.bind(null)
   socket.connect((InetSocketAddress(host, port)), 500)

   /**
    * Create a byte stream from a JPEG file and pipe it to the output stream
    * of the socket. This data is retrieved by the server device.
    */
   val outputStream = socket.getOutputStream()
   val cr = context.contentResolver
   val inputStream: InputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"))
   while (inputStream.read(buf).also { len = it } != -1) {
       outputStream.write(buf, 0, len)
   }
   outputStream.close()
   inputStream.close()
} catch (e: FileNotFoundException) {
   //catch logic
} catch (e: IOException) {
   //catch logic
} finally {
   /**
    * Clean up any open sockets when done
    * transferring or if an exception occurred.
    */
   socket.takeIf { it.isConnected }?.apply {
       close()
   }
}

Java

Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[]  = new byte[1024];
...
try {
   /**
    * Create a client socket with the host,
    * port, and timeout information.
    */
   socket.bind(null);
   socket.connect((new InetSocketAddress(host, port)), 500);

   /**
    * Create a byte stream from a JPEG file and pipe it to the output stream
    * of the socket. This data is retrieved by the server device.
    */
   OutputStream outputStream = socket.getOutputStream();
   ContentResolver cr = context.getContentResolver();
   InputStream inputStream = null;
   inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"));
   while ((len = inputStream.read(buf)) != -1) {
       outputStream.write(buf, 0, len);
   }
   outputStream.close();
   inputStream.close();
} catch (FileNotFoundException e) {
   //catch logic
} catch (IOException e) {
   //catch logic
}

/**
* Clean up any open sockets when done
* transferring or if an exception occurred.
*/
finally {
   if (socket != null) {
       if (socket.isConnected()) {
           try {
               socket.close();
           } catch (IOException e) {
               //catch logic
           }
       }
   }
}