/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.bluetooth;
import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import org.catrobat.catroid.R;
import org.catrobat.catroid.bluetooth.base.BluetoothConnection;
import org.catrobat.catroid.bluetooth.base.BluetoothConnectionFactory;
import org.catrobat.catroid.bluetooth.base.BluetoothDevice;
import org.catrobat.catroid.bluetooth.base.BluetoothDeviceFactory;
import org.catrobat.catroid.bluetooth.base.BluetoothDeviceService;
import org.catrobat.catroid.common.CatroidService;
import org.catrobat.catroid.common.ServiceProvider;
import org.catrobat.catroid.utils.ToastUtil;
import java.util.Set;
public class ConnectBluetoothDeviceActivity extends Activity {
public static final String TAG = ConnectBluetoothDeviceActivity.class.getSimpleName();
public static final String DEVICE_TO_CONNECT = "org.catrobat.catroid.bluetooth.DEVICE";
private static final int DEVICE_MAC_ADDRESS_LENGTH = 18;
private static BluetoothDeviceFactory btDeviceFactory;
private static BluetoothConnectionFactory btConnectionFactory;
protected BluetoothDevice btDevice;
private BluetoothManager btManager;
private ArrayAdapter<String> pairedDevicesArrayAdapter;
private ArrayAdapter<String> newDevicesArrayAdapter;
private static BluetoothDeviceFactory getDeviceFactory() {
if (btDeviceFactory == null) {
btDeviceFactory = new BluetoothDeviceFactoryImpl();
}
return btDeviceFactory;
}
private static BluetoothConnectionFactory getConnectionFactory() {
if (btConnectionFactory == null) {
btConnectionFactory = new BluetoothConnectionFactoryImpl();
}
return btConnectionFactory;
}
// hooks for testing
public static void setDeviceFactory(BluetoothDeviceFactory deviceFactory) {
btDeviceFactory = deviceFactory;
}
public static void setConnectionFactory(BluetoothConnectionFactory connectionFactory) {
btConnectionFactory = connectionFactory;
}
public void addPairedDevice(String pairedDevice) {
if (pairedDevicesArrayAdapter != null) {
pairedDevicesArrayAdapter.add(pairedDevice);
}
}
// end hooks for testing
private OnItemClickListener deviceClickListener = new OnItemClickListener() {
private String getSelectedBluetoothAddress(View view) {
String info = ((TextView) view).getText().toString();
if (info.lastIndexOf('-') != info.length() - DEVICE_MAC_ADDRESS_LENGTH) {
return null;
}
return info.substring(info.lastIndexOf('-') + 1);
}
@Override
public void onItemClick(AdapterView<?> av, View view, int position, long id) {
String address = getSelectedBluetoothAddress(view);
if (address == null) {
return;
}
connectDevice(address);
}
};
private final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (android.bluetooth.BluetoothDevice.ACTION_FOUND.equals(action)) {
android.bluetooth.BluetoothDevice device = intent.getParcelableExtra(android.bluetooth.BluetoothDevice.EXTRA_DEVICE);
if ((device.getBondState() != android.bluetooth.BluetoothDevice.BOND_BONDED)) {
newDevicesArrayAdapter.add(device.getName() + "-" + device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
findViewById(R.id.device_list_progress_bar).setVisibility(View.GONE);
setTitle(getString(R.string.select_device) + " " + btDevice.getName());
if (newDevicesArrayAdapter.isEmpty()) {
String noDevices = getResources().getString(R.string.none_found);
newDevicesArrayAdapter.add(noDevices);
}
}
}
};
private class ConnectDeviceTask extends AsyncTask<String, Void, BluetoothConnection.State> {
BluetoothConnection btConnection;
private ProgressDialog connectingProgressDialog;
@Override
protected void onPreExecute() {
setVisible(false);
connectingProgressDialog = ProgressDialog.show(ConnectBluetoothDeviceActivity.this, "",
getResources().getString(R.string.connecting_please_wait), true);
}
@Override
protected BluetoothConnection.State doInBackground(String... addresses) {
if (btDevice == null) {
Log.e(TAG, "Try connect to device which is not implemented!");
return BluetoothConnection.State.NOT_CONNECTED;
}
btConnection = getConnectionFactory().createBTConnectionForDevice(btDevice.getDeviceType(), addresses[0],
btDevice.getBluetoothDeviceUUID(), ConnectBluetoothDeviceActivity.this.getApplicationContext());
return btConnection.connect();
}
@Override
protected void onPostExecute(BluetoothConnection.State connectionState) {
connectingProgressDialog.dismiss();
int result = RESULT_CANCELED;
if (connectionState == BluetoothConnection.State.CONNECTED) {
btDevice.setConnection(btConnection);
result = RESULT_OK;
BluetoothDeviceService btDeviceService = ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE);
btDeviceService.deviceConnected(btDevice);
} else {
ToastUtil.showError(ConnectBluetoothDeviceActivity.this, R.string.bt_connection_failed);
}
setResult(result);
finish();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createAndSetDeviceService();
setContentView(R.layout.device_list);
setTitle(getString(R.string.select_device) + " " + btDevice.getName());
setResult(Activity.RESULT_CANCELED);
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
doDiscovery();
view.setVisibility(View.GONE);
}
});
pairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
newDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(pairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(deviceClickListener);
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(newDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(deviceClickListener);
IntentFilter filter = new IntentFilter(android.bluetooth.BluetoothDevice.ACTION_FOUND);
this.registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(receiver, filter);
int bluetoothState = activateBluetooth();
if (bluetoothState == BluetoothManager.BLUETOOTH_ALREADY_ON) {
listAndSelectDevices();
}
}
private void listAndSelectDevices() {
Set<android.bluetooth.BluetoothDevice> pairedDevices = btManager.getBluetoothAdapter().getBondedDevices();
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (android.bluetooth.BluetoothDevice device : pairedDevices) {
pairedDevicesArrayAdapter.add(device.getName() + "-" + device.getAddress());
}
}
if (pairedDevices.size() == 0) {
String noDevices = getResources().getText(R.string.none_paired).toString();
pairedDevicesArrayAdapter.add(noDevices);
}
this.setVisible(true);
}
protected void createAndSetDeviceService() {
Class<BluetoothDevice> serviceType = (Class<BluetoothDevice>) getIntent().getSerializableExtra(DEVICE_TO_CONNECT);
btDevice = getDeviceFactory().createDevice(serviceType, this.getApplicationContext());
}
private void connectDevice(String address) {
btManager.getBluetoothAdapter().cancelDiscovery();
new ConnectDeviceTask().execute(address);
}
@Override
protected void onDestroy() {
if (btManager != null && btManager.getBluetoothAdapter() != null) {
btManager.getBluetoothAdapter().cancelDiscovery();
}
this.unregisterReceiver(receiver);
super.onDestroy();
}
private void doDiscovery() {
setProgressBarIndeterminateVisibility(true);
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
findViewById(R.id.device_list_progress_bar).setVisibility(View.VISIBLE);
if (btManager.getBluetoothAdapter().isDiscovering()) {
btManager.getBluetoothAdapter().cancelDiscovery();
}
btManager.getBluetoothAdapter().startDiscovery();
}
private int activateBluetooth() {
btManager = new BluetoothManager(this);
int bluetoothState = btManager.activateBluetooth();
if (bluetoothState == BluetoothManager.BLUETOOTH_NOT_SUPPORTED) {
ToastUtil.showError(this, R.string.notification_blueth_err);
setResult(Activity.RESULT_CANCELED);
finish();
}
return bluetoothState;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i(TAG, "Bluetooth activation activity returned");
switch (resultCode) {
case Activity.RESULT_OK:
listAndSelectDevices();
break;
case Activity.RESULT_CANCELED:
ToastUtil.showError(this, R.string.notification_blueth_err);
setResult(Activity.RESULT_CANCELED);
finish();
break;
}
}
}