Browse Source

1.添加蓝牙状态广播接收器;
2.完善设备连接活动。

Yumin 6 years ago
parent
commit
059fa032cb

+ 1 - 1
app/build.gradle

@@ -4,7 +4,7 @@ android {
     compileSdkVersion 27
     defaultConfig {
         applicationId "cn.minbb.producttester"
-        minSdkVersion 16
+        minSdkVersion 18
         targetSdkVersion 27
         versionCode 1
         versionName "1.0"

+ 15 - 0
app/src/main/AndroidManifest.xml

@@ -7,6 +7,9 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <!-- 管理蓝牙设备 -->
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <!-- 如果 Android6.0 蓝牙搜索不到设备,需要补充下面两个权限 -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
     <application
         android:name=".ctrl.App"
@@ -33,6 +36,18 @@
         <activity
             android:name=".views.ScanDeviceActivity"
             android:label="设备连接" />
+
+        <receiver
+            android:name=".receiver.BluetoothStatusReceiver"
+            android:enabled="false"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.bluetooth.device.action.FOUND" />
+                <action android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />
+                <action android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
+                <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
+            </intent-filter>
+        </receiver>
     </application>
 
 </manifest>

+ 5 - 3
app/src/main/java/cn/minbb/producttester/adapter/DeviceListAdapter.java

@@ -1,5 +1,6 @@
 package cn.minbb.producttester.adapter;
 
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -76,12 +77,13 @@ public class DeviceListAdapter extends BaseAdapter {
 
     public static class ItemBean {
 
+        public BluetoothDevice device;
         String deviceName;
         String deviceAddress;
 
-        public ItemBean(String deviceName, String deviceAddress) {
-            this.deviceName = deviceName;
-            this.deviceAddress = deviceAddress;
+        public ItemBean(BluetoothDevice device) {
+            this.deviceName = device.getName();
+            this.deviceAddress = device.getAddress();
         }
     }
 }

+ 14 - 0
app/src/main/java/cn/minbb/producttester/ctrl/App.java

@@ -3,8 +3,12 @@ package cn.minbb.producttester.ctrl;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.Application;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Environment;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
@@ -17,11 +21,14 @@ import com.joanzapata.iconify.Iconify;
 import com.joanzapata.iconify.fonts.FontAwesomeModule;
 
 import java.io.File;
+import java.lang.reflect.Method;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
 
 import cn.minbb.producttester.R;
+import lombok.Getter;
+import lombok.Setter;
 
 public class App extends Application {
 
@@ -30,6 +37,11 @@ public class App extends Application {
     // 时间格式
     private static SimpleDateFormat simpleDateFormat = (SimpleDateFormat) SimpleDateFormat.getDateTimeInstance();
 
+    // 蓝牙适配器
+    @Getter
+    @Setter
+    private BluetoothAdapter bluetoothAdapter;
+
     public App() {
     }
 
@@ -48,6 +60,8 @@ public class App extends Application {
 
         // 初始化字体图标模块
         Iconify.with(new FontAwesomeModule());
+
+        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
     }
 
     @Override

+ 61 - 0
app/src/main/java/cn/minbb/producttester/receiver/BluetoothStatusReceiver.java

@@ -0,0 +1,61 @@
+package cn.minbb.producttester.receiver;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import java.lang.reflect.Method;
+
+import cn.minbb.producttester.ctrl.App;
+
+public class BluetoothStatusReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        System.out.println("广播接收器 action = " + action);
+        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
+            // 获取查找到的蓝牙设备
+            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+            System.out.println("蓝牙设备 Found = " + device.getName());
+            // 如果查找到的设备符合要连接的设备,处理
+            if (device.getName().equalsIgnoreCase(device.getName())) {
+                // 搜索蓝牙设备的过程占用资源比较多,一旦找到需要连接的设备后需要及时关闭搜索
+                App.getApp().getBluetoothAdapter().cancelDiscovery();
+                // 获取蓝牙设备的连接状态
+                switch (device.getBondState()) {
+                    // 未配对
+                    case BluetoothDevice.BOND_NONE:
+                        // 配对
+                        try {
+                            Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
+                            createBondMethod.invoke(device);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                        break;
+                    // 已配对
+                    case BluetoothDevice.BOND_BONDED:
+                        // 连接
+                        break;
+                }
+            }
+        } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
+            // 状态改变的广播
+            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+            if (device.getName().equalsIgnoreCase(device.getName())) {
+                switch (device.getBondState()) {
+                    case BluetoothDevice.BOND_NONE:
+                        // 取消配对
+                        break;
+                    case BluetoothDevice.BOND_BONDING:
+                        // 正在配对
+                        break;
+                    case BluetoothDevice.BOND_BONDED:
+                        // 完成配对
+                        break;
+                }
+            }
+        }
+    }
+}

+ 216 - 17
app/src/main/java/cn/minbb/producttester/views/ScanDeviceActivity.java

@@ -6,12 +6,19 @@ import android.annotation.SuppressLint;
 import android.app.ProgressDialog;
 import android.bluetooth.BluetoothAdapter;
 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.pm.PackageManager;
+import android.os.Build;
 import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.support.annotation.Nullable;
+import android.os.Handler;
+import android.support.annotation.NonNull;
 import android.support.v7.app.AppCompatActivity;
+import android.support.v7.app.AppCompatDelegate;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
@@ -23,9 +30,15 @@ import android.widget.Toast;
 
 import com.joanzapata.iconify.widget.IconTextView;
 
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.UUID;
 
 import butterknife.BindView;
 import butterknife.ButterKnife;
@@ -59,7 +72,15 @@ public class ScanDeviceActivity extends AppCompatActivity {
 
     private ProgressDialog dialog;
 
-    private BluetoothAdapter adapter;
+    private BluetoothAdapter adapter = App.getApp().getBluetoothAdapter();
+    List<DeviceListAdapter.ItemBean> matchItemBeanList = new ArrayList<>();
+    List<DeviceListAdapter.ItemBean> searchItemBeanList = new ArrayList<>();
+    private DeviceListAdapter matchDeviceListAdapter;
+    private DeviceListAdapter searchDeviceListAdapter;
+
+    static {
+        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -67,11 +88,48 @@ public class ScanDeviceActivity extends AppCompatActivity {
         setContentView(R.layout.activity_scan_device);
         ButterKnife.bind(this);
 
+        // 设置广播信息过滤
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
+        intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        // 注册广播接收器,接收并处理搜索结果
+        this.registerReceiver(receiver, intentFilter);
+
+        // 检查设备是否支持蓝牙
+        if (adapter == null) {
+            // 设备不支持蓝牙
+            Toast.makeText(ScanDeviceActivity.this, "设备不支持蓝牙", Toast.LENGTH_LONG).show();
+            ScanDeviceActivity.this.finish();
+        } else {
+            if (!adapter.isEnabled()) {
+                Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+                // 设置蓝牙可见性,最多 300 秒
+                intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 60);
+                ScanDeviceActivity.this.startActivityForResult(intent, 0);
+            }
+            Set<BluetoothDevice> devices = adapter.getBondedDevices();
+            for (BluetoothDevice device : devices) {
+                matchItemBeanList.add(new DeviceListAdapter.ItemBean(device));
+            }
+            matchDeviceListAdapter = new DeviceListAdapter(this, matchItemBeanList);
+            matchList.setAdapter(matchDeviceListAdapter);
+            searchDeviceListAdapter = new DeviceListAdapter(this, searchItemBeanList);
+            searchList.setAdapter(searchDeviceListAdapter);
+        }
+
         initView();
         setListener();
         loadData();
     }
 
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        this.unregisterReceiver(receiver);
+    }
+
     private void initView() {
         App.setupActionBar(this);
     }
@@ -80,25 +138,34 @@ public class ScanDeviceActivity extends AppCompatActivity {
         matchList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
             @Override
             public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
+                // 尝试连接
+            }
+        });
+        searchList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                // 尝试配对
+                try {
+                    Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
+                    createBondMethod.invoke(searchItemBeanList.get(position).device);
+                } catch (NoSuchMethodException e) {
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                } catch (InvocationTargetException e) {
+                    e.printStackTrace();
+                }
             }
         });
     }
 
     private void loadData() {
-        // 检查设备是否支持蓝牙
-        adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter == null) {
-            // 设备不支持蓝牙
-            Toast.makeText(ScanDeviceActivity.this, "设备不支持蓝牙", Toast.LENGTH_LONG).show();
-            ScanDeviceActivity.this.finish();
-        }
-        List<DeviceListAdapter.ItemBean> matchItemBeanList = new ArrayList<>();
-        Set<BluetoothDevice> devices = adapter.getBondedDevices();
-        for (BluetoothDevice device : devices) {
-            matchItemBeanList.add(new DeviceListAdapter.ItemBean(device.getName(), device.getAddress()));
-            System.out.println("name = " + device.getName());
+        // 请求定位权限
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (this.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+                requestPermissions(new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
+            }
         }
-        matchList.setAdapter(new DeviceListAdapter(this, matchItemBeanList));
     }
 
     public static void start(Context context) {
@@ -112,6 +179,13 @@ public class ScanDeviceActivity extends AppCompatActivity {
             dialog.setTitle("蓝牙串口");
             dialog.setMessage("搜索设备中······");
             dialog.setCancelable(false);
+            dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialogInterface, int i) {
+                    adapter.cancelDiscovery();
+                    dialog.dismiss();
+                }
+            });
         }
         if (show) {
             dialog.show();
@@ -173,6 +247,14 @@ public class ScanDeviceActivity extends AppCompatActivity {
         return (int) (dpValue * density + 0.5f);
     }
 
+    private void connect(BluetoothDevice device) throws IOException {
+        // 固定的 UUID
+        String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
+        UUID uuid = UUID.fromString(SPP_UUID);
+        BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);
+        socket.connect();
+    }
+
     @OnClick({R.id.matchListToggle, R.id.searchListToggle})
     public void onViewClicked(View view) {
         switch (view.getId()) {
@@ -187,7 +269,7 @@ public class ScanDeviceActivity extends AppCompatActivity {
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        menu.add(0, 0, 0, "扫描").setIcon(R.drawable.ic_search_white_24dp).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+        menu.add(0, 0, 0, "搜索设备").setIcon(R.drawable.ic_search_white_24dp).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
         return super.onCreateOptionsMenu(menu);
     }
 
@@ -198,6 +280,8 @@ public class ScanDeviceActivity extends AppCompatActivity {
                 ScanDeviceActivity.this.finish();
                 break;
             case 0:
+                showProgress(true);
+                matchItemBeanList.clear();
                 // 打开蓝牙
                 if (!adapter.isEnabled()) {
                     Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
@@ -205,8 +289,123 @@ public class ScanDeviceActivity extends AppCompatActivity {
                     intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
                     ScanDeviceActivity.this.startActivity(intent);
                 }
+                // 寻找蓝牙设备,Android 会将查找到的设备以广播形式发出去
+                if (!adapter.isDiscovering()) {
+                    adapter.startDiscovery();
+                }
+                // 弹出是否允许扫描蓝牙设备的选择对话框
+                // Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
+                // startActivityForResult(intent, 1);
+                new Handler().postDelayed(() -> runOnUiThread(() -> {
+                    showProgress(false);
+                    adapter.cancelDiscovery();
+                }), 20000);
                 break;
         }
         return super.onOptionsItemSelected(item);
     }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        switch (requestCode) {
+            case 0:
+                if (resultCode == RESULT_CANCELED) {
+                    ScanDeviceActivity.this.finish();
+                    Toast.makeText(this, "蓝牙未打开", Toast.LENGTH_SHORT).show();
+                }
+                break;
+            case 1:
+                new Handler().postDelayed(() -> runOnUiThread(() -> {
+                    // 刷新蓝牙设备列表
+                    System.out.println("刷新蓝牙设备列表");
+                }), 50);
+                if (resultCode == RESULT_OK) {
+                    Toast.makeText(this, "允许本地蓝牙被附近的其它蓝牙设备发现", Toast.LENGTH_SHORT).show();
+                } else if (resultCode == RESULT_CANCELED) {
+                    Toast.makeText(this, "不允许蓝牙被附近的其它蓝牙设备发现", Toast.LENGTH_SHORT).show();
+                }
+                break;
+        }
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        switch (requestCode) {
+            case 1:
+                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                    System.out.println("权限请求成功");
+                }
+                break;
+            default:
+        }
+    }
+
+    private BroadcastReceiver receiver = 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);
+
+                matchItemBeanList.add(new DeviceListAdapter.ItemBean(device));
+                searchDeviceListAdapter.notifyDataSetChanged();
+
+                // 如果查找到的设备符合要连接的设备,处理
+                if (device.getName().equalsIgnoreCase(device.getName())) {
+                    // 搜索蓝牙设备的过程占用资源比较多,一旦找到需要连接的设备后需要及时关闭搜索
+                    App.getApp().getBluetoothAdapter().cancelDiscovery();
+                    // 获取蓝牙设备的连接状态
+                    switch (device.getBondState()) {
+                        // 未配对
+                        case BluetoothDevice.BOND_NONE:
+                            // 配对
+                            try {
+                                Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
+                                createBondMethod.invoke(device);
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                            break;
+                        // 已配对
+                        case BluetoothDevice.BOND_BONDED:
+                            // 连接
+                            break;
+                    }
+                }
+            } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
+                // 状态改变的广播
+                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                if (device.getName().equalsIgnoreCase(device.getName())) {
+                    switch (device.getBondState()) {
+                        case BluetoothDevice.BOND_NONE:
+                            // 取消配对
+                            break;
+                        case BluetoothDevice.BOND_BONDING:
+                            // 正在配对
+                            break;
+                        case BluetoothDevice.BOND_BONDED:
+                            // 完成配对
+                            break;
+                    }
+                }
+            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
+                new Handler().postDelayed(() -> runOnUiThread(() -> {
+                    if (!adapter.isEnabled()) {
+                        Toast.makeText(ScanDeviceActivity.this, "蓝牙已关闭", Toast.LENGTH_SHORT).show();
+                        ScanDeviceActivity.this.finish();
+                    } else {
+                        matchItemBeanList.clear();
+                        Set<BluetoothDevice> devices = adapter.getBondedDevices();
+                        for (BluetoothDevice device : devices) {
+                            matchItemBeanList.add(new DeviceListAdapter.ItemBean(device));
+                        }
+                        matchDeviceListAdapter.notifyDataSetChanged();
+                    }
+                }), 500);
+            }
+        }
+    };
 }

