content: package com.alexkang.bluechat;
  
  import android.app.Activity;
  import android.app.ProgressDialog;
  import android.bluetooth.BluetoothAdapter;
  import android.bluetooth.BluetoothClass;
  import android.bluetooth.BluetoothDevice;
  import android.bluetooth.BluetoothSocket;
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.SharedPreferences;
  import android.database.Cursor;
  import android.graphics.Bitmap;
  import android.graphics.BitmapFactory;
  import android.graphics.Matrix;
  import android.net.Uri;
  import android.os.Bundle;
  import android.preference.PreferenceManager;
  import android.provider.MediaStore;
  import android.view.MenuItem;
  import android.view.View;
  import android.widget.Button;
  import android.widget.EditText;
  import android.widget.Toast;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.util.ArrayList;
  
  public class ClientActivity extends Activity {
  
      public static final int PICK_IMAGE = 1;
  
      private ArrayList<Integer> acceptableDevices = new ArrayList<>();
  
      private EditText mMessage;
      private ProgressDialog mProgressDialog;
  
      private String mUsername;
      private BluetoothAdapter mBluetoothAdapter;
      private BluetoothSocket mSocket;
  
      private ChatManager mChatManager;
  
      private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
              String action = intent.getAction();
  
              if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                  BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                  int deviceClass = device.getBluetoothClass().getDeviceClass();
  
                  if (acceptableDevices.contains(deviceClass)) {
                      new ConnectThread(device).start();
                  }
              }
          }
      };
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_chatroom);
          if (getActionBar() != null) {
              getActionBar().setDisplayHomeAsUpEnabled(true);
          }
  
          acceptableDevices.add(BluetoothClass.Device.COMPUTER_HANDHELD_PC_PDA);
          acceptableDevices.add(BluetoothClass.Device.COMPUTER_PALM_SIZE_PC_PDA);
          acceptableDevices.add(BluetoothClass.Device.PHONE_SMART);
  
          Button mAttachButton = (Button) findViewById(R.id.attach);
          Button mSendButton = (Button) findViewById(R.id.send);
          mMessage = (EditText) findViewById(R.id.message);
          mChatManager = new ChatManager(this, false);
          mProgressDialog = new ProgressDialog(this);
  
          mAttachButton.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  uploadAttachment();
              }
          });
  
          mSendButton.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  sendMessage();
              }
          });
  
          mProgressDialog.setMessage(getString(R.string.looking_for_chatroom));
          mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
              @Override
              public void onCancel(DialogInterface dialogInterface) {
                  finish();
              }
          });
          mProgressDialog.show();
  
          mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  
          SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
          mUsername = sharedPref.getString("username", mBluetoothAdapter.getName());
  
          startDeviceSearch();
      }
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          int id = item.getItemId();
          if (id == android.R.id.home) {
              Intent i = new Intent(this, MainActivity.class);
              startActivity(i);
              finish();
          }
          return super.onOptionsItemSelected(item);
      }
  
      private void startDeviceSearch() {
          mBluetoothAdapter.enable();
          IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
          registerReceiver(mReceiver, filter);
  
          new WaitForBluetoothThread().start();
      }
  
      private void sendMessage() {
          byte[] byteArray;
  
          if (mMessage.getText().toString().length() == 0) {
              return;
          }
  
          try {
              byte[] messageBytes = mMessage.getText().toString().getBytes();
              byteArray = mChatManager.buildPacket(
                      ChatManager.MESSAGE_SEND,
                      mUsername,
                      messageBytes
              );
          } catch (Exception e) {
              return;
          }
  
          mChatManager.writeMessage(byteArray);
          mMessage.setText("");
      }
  
      private void uploadAttachment() {
          Intent i = new Intent();
          i.setType("image/*");
          i.setAction(Intent.ACTION_PICK);
          startActivityForResult(Intent.createChooser(i, getString(R.string.select_picture)), PICK_IMAGE);
      }
  
      @Override
      public void onActivityResult(int requestCode, int resultCode, Intent data) {
          if (requestCode == PICK_IMAGE) {
              if (resultCode == RESULT_OK) {
                  Uri image = data.getData();
                  String[] filePathColumn = {MediaStore.Images.Media.DATA};
                  Cursor cursor = getContentResolver().query(image, filePathColumn, null, null, null);
  
                  cursor.moveToFirst();
                  int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                  String picturePath = cursor.getString(columnIndex);
  
                  new SendImageThread(picturePath).start();
                  cursor.close();
              }
          }
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
  
          unregisterReceiver(mReceiver);
  
          if (mSocket != null) {
              try {
                  mSocket.close();
              } catch (IOException e) {
                  System.err.println("Failed to close socket");
                  System.err.println(e.toString());
              }
          }
  
          if (mProgressDialog.isShowing()) {
              mProgressDialog.dismiss();
          }
  
          mBluetoothAdapter.cancelDiscovery();
      }
  
      private void manageSocket(BluetoothSocket socket) {
          mSocket = socket;
          mChatManager.startConnection(socket, mProgressDialog);
      }
  
      private class WaitForBluetoothThread extends Thread {
  
          public void run() {
              while (true) {
                  if (mBluetoothAdapter.isEnabled()) {
                      mBluetoothAdapter.startDiscovery();
                      break;
                  }
              }
          }
  
      }
  
      private class SendImageThread extends Thread {
  
          private Bitmap bitmap;
  
          public SendImageThread(String picturePath) {
              this.bitmap = BitmapFactory.decodeFile(picturePath);
          }
  
          public void run() {
              if (bitmap == null) {
                  runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                          Toast.makeText(getBaseContext(), getString(R.string.image_is_incompatible), Toast.LENGTH_SHORT).show();
                      }
                  });
  
                  return;
              }
              
              if (bitmap.getWidth() > 1024 || bitmap.getHeight() > 1024) {
                  float scalingFactor;
  
                  if (bitmap.getWidth() >= bitmap.getHeight()) {
                      scalingFactor = 1024f / bitmap.getWidth();
                  } else {
                      Matrix fixRotation = new Matrix();
                      fixRotation.postRotate(90);
                      scalingFactor = 1024f / bitmap.getHeight();
                  }
  
                  bitmap = Bitmap.createScaledBitmap(
                          bitmap,
                          (int) (bitmap.getWidth() * scalingFactor),
                          (int) (bitmap.getHeight() * scalingFactor),
                          false
                  );
              }
  
              try {
                  ByteArrayOutputStream output = new ByteArrayOutputStream();
                  bitmap.compress(Bitmap.CompressFormat.JPEG, 15, output);
                  byte[] imageBytes = output.toByteArray();
                  byte[] packet = mChatManager.buildPacket(
                          ChatManager.MESSAGE_SEND_IMAGE,
                          mUsername,
                          imageBytes
                  );
                  mChatManager.writeMessage(packet);
              } catch (Exception e) {
                  System.err.println("Failed to send image");
                  System.err.println(e.toString());
              }
          }
  
      }
  
      private class ConnectThread extends Thread {
  
          private final BluetoothSocket mmSocket;
  
          public ConnectThread(BluetoothDevice device) {
              BluetoothSocket tmp = null;
  
              try {
                  tmp = device.createRfcommSocketToServiceRecord(
                          java.util.UUID.fromString(MainActivity.UUID));
              } catch (Exception e) {
                  System.err.println("Failed to connect");
                  System.err.println(e.toString());
              }
  
              mmSocket = tmp;
          }
  
          public void run() {
              try {
                  mmSocket.connect();
              } catch (IOException e) {
                  try {
                      mmSocket.close();
                  } catch (IOException e2) {
                      return;
                  }
              }
  
              runOnUiThread(new Runnable() {
                  @Override
                  public void run() {
                      manageSocket(mmSocket);
                  }
              });
          }
  
      }
  
  }
  