Back to project page Bluebit.
The source code is released under:
Apache License
If you think the Android project Bluebit listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
// vim: et sw=4 sts=4 tabstop=4 /*/* w w w.ja v a2 s. co m*/ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.issc.ui; import com.issc.Bluebit; import com.issc.gatt.Gatt; import com.issc.gatt.GattAdapter; import com.issc.impl.LeService; import com.issc.R; import com.issc.util.Log; import com.issc.util.Util; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import android.app.Activity; import android.app.Dialog; import android.app.ListActivity; import android.app.ProgressDialog; import android.bluetooth.BluetoothDevice; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; /** * To scan BLE devices around user. * * The scanned results will be put into a List. * We can select one of these devices to discover services of it. * Or to get more detail by long-pressing. */ public class ActivityDeviceChooser extends ListActivity { private Button mBtnScan; private ProgressDialog mScanningDialog; private BaseAdapter mAdapter; private List<Map<String, Object>> mRecords; private final static String sName = "_name"; private final static String sAddr = "_address"; private final static String sExtra = "_come_from"; private final static String sDevice = "_bluetooth_device"; private final static int SCAN_DIALOG = 1; /* request code to ask a activity to connect to a device */ private final static int REQUEST_CONNECT_DEVICE = 0x201; private final static int MENU_DETAIL = 0; private final static int MENU_CHOOSE = 1; private Intent mHandler; private LeService mService; private ScanCallback mScanCallback; private SrvConnection mConn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_device_chooser); if (!getIntent().hasExtra(Bluebit.EXTRA_TARGET)) { finish(); Log.d("Not specified target activity"); return; } mHandler = (Intent)getIntent().getExtras().getParcelable(Bluebit.EXTRA_TARGET); mBtnScan = (Button) findViewById(R.id.btn_scan); registerForContextMenu(getListView()); mScanCallback = new ScanCallback(); initAdapter(); mConn = new SrvConnection(); } @Override protected void onDestroy() { super.onDestroy(); } @Override protected void onResume() { super.onResume(); // once we bound to LeService, register our listener bindService(new Intent(this, LeService.class), mConn, 0); } @Override protected void onPause() { super.onPause(); mService = null; unbindService(mConn); } private void initAdapter() { String[] from = {sName, sAddr, sExtra}; int[] to = {R.id.row_title, R.id.row_description, R.id.row_extra}; mRecords = new ArrayList<Map<String, Object>>(); mAdapter = new SimpleAdapter( this, mRecords, R.layout.row_device, from, to ); setListAdapter(mAdapter); } public void onClickBtnScan(View v) { startScan(); } @Override protected Dialog onCreateDialog(int id, Bundle args) { /* To show a loading icon when scanning */ if (id == SCAN_DIALOG) { mScanningDialog = new ProgressDialog(this); mScanningDialog.setMessage(this.getString(R.string.scanning)); mScanningDialog.setOnCancelListener(new Dialog.OnCancelListener() { public void onCancel(DialogInterface dialog) { stopScan(); } }); return mScanningDialog; } return null; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) { super.onCreateContextMenu(menu, v, info); if (v == getListView()) { menu.setHeaderTitle(R.string.device_menu_title); menu.add(0, MENU_DETAIL, Menu.NONE, R.string.device_menu_detail); menu.add(0, MENU_CHOOSE, Menu.NONE, R.string.device_menu_choose); } } @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); int pos = info.position; int id = item.getItemId(); if (id == MENU_DETAIL) { Intent i = new Intent(this, ActivityDeviceDetail.class); i.putExtra(Bluebit.CHOSEN_DEVICE, (BluetoothDevice)mRecords.get(pos).get(sDevice)); startActivity(i); } else if (id == MENU_CHOOSE) { mHandler.putExtra(Bluebit.CHOSEN_DEVICE, (BluetoothDevice)mRecords.get(pos).get(sDevice)); startActivityForResult(mHandler, REQUEST_CONNECT_DEVICE); } return true; } @Override protected void onActivityResult(int request, int result, Intent data) { if (request == REQUEST_CONNECT_DEVICE) { if (result == Bluebit.RESULT_REMOTE_DISCONNECT) { Toast.makeText(this, R.string.disconnected, Toast.LENGTH_SHORT).show(); } } } private void startScan() { Log.d("Scanning Devices"); showDialog(SCAN_DIALOG); // connected device will be ingored when scanning. resetList(); appendConnectedDevices(); appendBondDevices(); mService.startScan(mScanCallback); } private void stopScan() { Log.d("Stop scanning"); mService.stopScan(mScanCallback); } private void appendConnectedDevices() { this.runOnUiThread(new Runnable() { public void run() { appendDevices(mService.getConnectedDevices(), "connected"); mAdapter.notifyDataSetChanged(); } }); } /** * Clear and append bond device to List. * * We should list bond device although we might not connect to it, so user * is able to remove bond. */ private void resetList() { this.runOnUiThread(new Runnable() { public void run() { mRecords.clear(); mAdapter.notifyDataSetChanged(); } }); } private void appendBondDevices() { Set<BluetoothDevice> bonded = Util.getBondedDevices(); if (bonded != null) { Iterator<BluetoothDevice> it = bonded.iterator(); while(it.hasNext()) { BluetoothDevice device = it.next(); Log.d("Bonded device:" + device.getName() + ", " + device.getAddress()); appendDevice(device, "bonded"); } } } private void appendDevices(Iterable<BluetoothDevice> bonded, String type) { if (bonded == null) { return; } Iterator<BluetoothDevice> it = bonded.iterator(); while(it.hasNext()) { appendDevice(it.next(), type); } } private void appendDevice(final BluetoothDevice device, final String type) { this.runOnUiThread(new Runnable() { public void run() { uiAppendDevice(device, type); } }); } /** * Append Device to List in UI thread. * * There is just only one UI thread(main thread) so it guarantee single * thread. Only the UI thread could modify List. */ private void uiAppendDevice(BluetoothDevice device, String type) { if (uiIsInList(device)) { return; } final Map<String, Object> record = new HashMap<String, Object>(); record.put(sName, device.getName()); record.put(sAddr, device.getAddress()); record.put(sDevice, device); record.put(sExtra, type); mRecords.add(record); mAdapter.notifyDataSetChanged(); } /** * To check whether a device is already in List. * * This method should be called in UI thread(main thread) so it does not * worry about the List will be modify form another thread. */ private boolean uiIsInList(BluetoothDevice device) { Iterator<Map<String, Object>> it = mRecords.iterator(); while(it.hasNext()) { Map<String, Object> item = it.next(); if (item.get(sAddr).toString().equals(device.getAddress())) { return true; } } return false; } @Override public void onListItemClick(ListView parent, View view, int position, long id) { mHandler.putExtra(Bluebit.CHOSEN_DEVICE, (BluetoothDevice)mRecords.get(position).get(sDevice)); startActivityForResult(mHandler, REQUEST_CONNECT_DEVICE); } class ScanCallback implements GattAdapter.LeScanCallback { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { appendDevice(device, ""); } } class SrvConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mService = ((LeService.LocalBinder)service).getService(); resetList(); } @Override public void onServiceDisconnected(ComponentName componentName) { Log.e("Gatt Service disconnected"); } } }