+ 88 - 68
app/src/main/res/layout/activity_scan_device.xml

@@ -1,29 +1,36 @@
 <?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
     tools:context=".views.ScanDeviceActivity">
 
     <LinearLayout
+        android:id="@+id/matchListLayout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginLeft="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="8dp"
+        android:layout_marginRight="8dp"
         android:orientation="vertical">
 
-        <LinearLayout
-            android:id="@+id/matchListLayout"
+        <android.support.v7.widget.CardView
+            android:id="@+id/matchListToggle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginLeft="8dp"
-            android:layout_marginTop="8dp"
-            android:layout_marginEnd="8dp"
-            android:layout_marginRight="8dp"
-            android:orientation="vertical">
+            android:clickable="true"
+            android:focusable="true"
+            android:foreground="?android:attr/selectableItemBackground"
+            app:cardBackgroundColor="@android:color/white"
+            app:cardCornerRadius="5dp"
+            app:cardPreventCornerOverlap="true"
+            app:cardUseCompatPadding="true">
 
             <android.support.constraint.ConstraintLayout
-                android:id="@+id/matchListToggle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
 
@@ -31,10 +38,10 @@
                     android:id="@+id/matchListIcon"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginStart="8dp"
-                    android:layout_marginLeft="8dp"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginBottom="8dp"
+                    android:layout_marginStart="12dp"
+                    android:layout_marginLeft="12dp"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginBottom="12dp"
                     android:text="{fa-link}"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
