to top
BluetoothLeGatt / src / com.example.android.bluetoothlegatt /

DeviceScanActivity.java

1
/*
2
 * Copyright (C) 2013 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.example.android.bluetoothlegatt;
18
 
19
import android.app.Activity;
20
import android.app.ListActivity;
21
import android.bluetooth.BluetoothAdapter;
22
import android.bluetooth.BluetoothDevice;
23
import android.bluetooth.BluetoothManager;
24
import android.content.Context;
25
import android.content.Intent;
26
import android.content.pm.PackageManager;
27
import android.os.Bundle;
28
import android.os.Handler;
29
import android.view.LayoutInflater;
30
import android.view.Menu;
31
import android.view.MenuItem;
32
import android.view.View;
33
import android.view.ViewGroup;
34
import android.widget.BaseAdapter;
35
import android.widget.ListView;
36
import android.widget.TextView;
37
import android.widget.Toast;
38
 
39
import java.util.ArrayList;
40
 
41
/**
42
 * Activity for scanning and displaying available Bluetooth LE devices.
43
 */
44
public class DeviceScanActivity extends ListActivity {
45
    private LeDeviceListAdapter mLeDeviceListAdapter;
46
    private BluetoothAdapter mBluetoothAdapter;
47
    private boolean mScanning;
48
    private Handler mHandler;
49
 
50
    private static final int REQUEST_ENABLE_BT = 1;
51
    // Stops scanning after 10 seconds.
52
    private static final long SCAN_PERIOD = 10000;
53
 
54
    @Override
55
    public void onCreate(Bundle savedInstanceState) {
56
        super.onCreate(savedInstanceState);
57
        getActionBar().setTitle(R.string.title_devices);
58
        mHandler = new Handler();
59
 
60
        // Use this check to determine whether BLE is supported on the device.  Then you can
61
        // selectively disable BLE-related features.
62
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
63
            Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
64
            finish();
65
        }
66
 
67
        // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
68
        // BluetoothAdapter through BluetoothManager.
69
        final BluetoothManager bluetoothManager =
70
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
71
        mBluetoothAdapter = bluetoothManager.getAdapter();
72
 
73
        // Checks if Bluetooth is supported on the device.
74
        if (mBluetoothAdapter == null) {
75
            Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
76
            finish();
77
            return;
78
        }
79
    }
80
 
81
    @Override
82
    public boolean onCreateOptionsMenu(Menu menu) {
83
        getMenuInflater().inflate(R.menu.main, menu);
84
        if (!mScanning) {
85
            menu.findItem(R.id.menu_stop).setVisible(false);
86
            menu.findItem(R.id.menu_scan).setVisible(true);
87
            menu.findItem(R.id.menu_refresh).setActionView(null);
88
        } else {
89
            menu.findItem(R.id.menu_stop).setVisible(true);
90
            menu.findItem(R.id.menu_scan).setVisible(false);
91
            menu.findItem(R.id.menu_refresh).setActionView(
92
                    R.layout.actionbar_indeterminate_progress);
93
        }
94
        return true;
95
    }
96
 
97
    @Override
98
    public boolean onOptionsItemSelected(MenuItem item) {
99
        switch (item.getItemId()) {
100
            case R.id.menu_scan:
101
                mLeDeviceListAdapter.clear();
102
                scanLeDevice(true);
103
                break;
104
            case R.id.menu_stop:
105
                scanLeDevice(false);
106
                break;
107
        }
108
        return true;
109
    }
110
 
111
    @Override
112
    protected void onResume() {
113
        super.onResume();
114
 
115
        // Ensures Bluetooth is enabled on the device.  If Bluetooth is not currently enabled,
116
        // fire an intent to display a dialog asking the user to grant permission to enable it.
117
        if (!mBluetoothAdapter.isEnabled()) {
118
            if (!mBluetoothAdapter.isEnabled()) {
119
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
120
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
121
            }
122
        }
123
 
124
        // Initializes list view adapter.
125
        mLeDeviceListAdapter = new LeDeviceListAdapter();
126
        setListAdapter(mLeDeviceListAdapter);
127
        scanLeDevice(true);
128
    }
