teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

1

コードの追加

2019/12/28 06:27

投稿

ThiHuynh
ThiHuynh

スコア7

title CHANGED
File without changes
body CHANGED
@@ -1,4 +1,280 @@
1
+ ```
2
+
3
+ import android.app.Activity
4
+ import android.bluetooth.BluetoothAdapter
5
+ import android.bluetooth.BluetoothDevice
6
+ import android.bluetooth.BluetoothManager
7
+ import android.bluetooth.le.ScanCallback
8
+ import android.content.Context
9
+ import android.os.Bundle
10
+ import android.os.Handler
11
+ import android.os.Parcel
12
+ import android.os.Parcelable
13
+ import android.widget.*
14
+ import androidx.appcompat.app.AppCompatActivity
15
+ import com.hiramine.blecommunicator.R
16
+ import android.widget.Toast
17
+ import android.content.Intent
18
+ import android.view.*
19
+ import android.widget.AdapterView
20
+ import android.bluetooth.le.ScanResult as ScanResult1
21
+
22
+ abstract class DeviceListActivity() : AppCompatActivity(), Parcelable,
23
+ AdapterView.OnItemClickListener {
24
+
25
+ internal class DeviceListAdapter(activity: Activity) : BaseAdapter() {
26
+ private val mDeviceList: ArrayList<BluetoothDevice>
27
+ private val mInflator: LayoutInflater
28
+
29
+ init {
30
+ mDeviceList = ArrayList()
31
+ mInflator = activity.layoutInflater
32
+ }
33
+
34
+ // リストへの追加
35
+ fun addDevice(device: BluetoothDevice) {
36
+ if (!mDeviceList.contains(device)) { // 加えられていなければ加える
37
+ mDeviceList.add(device)
38
+ notifyDataSetChanged() // ListViewの更新
39
+ }
40
+ }
41
+
42
+ // リストのクリア
43
+ fun clear() {
44
+ mDeviceList.clear()
45
+ notifyDataSetChanged() // ListViewの更新
46
+ }
47
+
48
+ override fun getCount(): Int {
49
+ return mDeviceList.size
50
+ }
51
+
52
+ override fun getItem(position: Int): Any {
53
+ return mDeviceList[position]
54
+ }
55
+
56
+ override fun getItemId(position: Int): Long {
57
+ return position.toLong()
58
+ }
59
+
60
+ internal class ViewHolder {
61
+ var deviceName: TextView? = null
62
+ var deviceAddress: TextView? = null
63
+ }
64
+
65
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
66
+ var convertView = convertView
67
+ val viewHolder: ViewHolder
68
+ // General ListView optimization code.
69
+ if (null == convertView) {
70
+ convertView = mInflator.inflate(R.layout.listitem_device, parent, false)
71
+ viewHolder = ViewHolder()
72
+ viewHolder.deviceAddress = convertView!!.findViewById(R.id.textview_deviceaddress)
73
+ viewHolder.deviceName = convertView.findViewById(R.id.textview_devicename)
74
+ convertView.setTag(viewHolder)
75
+ } else {
76
+ viewHolder = convertView.getTag() as ViewHolder
77
+ }
78
+
79
+ val device = mDeviceList[position]
80
+ val deviceName = device.name
81
+ if (null != deviceName && 0 < deviceName.length) {
82
+ viewHolder.deviceName!!.text = deviceName
83
+ } else {
84
+ viewHolder.deviceName!!.setText(R.string.unknown_device)
85
+ }
86
+ viewHolder.deviceAddress!!.text = device.address
87
+
88
+ return convertView
89
+ }
90
+ }
91
+
92
+ // 定数
93
+ private val REQUEST_ENABLEBLUETOOTH = 1 // Bluetooth機能の有効化要求時の識別コード
94
+ private val SCAN_PERIOD: Long = 10000 // スキャン時間。単位はミリ秒。
95
+ val EXTRAS_DEVICE_NAME = "DEVICE_NAME"
96
+ val EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS"
97
+
98
+ // メンバー変数
99
+ private var mBluetoothAdapter: BluetoothAdapter? =
100
+ null // BluetoothAdapter : Bluetooth処理で必要
101
+ private var mDeviceListAdapter: DeviceListAdapter? = null // リストビューの内容
102
+ private var mHandler: Handler? =
103
+ null // UIスレッド操作ハンドラ : 「一定時間後にスキャンをやめる処理」で必要
104
+ private var mScanning = false // スキャン中かどうかのフラグ
105
+
106
+ // デバイススキャンコールバック
107
+ private val mLeScanCallback = object : ScanCallback() {
108
+ // スキャンに成功(アドバタイジングは一定間隔で常に発行されているため、本関数は一定間隔で呼ばれ続ける)
109
+ override fun onScanResult(callbackType: Int, result: ScanResult1) {
110
+ super.onScanResult(callbackType, result)
111
+ runOnUiThread { mDeviceListAdapter!!.addDevice(result.getDevice()) }
112
+ }
113
+
114
+ // スキャンに失敗
115
+ override fun onScanFailed(errorCode: Int) {
116
+ super.onScanFailed(errorCode)
117
+ }
118
+ }
119
+
120
+ constructor(parcel: Parcel) : this() {
121
+
122
+ }
123
+
124
+
125
+ override fun onCreate(savedInstanceState: Bundle?) {
126
+
127
+ super.onCreate(savedInstanceState)
128
+ setContentView(com.hiramine.blecommunicator.R.layout.activity_device_list)
129
+
130
+ // 戻り値の初期化
131
+ setResult(Activity.RESULT_CANCELED)
132
+
133
+ // リストビューの設定
134
+ mDeviceListAdapter = DeviceListAdapter(this) // ビューアダプターの初期化
135
+ val listView = findViewById(R.id.devicelist) as ListView // リストビューの取得
136
+ listView.adapter = mDeviceListAdapter // リストビューにビューアダプターをセット
137
+ listView.setOnItemClickListener(this) // クリックリスナーオブジェクトのセット
138
+
139
+ // UIスレッド操作ハンドラの作成(「一定時間後にスキャンをやめる処理」で使用する)
140
+ mHandler = Handler()
141
+
142
+ // Bluetoothアダプタの取得
143
+ val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
144
+ mBluetoothAdapter = bluetoothManager.adapter
145
+ if (null == mBluetoothAdapter) { // デバイス(=スマホ)がBluetoothをサポートしていない
146
+ Toast.makeText(this, R.string.bluetooth_is_not_supported, Toast.LENGTH_SHORT).show()
147
+ finish() // アプリ終了宣言
148
+ return
149
+ }
150
+ }
151
+
152
+ override fun onResume() {
153
+ super.onResume()
154
+
155
+ // デバイスのBluetooth機能の有効化要求
156
+ requestBluetoothFeature()
157
+
158
+ // スキャン開始
159
+ startScan()
160
+ }
161
+
162
+ // 別のアクティビティ(か別のアプリ)に移行したことで、バックグラウンドに追いやられた時
163
+ override fun onPause() {
164
+ super.onPause()
165
+
166
+ // スキャンの停止
167
+ stopScan()
168
+ }
169
+
170
+ // デバイスのBluetooth機能の有効化要求
171
+ private fun requestBluetoothFeature() {
172
+ if (mBluetoothAdapter!!.isEnabled()) {
173
+ return
174
+ }
175
+ // デバイスのBluetooth機能が有効になっていないときは、有効化要求(ダイアログ表示)
176
+ val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
177
+ startActivityForResult(enableBtIntent, REQUEST_ENABLEBLUETOOTH)
178
+ }
179
+
180
+ // 機能の有効化ダイアログの操作結果
181
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
182
+ when (requestCode) {
183
+ REQUEST_ENABLEBLUETOOTH // Bluetooth有効化要求
184
+ -> if (Activity.RESULT_CANCELED == resultCode) { // 有効にされなかった
185
+ Toast.makeText(this, R.string.bluetooth_is_not_working, Toast.LENGTH_SHORT).show()
186
+ finish() // アプリ終了宣言
187
+ return
188
+ }
189
+ }
190
+ super.onActivityResult(requestCode, resultCode, data)
191
+ }
192
+
193
+ // スキャンの開始
194
+ private fun startScan() {
195
+ // リストビューの内容を空にする。
196
+ mDeviceListAdapter?.clear()
197
+
198
+ // BluetoothLeScannerの取得
199
+ // ※Runnableオブジェクト内でも使用できるようfinalオブジェクトとする。
200
+ val scanner = mBluetoothAdapter!!.getBluetoothLeScanner() ?: return
201
+
202
+
203
+ // スキャン開始(一定時間後にスキャン停止する)
204
+ mHandler?.postDelayed(Runnable {
205
+ mScanning = false
206
+ scanner.stopScan(mLeScanCallback)
207
+
208
+ // メニューの更新
209
+ invalidateOptionsMenu()
210
+ }, SCAN_PERIOD)
211
+
212
+ mScanning = true
213
+ scanner.startScan(mLeScanCallback)
214
+
215
+ // メニューの更新
216
+ invalidateOptionsMenu()
217
+ }
218
+
219
+ // スキャンの停止
220
+ private fun stopScan() {
221
+ // 一定期間後にスキャン停止するためのHandlerのRunnableの削除
222
+ mHandler?.removeCallbacksAndMessages(null)
223
+
224
+ // BluetoothLeScannerの取得
225
+ val scanner = mBluetoothAdapter?.getBluetoothLeScanner() ?: return
226
+ mScanning = false
227
+ scanner.stopScan(mLeScanCallback)
228
+
229
+ // メニューの更新
230
+ invalidateOptionsMenu()
231
+ }
232
+
233
+
234
+ override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
235
+ // クリックされたアイテムの取得
236
+ val device = mDeviceListAdapter?.getItem(position) as BluetoothDevice
237
+ // 戻り値の設定
238
+ val intent = Intent()
239
+ intent.putExtra(EXTRAS_DEVICE_NAME, device.name)
240
+ intent.putExtra(EXTRAS_DEVICE_ADDRESS, device.address)
241
+ setResult(Activity.RESULT_OK, intent)
242
+ finish()
243
+ }
244
+
245
+ // オプションメニュー作成時の処理
246
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
247
+ menuInflater.inflate(R.menu.activity_device_list, menu)
248
+ if (mScanning) {
249
+ menu.findItem(R.id.menuitem_stop).setVisible(false)
250
+ menu.findItem(R.id.menuitem_scan).setVisible(true)
251
+ menu.findItem(R.id.menuitem_progress).setActionView(null)
252
+ } else {
253
+ menu.findItem(R.id.menuitem_stop).setVisible(true)
254
+ menu.findItem(R.id.menuitem_scan).setVisible(false)
255
+ menu.findItem(R.id.menuitem_progress)
256
+ .setActionView(R.layout.actionbar_indeterminate_progress)
257
+ }
258
+ return true
259
+ }
260
+
261
+ // オプションメニューのアイテム選択時の処理
262
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
263
+ when (item.getItemId()) {
264
+ R.id.menuitem_scan -> startScan() // スキャンの開始
265
+ R.id.menuitem_stop -> stopScan() // スキャンの停止
266
+ }
267
+ return true
268
+ }
269
+
270
+ }
271
+
272
+
273
+
274
+
275
+
276
+ コード
1
- ![イメージ説明](1aaa490cbf8722c93171b0eac7f9541d.png)
277
+ ```[イメージ説明](1aaa490cbf8722c93171b0eac7f9541d.png)
2
278
  MainActivityの分です。deviceListActivity.で引っ張ってきているはずなのに、赤字の部分が直りません。わかるかたお願いします。 
3
279
 
4
280
  ちなみにBLEのアプリを作っています