@@ -45,8 +52,8 @@
                     android:layout_height="wrap_content"
                     android:layout_marginStart="8dp"
                     android:layout_marginLeft="8dp"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginBottom="8dp"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginBottom="12dp"
                     android:text="已配对"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintStart_toEndOf="@+id/matchListIcon"
@@ -57,10 +64,10 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_gravity="end"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginEnd="8dp"
-                    android:layout_marginRight="8dp"
-                    android:layout_marginBottom="8dp"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginEnd="12dp"
+                    android:layout_marginRight="12dp"
+                    android:layout_marginBottom="12dp"
                     android:text="{fa-chevron-down}"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintEnd_toEndOf="parent"
@@ -68,34 +75,47 @@
 
             </android.support.constraint.ConstraintLayout>
 
-            <cn.minbb.producttester.controls.FoldingLayout
-                android:id="@+id/matchListFolding"
+        </android.support.v7.widget.CardView>
+
+        <cn.minbb.producttester.controls.FoldingLayout
+            android:id="@+id/matchListFolding"
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:tag="main">
+
+            <ListView
+                android:id="@+id/matchList"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:tag="main">
+                android:layout_height="wrap_content" />
 
-                <ListView
-                    android:id="@+id/matchList"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
+        </cn.minbb.producttester.controls.FoldingLayout>
 