129
 
130
    @Override
131
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
132
        // User chose not to enable Bluetooth.
133
        if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
134
            finish();
135
            return;
136
        }
137
        super.onActivityResult(requestCode, resultCode, data);
138
    }
139
 
140
    @Override
141
    protected void onPause() {
142
        super.onPause();
143
        scanLeDevice(false);
144
        mLeDeviceListAdapter.clear();
145
    }
146
 
147
    @Override
148
    protected void onListItemClick(ListView l, View v, int position, long id) {
149
        final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);
150
        if (device == null) return;
151
        final Intent intent = new Intent(this, DeviceControlActivity.class);
152
        intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName());
153
        intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress());
154
        if (mScanning) {
155
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
156
            mScanning = false;
157
        }
158
        startActivity(intent);
159
    }
160
 
161
    private void scanLeDevice(final boolean enable) {
162
        if (enable) {
163
            // Stops scanning after a pre-defined scan period.
164
            mHandler.postDelayed(new Runnable() {
165
                @Override
166
                public void run() {
167
                    mScanning = false;
168
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
169
                    invalidateOptionsMenu();
170
                }
171
            }, SCAN_PERIOD);
172
 
173
            mScanning = true;
174
            mBluetoothAdapter.startLeScan(mLeScanCallback);
175
        } else {
176
            mScanning = false;
177
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
178
        }
179
        invalidateOptionsMenu();
180
    }
181
 
182
    // Adapter for holding devices found through scanning.
183
    private class LeDeviceListAdapter extends BaseAdapter {
184
        private ArrayList<BluetoothDevice> mLeDevices;
185
        private LayoutInflater mInflator;
186
 
187
        public LeDeviceListAdapter() {
188
            super();
189
            mLeDevices = new ArrayList<BluetoothDevice>();
190
            mInflator = DeviceScanActivity.this.getLayoutInflater();
191
        }
192
 
193
        public void addDevice(BluetoothDevice device) {
194
            if(!mLeDevices.contains(device)) {
195
                mLeDevices.add(device);
196
            }
197
        }
198
 
199
        public BluetoothDevice getDevice(int position) {
200
            return mLeDevices.get(position);
201
        }
202
 
203
        public void clear() {
204
            mLeDevices.clear();
205
        }
206
 
207
        @Override
208
        public int getCount() {
209
            return mLeDevices.size();
210
        }
211
 
212
        @Override
213
        public Object getItem(int i) {
214
            return mLeDevices.get(i);
215
        }
216
 
217
        @Override
218
        public long getItemId(int i) {
219
            return i;
220
        }
221
 
222
        @Override
223
        public View getView(int i, View view, ViewGroup viewGroup) {
224
            ViewHolder viewHolder;
225
            // General ListView optimization code.
226
            if (view == null) {
227
                view = mInflator.inflate(R.layout.listitem_device, null);
228
                viewHolder = new ViewHolder();
229
                viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
230
                viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
231
                view.setTag(viewHolder);
232
            } else {
233
                viewHolder = (ViewHolder) view.getTag();
234
            }
235
 
236
            BluetoothDevice device = mLeDevices.get(i);
237
            final String deviceName = device.getName();
238
            if (deviceName != null && deviceName.length() > 0)
239
                viewHolder.deviceName.setText(deviceName);
240
            else
241
                viewHolder.deviceName.setText(R.string.unknown_device);
242
            viewHolder.deviceAddress.setText(device.getAddress());
243
 
244
            return view;
245
        }
246
    }
247
 
248
    // Device scan callback.
249
    private BluetoothAdapter.LeScanCallback mLeScanCallback =
250
            new BluetoothAdapter.LeScanCallback() {
251
 
252
        @Override
253
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
254
            runOnUiThread(new Runnable() {
255
                @Override
256
                public void run() {
257
                    mLeDeviceListAdapter.addDevice(device);
258
                    mLeDeviceListAdapter.notifyDataSetChanged();
259
                }
260
            });
261
        }
262
    };
263
 
264
    static class ViewHolder {
265
        TextView deviceName;
266
        TextView deviceAddress;
267
    }
268
}