-            </cn.minbb.producttester.controls.FoldingLayout>
+    </LinearLayout>
 
-        </LinearLayout>
+    <LinearLayout
+        android:id="@+id/searchListLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginLeft="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="8dp"
+        android:layout_marginRight="8dp"
+        android:orientation="vertical">
 
-        <LinearLayout
-            android:id="@+id/searchListLayout"
+        <android.support.v7.widget.CardView
+            android:id="@+id/searchListToggle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginLeft="8dp"
-            android:layout_marginTop="8dp"
-            android:layout_marginEnd="8dp"
-            android:layout_marginRight="8dp"
-            android:orientation="vertical">
+            android:clickable="true"
+            android:focusable="true"
+            android:foreground="?android:attr/selectableItemBackground"
+            app:cardBackgroundColor="@android:color/white"
+            app:cardCornerRadius="5dp"
+            app:cardPreventCornerOverlap="true"
+            app:cardUseCompatPadding="true">
 
             <android.support.constraint.ConstraintLayout
-                android:id="@+id/searchListToggle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
 
@@ -103,10 +123,10 @@
                     android:id="@+id/iconTextView2"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginStart="8dp"
-                    android:layout_marginLeft="8dp"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginBottom="8dp"
+                    android:layout_marginStart="12dp"
+                    android:layout_marginLeft="12dp"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginBottom="12dp"
                     android:text="{fa-unlink}"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
@@ -117,8 +137,8 @@
                     android:layout_height="wrap_content"
                     android:layout_marginStart="8dp"
                     android:layout_marginLeft="8dp"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginBottom="8dp"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginBottom="12dp"
                     android:text="搜索列表"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintStart_toEndOf="@+id/iconTextView2"
@@ -129,10 +149,10 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_gravity="end"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginEnd="8dp"
-                    android:layout_marginRight="8dp"
-                    android:layout_marginBottom="8dp"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginEnd="12dp"
+                    android:layout_marginRight="12dp"
+                    android:layout_marginBottom="12dp"
                     android:text="{fa-chevron-down}"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintEnd_toEndOf="parent"
@@ -140,27 +160,27 @@
 
             </android.support.constraint.ConstraintLayout>
 
-            <cn.minbb.producttester.controls.FoldingLayout
-                android:id="@+id/searchListFolding"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:tag="main">
-
-                <ListView
-                    android:id="@+id/searchList"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
+        </android.support.v7.widget.CardView>
 
-            </cn.minbb.producttester.controls.FoldingLayout>
-
-        </LinearLayout>
-
-        <View
-            android:id="@+id/bottomLayout"
+        <cn.minbb.producttester.controls.FoldingLayout
+            android:id="@+id/searchListFolding"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="8dp" />
+            android:tag="main">
+
+            <ListView
+                android:id="@+id/searchList"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+        </cn.minbb.producttester.controls.FoldingLayout>
 
     </LinearLayout>
 
-</ScrollView>
+    <View
+        android:id="@+id/bottomLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp" />
+
+</LinearLayout>

+ 1 - 1
app/src/main/res/layout/item_device_list.xml

@@ -10,7 +10,7 @@
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
         android:layout_marginLeft="8dp"
-        android:layout_marginTop="8dp"
+        android:layout_marginTop="4dp"
         android:text="设备名称"
         android:textColor="@android:color/black"
         android:textSize="18sp"