蓝牙开发

来源:互联网 发布:超星网络课程登录入口 编辑:程序博客网 时间:2024/05/21 11:10

关于WIFI就不多介绍啦,直接来个段子吧。

问:“WiFi对人体有伤害么?”

答:“不清楚,反正没有WiFi我就浑身不舒服。

比较重要的一点就是WifiManager  wm=(WifiManager)Android_Wifi.this.getSystemService(Context.WIFI_SERVICE);

关闭打开搜索都可以通过调用wm的相关方法实现。可能要开发wifi万能钥匙那一类的程序才用到这个吧,普通应用程序主要就识别是wifi网络还是移动网络。不多讲

代码参考博客:http://blog.csdn.net/sbvfhp/article/details/7007090

重点蓝牙:

 一:什么是蓝牙

    1:Bluetooth是目前使用最广泛的无线通讯协议,近距离无线通讯的标准。传说瑞典有个国王特别爱吃蓝莓导致自己的牙齿天天都是蓝色的,在他执政期间这位国王非常善于交际,能说会到,和邻国的搞得关系非常好,这个Bluetooth的发明者觉得蓝牙它的作用就是在近距离沟通周围的设备,跟这个国王很类似,于是起名叫蓝牙。

    2:主要针对短距离设备通讯(10米)

    3:无线耳机,无线鼠标,无线键盘

    

蓝牙标志

 

 二:蓝牙工作流程图

    首先两个设备上都要有蓝牙设备或者专业一点叫蓝牙适配器,以手机和电脑为例我画了如下流程图。其次在手机上进行扫描,扫描周围蓝蓝牙设备,先找到手机附近的电脑,然后给它发出一个信号需要进行蓝牙的配对,再次返回一个信号说明手机和电脑已经配对成功了,最后配对成功后可以进行文件传输了。这是一个最基本的一个流程。

  三:蓝牙开发相关类

  在Android手机中开发蓝牙程序时,离不开几个类:

BluetoothSocket:close()  connect()  getInputStream()......

BluetoothServerSocket : accept()

BlutoothAdapter :代表本地的蓝牙适配器设备,通过此类可以让用户能执行基本的蓝牙任务。

BluetoothClass: 代表了一个描述设备通用特性和功能的蓝牙类。比如一个蓝牙类会指定如电话、计算机或耳机的通用设备类型。

BluetoothClass.Service: 

BluetoothClass.Device:

BluetoothClass.Device.Major: 定义了主要设备类的常量

 

其中与蓝牙相关的最重要的两个API

   1:BuletoothAdapter

  这个类的对象代表了本地的蓝牙适配器,相当于蓝牙工作流程图中的手机里的蓝牙适配器,也就是说比如这个应用程序是运行在手机上,那么手机上的蓝牙适配器就是本地蓝牙适配器。

   2:BuletoothDevice

   这个类的对象代表了远程的蓝牙设备,相当于蓝牙工作流程图中的计算机里的蓝牙适配器,也就是说比如这个应用程序是运行在手机上,那么BuletoothDevice代表了你要连接的远程的那个设备上面的蓝牙适配器。

 四:蓝牙开发步骤:

此部分转载于 http://zhouyunan2010.iteye.com/blog/1186021

从查找蓝牙设备到能够相互通信要经过几个基本步骤(本机做为服务器): 
1.设置权限 
在manifest中配置 

<uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

2.启动蓝牙 
首先要查看本机是否支持蓝牙,获取BluetoothAdapter蓝牙适配器对象 

复制代码
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if(mBluetoothAdapter == null){        //表明此手机不支持蓝牙        return;}if(!mBluetoothAdapter.isEnabled()){    //蓝牙未开启,则开启蓝牙            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);}//......public void onActivityResult(int requestCode, int resultCode, Intent data){       if(requestCode == REQUEST_ENABLE_BT){              if(requestCode == RESULT_OK){                   //蓝牙已经开启               }       }}
复制代码

3。发现蓝牙设备 
这里可以细分为几个方面 
(1)使本机蓝牙处于可见(即处于易被搜索到状态),便于其他设备发现本机蓝牙 

复制代码
//使本机蓝牙在300秒内可被搜索private void ensureDiscoverable() {        if (mBluetoothAdapter.getScanMode() !=            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);            startActivity(discoverableIntent);        }}
复制代码

(2)查找已经配对的蓝牙设备,即以前已经配对过的设备 

复制代码
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();        if (pairedDevices.size() > 0) {            findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);            for (BluetoothDevice device : pairedDevices) {                //device.getName() +" "+ device.getAddress());            }        } else {            mPairedDevicesArrayAdapter.add("没有找到已匹对的设备");        }
复制代码

(3)通过mBluetoothAdapter.startDiscovery();搜索设备,要获得此搜索的结果需要注册 
一个BroadcastReceiver来获取。先注册再获取信息,然后处理 

复制代码
//注册,当一个设备被发现时调用onReceiveIntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);        this.registerReceiver(mReceiver, filter);//当搜索结束后调用onReceivefilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);        this.registerReceiver(mReceiver, filter);//.......private BroadcastReceiver mReceiver = 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);                  // 已经配对的则跳过                 if (device.getBondState() != BluetoothDevice.BOND_BONDED) {                      mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());  //保存设备地址与名字                 }            }else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {  //搜索结束                if (mNewDevicesArrayAdapter.getCount() == 0) {                    mNewDevicesArrayAdapter.add("没有搜索到设备");                }            }        }};
复制代码

4.建立连接 
查找到设备 后,则需要建立本机与其他设备之间的连接。 
一般用本机搜索其他蓝牙设备时,本机可以作为一个服务端,接收其他设备的连接。 
启动一个服务器端的线程,死循环等待客户端的连接,这与ServerSocket极为相似。 
这个线程在准备连接之前启动 

 View Code

5.交换数据

搜索到设备后可以获取设备的地址,通过此地址获取一个BluetoothDeviced对象,可以看做客户端,通过此对象device.createRfcommSocketToServiceRecord(MY_UUID);同一个UUID可与服务器建立连接获取另一个socket对象,由此服务端与客户端各有一个socket对象,此时 
他们可以互相交换数据了。 
创立客户端socket可建立线程 

 View Code

6.建立数据通信线程,进行读取数据 

复制代码
//建立连接后,进行数据通信的线程    private class ConnectedThread extends Thread{        private BluetoothSocket socket;        private InputStream inStream;        private OutputStream outStream;                public ConnectedThread(BluetoothSocket socket){                        this.socket = socket;            try {                //获得输入输出流                inStream = socket.getInputStream();                outStream = socket.getOutputStream();            } catch (IOException e) {                Log.e("app", "temp sockets not created", e);            }        }                public void run(){            byte[] buff = new byte[1024];            int len=0;            //读数据需不断监听,写不需要            while(true){                try {                    len = inStream.read(buff);                    //把读取到的数据发送给UI进行显示                    Message msg = handler.obtainMessage(BluetoothChat.MESSAGE_READ,                            len, -1, buff);                    msg.sendToTarget();                } catch (IOException e) {                    Log.e("app", "disconnected", e);                    connectionLost();    //失去连接                    start();    //重新启动服务器                    break;                }            }        }                        public void write(byte[] buffer) {            try {                outStream.write(buffer);                // Share the sent message back to the UI Activity                handler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)                        .sendToTarget();            } catch (IOException e) {                Log.e("app", "Exception during write", e);            }        }        public void cancel() {            try {                socket.close();            } catch (IOException e) {                Log.e("app", "close() of connect socket failed", e);            }        }    }
复制代码

到这里,蓝牙通信的基本操作已经全部完成。 

五:蓝牙聊天室开发

源码参考 http://download.csdn.net/detail/mr_raptor/8033951#comment  

此demo界面优美,实现基本功能,但不能保存聊天记录,黑屏自动断线,在此基础做出修改。

     相关知识:

     在EditText中插入表情图片 (CharacterStyle&SpannableString)

 源码分析:  

  1.  Android中pendingIntent的深入理解 

Utils.java

复制代码
 1 package cn.com.farsgiht.bluetoothdemo.utils; 2  3 import android.app.Activity; 4 import android.app.Notification; 5 import android.app.NotificationManager; 6 import android.app.PendingIntent; 7 import android.content.Context; 8 import android.content.Intent; 9 import cn.com.farsgiht.bluetoothdemo.R;10 11 public class Utils {12     public static final int NOTIFY_ID1 = 1001;13     14     public static void notifyMessage(Context context, String msg, Activity activity){15         //Notification builder; 16         PendingIntent contentIntent = null; 17         NotificationManager nm;18         // 发送通知需要用到NotificationManager对象 19         nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);20         // 消息对象21         Intent notificationIntent = new Intent(context, activity.getClass());22         // PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)23         // 用来获得一个挂起的PendingIntent,让该Intent去启动新的Activity来处理通知24         contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0); 25 26         27         //定义通知栏展现的内容信息28         int icon = R.drawable.icon;29         long when = System.currentTimeMillis();30         Notification notification = new Notification(icon, msg, when);31         notification.defaults |= Notification.DEFAULT_VIBRATE;32         notification.defaults |= Notification.DEFAULT_SOUND; // 调用系统自带声音  33         notification.flags |= Notification.FLAG_AUTO_CANCEL; // 点击清除按钮或点击通知后会自动消失34         notification.defaults |= Notification.DEFAULT_LIGHTS;35         notification.vibrate = new long[]{300, 500};36         notification.setLatestEventInfo(context, "BluetoothChat", msg, contentIntent);37        /* // 定制我们要在状态栏显示的通知样式38         builder = new Notification(context);39         builder.setContentIntent(contentIntent)40              .setSmallIcon(R.drawable.ic_launcher)//设置状态栏里面的图标(小图标)                     .setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.i5))//下拉下拉列表里面的图标(大图标)        .setTicker("this is bitch!") //设置状态栏的显示的信息41              .setWhen(System.currentTimeMillis())//设置时间发生时间42              .setAutoCancel(true)//设置可以清除43              .setContentTitle("This is ContentTitle")//设置下拉列表里的标题44              .setContentText("this is ContentText");//设置上下文内容45         */        46         // 获得刚才创建的通知对象47         // Notification notification = builder.getNotification();//获取一个Notification48          49          // 通过NotificationManger来发送通知消息50          // 参数1通知的ID,参数2发送哪个通知51          nm.notify(NOTIFY_ID1, notification);52     }53 }
复制代码

通知栏相关代码

     2. PageIndicatorView.java

复制代码
 1 package cn.com.farsgiht.bluetoothdemo.UI; 2  3 import cn.com.farsgiht.bluetoothdemo.R; 4 import android.content.Context; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.widget.ImageView; 8 import android.widget.LinearLayout; 9 10 public class PageIndicatorView extends ImageView {11     private final String TAG = "PageIndicatorView";12     private LinearLayout mPageIndicLayout;13 14     public PageIndicatorView(Context context) {15         super(context);16         setSelectedView(false);17     }18     19     public void setSelectedView(boolean selected){20         Bitmap bitmap;21         if(selected){22             bitmap = BitmapFactory.decodeResource(getResources(),23                 R.drawable.page_select);24         }else{25             bitmap = BitmapFactory.decodeResource(getResources(),26                     R.drawable.page_item);27         }28         this.setImageBitmap(bitmap);29     }30 }
复制代码

        表情页页面指示器

  3. DrawerHScrollView.java

复制代码
  1 package cn.com.farsgiht.bluetoothdemo.UI;  2   3 import java.util.Hashtable;  4   5 import android.content.Context;  6 import android.util.AttributeSet;  7 import android.util.Log;  8 import android.view.Gravity;  9 import android.view.ViewGroup; 10 import android.view.ViewParent; 11 import android.widget.HorizontalScrollView; 12 import android.widget.LinearLayout; 13  14 public class DrawerHScrollView extends HorizontalScrollView { 15     private static final String TAG = "DrawerHScrollView"; 16      17     private int currentPage = 0; 18     private int totalPages = 1; 19     private static Hashtable<Integer, Integer> positionLeftTopOfPages = new Hashtable(); 20     private LinearLayout mPageIndicLayout; 21     private Context mContext; 22  23     public DrawerHScrollView(Context context) { 24         super(context); 25         this.mContext = context; 26     } 27  28     public DrawerHScrollView(Context context, AttributeSet attrs) { 29         super(context, attrs); 30         this.mContext = context; 31     } 32  33     public DrawerHScrollView(Context context, AttributeSet attrs, int defStyle) { 34         super(context, attrs, defStyle); 35         this.mContext = context; 36     } 37      38     public void cleanup(){ 39         currentPage = 0; 40         totalPages = 1; 41         if(positionLeftTopOfPages != null){ 42             positionLeftTopOfPages.clear(); 43         } 44     } 45      46     public void setParameters(int totalPages, int currentPage, int scrollDisX, int space) { 47         Log.d(TAG, "~~~~~setParameters totalPages:"+totalPages +",currentPage:"+ currentPage +",scrollDisX:"+scrollDisX); 48         this.totalPages = totalPages; 49         this.currentPage = currentPage; 50         positionLeftTopOfPages.clear(); 51         for (int i = 0;i < totalPages;i++){ 52             int posx = (scrollDisX) * i - space; 53             positionLeftTopOfPages.put(i, posx); 54             Log.d(TAG, "~~~~~setParameters i:"+i +",posx:"+posx); 55         } 56         smoothScrollTo(0, 0); 57         setPageIndicLayout(); 58         if(mPageIndicLayout != null){ 59             updateDrawerPageLayout(totalPages, currentPage); 60         } 61     } 62      63     public void setPageIndicLayout(){ 64         // 添加表情多页图标布局 65         mPageIndicLayout = new LinearLayout(mContext); 66         mPageIndicLayout.setGravity(Gravity.CENTER); 67         ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 68         mPageIndicLayout.setLayoutParams(params); 69         ViewParent parent = this.getParent(); 70         if(parent instanceof LinearLayout){ 71             LinearLayout layout = (LinearLayout)parent; 72             layout.addView(mPageIndicLayout, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); 73         } 74     } 75  76     @Override 77     public void fling(int velocityX) { 78         Log.v(TAG, "-->fling velocityX:"+velocityX); 79         boolean change_flag = false; 80         if (velocityX > 0 && (currentPage < totalPages - 1)){ 81             currentPage++; 82             change_flag = true; 83         } else if (velocityX < 0 && (currentPage > 0)){ 84             currentPage--; 85             change_flag = true; 86         } 87         if (change_flag){ 88             int postionTo = (Integer)positionLeftTopOfPages.get(new Integer(currentPage)).intValue(); 89             Log.v(TAG, "------smoothScrollTo posx:"+postionTo); 90             smoothScrollTo(postionTo, 0); 91             updateDrawerPageLayout(totalPages, currentPage); 92         } 93         //super.fling(velocityX); 94     } 95      96     public void updateDrawerPageLayout(int total_pages, int sel_page) { 97         Log.e(TAG, "~~~updateBooksPageLayout total_pages:" + total_pages 98                 + ",sel_page:" + sel_page); 99         mPageIndicLayout.removeAllViews();100         if (total_pages <= 0 || sel_page < 0 || sel_page >= total_pages) {101             Log.e(TAG, "total_pages or sel_page is outofrange.");102             return;103         }104         for (int i = 0; i < total_pages; i++) {105             if (i != 0) {106                 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(107                         LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);108                 params.setMargins(5, 0, 0, 0);109                 mPageIndicLayout.addView(new PageIndicatorView(mContext), params);110             } else {111                 mPageIndicLayout.addView(new PageIndicatorView(mContext));112             }113         }114         PageIndicatorView selItem = (PageIndicatorView) mPageIndicLayout115                 .getChildAt(sel_page);116         selItem.setSelectedView(true);117     }118 }
复制代码

    定制的表情页面,继承HorizontalScrollView,支持水平滑动。需要说明的是页面指示器的布局是通过代码实现的,而不是在xml文件中

  4. ChatListViewAdapter.java

    消息适配器。发送的消息存放在mDatalist中

           在activity_chat.xml设置android:listSelector="#00FFFFFF"可以避免点击消息时出现的矩形框。

           重写的getView中实现自己发送的消息显示在右边,别人发送的消息显示在左边。

    TouchListener实现触摸消息变成密码形态,并在onclick方法中再次调用。我想大概是因为触摸和点击本来就不好区分吧。同时在点击事件里不要忘了设置消息显示的形态,因为listview在重绘时需要考虑这一点。

    Adapter的作用就是ListView界面与数据之间的桥梁,当列表里的每一项显示到页面时,都会调用Adapter的getView方法返回一个View。 


优化的思路两种: 

1. View的重用 
    View的每次创建是比较耗时的,因此对于getview方法传入的convertView应充分利用 != null的判断 

2.ViewHolder的应用 

View的findViewById()方法也是比较耗时的,因此需要考虑只调用一次,ViewHolder就是一个持有者的类,他里面一般没有方法,只有属性,作用就是一个临时的储存器,把你getView方法中每次返回的View存起来,可以下次再用。这样做的好处就是不必每次都到布局文件中去拿到你的View,提高了效率。

   5. Task.java定义了一些常量

   6. TaskService.java  在Service中新开线程和直接新开线程的区别与意义

     前面写到的蓝牙通信的几步走也是在这里面实现的

分为几个线程:

AcceptThread 等待客户端连接线程 

ConnectThread(BluetoothDevice device) 作为客户端连接指定的蓝牙设备线程

ConnectedThread(BluetoothSocket socket)  在客户端,使用一个单独的BluetoothSocket类去初始化一个外接连接和管理该连接,发送消息也在这个线程里面

TaskThread总线程和mTaskList一起协调上面三个线程的运行工作。

要搞清TaskServic的原理,理清两个变量很重要:mServiceHandler  mActivityHandler

mServiceHandler:监控着连接状态的变化,如断线,连接成功,连接中

mActivityHandler:监控着信息状态的变化,起到通知主Activity的作用。如:发消息,收消息。

7. SoundEffect.java 

    音效相关的类,实现了一个OnLoadCompleteListener接口,还有一个play() 方法,决定播放哪一首歌曲。

8. DataProtocol 和 Message

  DataProtocol 是对不同的消息类型进行打包和解包

  Message 定义了消息的几个参数

9. SelectDevice  DownloadActivity   ChatActivity 是应用程序里面的三个Activity

     保存和恢复activity的状态数据

 

 自己修改说明:

 ChatActivity加入再按一次退出功能,更加人性化。加入消息记录功能。

消息记录实现概述:当在服务中开始收发发送消息时,就通过mActivityHandler通知ChatActivity,完成数据库读写操作。

ChatActivity.java:

复制代码
  1 package cn.com.farsgiht.bluetoothdemo;  2   3 import java.text.SimpleDateFormat;  4 import java.util.ArrayList;  5 import java.util.HashMap;  6 import android.app.Activity;  7 import android.app.AlertDialog;  8 import android.bluetooth.BluetoothAdapter;  9 import android.bluetooth.BluetoothDevice; 10 import android.content.ContentValues; 11 import android.content.Context; 12 import android.content.DialogInterface; 13 import android.content.DialogInterface.OnClickListener; 14 import android.content.Intent; 15 import android.database.sqlite.SQLiteDatabase; 16 import android.graphics.Bitmap; 17 import android.graphics.BitmapFactory; 18 import android.os.Bundle; 19 import android.os.Handler; 20 import android.os.Message; 21 import android.text.Spannable; 22 import android.text.SpannableString; 23 import android.text.style.ImageSpan; 24 import android.util.DisplayMetrics; 25 import android.util.Log; 26 import android.view.Display; 27 import android.view.Gravity; 28 import android.view.KeyEvent; 29 import android.view.LayoutInflater; 30 import android.view.Menu; 31 import android.view.MenuInflater; 32 import android.view.MenuItem; 33 import android.view.View; 34 import android.view.ViewGroup; 35 import android.view.inputmethod.InputMethodManager; 36 import android.widget.AdapterView; 37 import android.widget.AdapterView.OnItemClickListener; 38 import android.widget.Button; 39 import android.widget.EditText; 40 import android.widget.GridView; 41 import android.widget.ImageView; 42 import android.widget.LinearLayout; 43 import android.widget.LinearLayout.LayoutParams; 44 import android.widget.ListView; 45 import android.widget.SimpleAdapter; 46 import android.widget.Toast; 47 import cn.com.farsgiht.bluetoothdemo.UI.ChatListViewAdapter; 48 import cn.com.farsgiht.bluetoothdemo.UI.DrawerHScrollView; 49 import cn.com.farsgiht.bluetoothdemo.sound.SoundEffect; 50 import cn.com.farsgiht.bluetoothdemo.task.Task; 51 import cn.com.farsgiht.bluetoothdemo.task.TaskService; 52 import cn.com.farsgiht.bluetoothdemo.utils.Utils; 53  54 public class ChatActivity extends Activity implements View.OnClickListener{ 55     private final String TAG = "ChatActivity"; 56     public static int sAliveCount = 0; 57     public static final String EXTRA_MESSAGER = "cn.com.farsgiht.bluetoothdemo.BUNDLE"; 58     public static final String DEVICE_NAME = "device_name"; 59     // 蓝牙状态变量 60     private static int sBTState = -1; 61      62     private final int REQUES_BT_ENABLE_CODE = 123; 63     private final int REQUES_SELECT_BT_CODE = 222; 64      65     private ListView mList; 66     private EditText mInput; 67     private Button mSendBtn; 68     private ImageView mEmoButton; 69     private GridView mGridView; 70     private boolean isUpdate = false; 71     private BluetoothDevice mRemoteDevice; 72      73     private LinearLayout mRootLayout, mChatLayout; 74      75     private View mEmoView; 76     private boolean isShowEmo = false; 77     private boolean isHaspressed = false; 78     private int mScrollHeight; 79      80     private DrawerHScrollView mScrollView; 81     private ChatListViewAdapter mAdapter2; 82     private ArrayList<HashMap<String, Object>> mChatContent2 = new ArrayList<HashMap<String, Object>>(); 83     private BluetoothAdapter mBluetoothAdapter; 84      85     private ArrayList<HashMap<String, Object>> mEmoList = new ArrayList<HashMap<String, Object>>(); 86      // 已连接设备的名字 87     private String mConnectedDeviceName = null; 88      89     private Handler mHandler = new Handler(){ 90         @Override 91         public void handleMessage(Message msg) { 92             //设置聊天信息的时间 93             SimpleDateFormat df0 = new SimpleDateFormat("MM-dd HH:mm:ss"); 94             String pdate=df0.format(System.currentTimeMillis()).toString();             95             switch(msg.what){ 96             case -1: 97                 showToast("没有连接其它用户,点击\"Menu\"扫描并选择周国用户"); 98                 SoundEffect.getInstance(ChatActivity.this).play(SoundEffect.SOUND_ERR); 99                 break;100             case Task.TASK_SEND_MSG:101 //               showToast(msg.obj.toString());102                String writeMessage = msg.obj.toString();103                if(writeMessage!=null && isHaspressed)104                {105                    //将发送的信息插入到数据库106                    ContentValues values=new ContentValues();107                    values.put("name", "我");108                    values.put("pdate",pdate);109                    values.put("informations", writeMessage);110                    //创建数据库111                    DatabaseHelper insertdbHelper=new DatabaseHelper(ChatActivity.this,"zhsf_db");112                    SQLiteDatabase insertdb=insertdbHelper.getWritableDatabase();113                    insertdb.insert("info", null, values);114                }115                 if(sAliveCount <= 0){116                     Utils.notifyMessage(ChatActivity.this, msg.obj.toString(), ChatActivity.this);117                 }              118                 break;    119             case Task.TASK_RECV_MSG:    120                String readMessage =((HashMap<String,Object>) msg.obj).get(ChatListViewAdapter.KEY_TEXT).toString();121                mConnectedDeviceName = ((HashMap<String,Object>) msg.obj).get(ChatListViewAdapter.KEY_NAME).toString(); 122                if(readMessage!=null)123                {124                    //将接受的信息插入到数据库125                    ContentValues values2=new ContentValues();126                    values2.put("name", mConnectedDeviceName);127                    values2.put("pdate",pdate);128                    values2.put("informations", readMessage);129                    DatabaseHelper insertdbHelper2=new DatabaseHelper(ChatActivity.this,"zhsf_db");130                    SQLiteDatabase insertdb2=insertdbHelper2.getWritableDatabase();131                    insertdb2.insert("info", null, values2);         132                }133                 134                 if(msg.obj == null)135                     return;136                 if(msg.obj instanceof HashMap<?, ?>){137                     showTargetMessage((HashMap<String, Object>) msg.obj);                    138                 }        139                 if(sAliveCount <= 0){140                     Utils.notifyMessage(ChatActivity.this, "您有未读取消息", ChatActivity.this);141                 }                              142                 break;143             case Task.TASK_GET_REMOTE_STATE:144                 setTitle((String)msg.obj);145                 if(sAliveCount <= 0){146                     if(isBTStateChanged(msg.arg1) && msg.arg1 != TaskService.BT_STAT_WAIT)147                         Utils.notifyMessage(ChatActivity.this, (String)msg.obj, ChatActivity.this);148                 }149                 break;150     151             }152         }153     };154     155     @Override156     protected void onCreate(Bundle savedInstanceState) {157         super.onCreate(savedInstanceState);158         setContentView(R.layout.activity_chat);159         160         // 获得蓝牙管理器161         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 162         if (mBluetoothAdapter == null) {163             Log.e(TAG, "Your device is not support Bluetooth!");164             Toast.makeText(this, "该设备没有蓝牙设备", Toast.LENGTH_LONG).show();165             return;166         }167         168         mRootLayout = (LinearLayout) findViewById(R.id.root);169         mChatLayout = (LinearLayout) findViewById(R.id.topPanel);170         mList = (ListView) findViewById(R.id.listView1);171     172         mAdapter2 = new ChatListViewAdapter(this, mChatContent2);173         174         mList.setAdapter(mAdapter2);175 176         // 初始化表情177         mEmoView = initEmoView();178         179         mInput = (EditText) findViewById(R.id.inputEdit);180         mInput.setOnClickListener(new android.view.View.OnClickListener() {181             @Override182             public void onClick(View v) {183                 // 点击输入框后,隐藏表情,显示输入法184                 InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 185                 imm.showSoftInput(mInput, 0);186                 showEmoPanel(false);187             }188         });189         190         mSendBtn = (Button) findViewById(R.id.sendBtn);191         mEmoButton = (ImageView) findViewById(R.id.emotionBtn);192         193         mSendBtn.setOnClickListener(this);194         mEmoButton.setOnClickListener(this);195         196         //---------------------------------------------------------------------197         // 打开蓝牙设备198         if (!mBluetoothAdapter.isEnabled()) {199             Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);200             startActivityForResult(enableBtIntent, REQUES_BT_ENABLE_CODE); 201         }else{202             // 默认设备作为服务端203             startServiceAsServer();204         }205         //---------------------------------------------------------------------206     }207     208     private View initEmoView(){209         if(mEmoView == null){210             LayoutInflater inflater = getLayoutInflater();211             mEmoView = inflater.inflate(R.layout.emo_layout, null);212             213             mScrollView = (DrawerHScrollView) mEmoView.findViewById(R.id.scrollView);214             mGridView = (GridView) mEmoView.findViewById(R.id.gridView);215             mGridView.setOnItemClickListener(new OnItemClickListener() {216                 @Override217                 public void onItemClick(AdapterView<?> parent, View view,218                         int position, long id) {219                     // 在android中要显示图片信息,必须使用Bitmap位图的对象来装载  220                     Bitmap bitmap = BitmapFactory.decodeResource(getResources(), (Integer) mEmoList.get(position).get("img")); 221                     ImageSpan imageSpan = new ImageSpan(ChatActivity.this, bitmap);  222                     SpannableString spannableString = new SpannableString((String) mEmoList.get(position).get("text"));//face就是图片的前缀名  223                     spannableString.setSpan(imageSpan, 0, 8,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);  224                     mInput.append(spannableString);225                     System.out.println("mInput:"+mInput.getText());226                 }227             });228 229             mScrollHeight = setScrollGridView(mScrollView, mGridView, 3);230             System.out.println("mScrollHeight:" + mScrollHeight);231         }232         return mEmoView;233     }234     235 236     237     private void startServiceAsServer(){238         TaskService.start(this, mHandler);239         TaskService.newTask(new Task(mHandler, Task.TASK_START_ACCEPT, null));240         SoundEffect.getInstance(this).play(SoundEffect.SOUND_PLAY);241     }242     243     @Override244     protected void onResume() {245         sAliveCount++;246         super.onResume();247     }248 249     @Override250     protected void onPause() {251         sAliveCount--;252         super.onPause();253     }254     255     @Override256     protected void onDestroy() {257         super.onDestroy();258         // 关闭蓝牙259         if(mBluetoothAdapter.isEnabled())260             mBluetoothAdapter.disable();261         // 停止服务262         TaskService.stop(this);263     }264     265     266     @Override267     public void onClick(View v) {268         if(v == mSendBtn){269             String msg = mInput.getText().toString().trim();270             TaskService.newTask(new Task(mHandler, Task.TASK_GET_REMOTE_STATE, null));//通过点击按钮触发相应线程的启动,比较巧妙,值得学习271             if(msg.length() == 0){272                 showToast("聊天内容为空");273                 SoundEffect.getInstance(ChatActivity.this).play(SoundEffect.SOUND_ERR);274                 return;275             }276             277             //------ DEUBG ------ 278             TaskService.newTask(new Task(mHandler, Task.TASK_SEND_MSG, new Object[]{msg}));279             showOwnMessage(msg);//立马显示自己发送的消息,所以在handler里面就没有再做处理280             isHaspressed = true;//数据库可以开始记录消息啦281             mInput.setText("");282         }else if(v == mEmoButton){283             System.out.println("Emo btn clicked");284             // 关闭输入法285             InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 286             imm.hideSoftInputFromWindow(mInput.getWindowToken(),0);287             if(isShowEmo){288                 showEmoPanel(false);289             }else{290                 showEmoPanel(true);291             }292         }293     }294     295     private void showEmoPanel(boolean show){296         if(show && !isShowEmo){297             mEmoView.setVisibility(View.VISIBLE);298             mEmoButton.setImageResource(R.drawable.emo_collapse);299             ViewGroup.LayoutParams params = mChatLayout.getLayoutParams();300             params.height = mChatLayout.getHeight() - mScrollHeight;301             mChatLayout.setLayoutParams(params);302             isShowEmo = true;303         }else if(!show && isShowEmo){304             mEmoView.setVisibility(View.GONE);305             mEmoButton.setImageResource(R.drawable.emo_bkg);306             ViewGroup.LayoutParams params = mChatLayout.getLayoutParams();307             params.height = mChatLayout.getHeight() + mScrollHeight;308             mChatLayout.setLayoutParams(params);309             isShowEmo = false;310         }311         if(!isUpdate && show){312             LinearLayout.LayoutParams para = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);313             mRootLayout.addView(mEmoView, para);314             isUpdate = true;315         }316     }317     318     319     320     private boolean isBTStateChanged(int now){321         if(sBTState != now){322             sBTState = now;323             return true;324         }else{325             return false;326         }327     }328     329     /**330      * 显示对方信息331      * @param data332      */333     private void showTargetMessage(HashMap<String, Object> data){334         SimpleDateFormat df1 = new SimpleDateFormat("E MM月dd日   HH:mm ");335         data.put(ChatListViewAdapter.KEY_DATE, df1.format(System.currentTimeMillis()).toString());336         data.put(ChatListViewAdapter.KEY_SHOW_MSG, true);337         mChatContent2.add(data);338         mAdapter2.notifyDataSetChanged();339         SoundEffect.getInstance(ChatActivity.this).play(SoundEffect.SOUND_RECV);340     }341     342     /**343      * 显示自己信息344      * @param data345      */346     private void showOwnMessage(String msg){347         HashMap<String, Object> map = new HashMap<String, Object>();348         map.put(ChatListViewAdapter.KEY_ROLE, ChatListViewAdapter.ROLE_OWN);//哪个角色的消息349         map.put(ChatListViewAdapter.KEY_NAME, mBluetoothAdapter.getName());350         map.put(ChatListViewAdapter.KEY_TEXT, msg);351         SimpleDateFormat df2 = new SimpleDateFormat("E MM月dd日  HH:mm ");352         map.put(ChatListViewAdapter.KEY_DATE, df2.format(System.currentTimeMillis()).toString());353         map.put(ChatListViewAdapter.KEY_SHOW_MSG, true);354         mChatContent2.add(map);355         mAdapter2.notifyDataSetChanged();356         SoundEffect.getInstance(ChatActivity.this).play(SoundEffect.SOUND_SEND);357     }358 359     @Override360     public boolean onCreateOptionsMenu(Menu menu) {361          MenuInflater inflater = getMenuInflater();362          inflater.inflate(R.menu.option_menu, menu);363          return true;364     }365 366     @Override367     public boolean onOptionsItemSelected(MenuItem item) {368           switch (item.getItemId()) {369             case R.id.scan:370                 startActivityForResult(new Intent(this, SelectDevice.class), REQUES_SELECT_BT_CODE);371                 break;372             case R.id.discoverable:373                 // 调用设置用户名方法374                 AlertDialog.Builder dlg = new AlertDialog.Builder(this);375                 final EditText devNameEdit = new EditText(this);376                 dlg.setView(devNameEdit);377                 dlg.setTitle("请输入用户名");378                 dlg.setPositiveButton("设置", new OnClickListener() {379                     public void onClick(DialogInterface dialog, int which) {380                         if(devNameEdit.getText().toString().length() != 0)381                             mBluetoothAdapter.setName(devNameEdit.getText().toString());382                     }383                 });384                 dlg.create();385                 dlg.show();386                 return true;387             case R.id.record:388                 Intent recordIntent = new Intent(ChatActivity.this, RecordListActivity.class);389                 startActivity(recordIntent);390                 return true;391             case R.id.exit:392                 Intent aboutIntent = new Intent(ChatActivity.this, DownloadActivity.class);393                 startActivity(aboutIntent);394                 return true;395             }396             return false;397     }398 399     @Override400     protected void onActivityResult(int requestCode, int resultCode, Intent data) {401         if(requestCode == REQUES_BT_ENABLE_CODE && resultCode == RESULT_OK){402             startServiceAsServer();403         }else if(requestCode == REQUES_SELECT_BT_CODE && resultCode == RESULT_OK){404             mRemoteDevice = data.getParcelableExtra("DEVICE");405             if(mRemoteDevice == null)406                 return;407             TaskService.newTask(new Task(mHandler, Task.TASK_START_CONN_THREAD, new Object[]{mRemoteDevice}));408         }409         super.onActivityResult(requestCode, resultCode, data);410     }411     412     private void showToast(String msg){413         Toast tst = Toast.makeText(this, msg, Toast.LENGTH_SHORT);414         tst.setGravity(Gravity.CENTER | Gravity.TOP, 0, 240);415         tst.show();416     }417     418     419     // 设置表情的多页滚动显示控件420     public int setScrollGridView(DrawerHScrollView scrollView, GridView gridView, 421             int lines) {422         423         DisplayMetrics dm = new DisplayMetrics();424         getWindowManager().getDefaultDisplay().getMetrics(dm); 425         Display display = getWindowManager().getDefaultDisplay();426         System.out.println("Width:" + display.getWidth());427         System.out.println("Height:" + display.getHeight());428 429         430         int scrollWid = display.getWidth();431         int scrollHei;432         System.out.println("scrollWid:" + scrollWid);433         if (scrollWid <= 0 ){434             Log.d(TAG, "scrollWid or scrollHei is less than 0");435             return 0;436         }437          438           439         float density  = dm.density;      // 屏幕密度(像素比例:0.75/1.0/1.5/2.0)440         441         int readlViewWidht = 56;442         // 图片都放在了Hdpi中,所以计算出图片的像素独立宽度443         int viewWidth = (int) (readlViewWidht * density / 1.5);444         int viewHeight = viewWidth;445         System.out.println("viewWidth:" + viewWidth + " viewHeight:" + viewHeight);446         447         int numColsPage = scrollWid / viewWidth;448         int spaceing = (scrollWid - viewWidth * numColsPage)/(numColsPage);449         System.out.println("Space:" + spaceing);450 451 452         SimpleAdapter adapter = getEmoAdapter();453         int pages = adapter.getCount() / (numColsPage * lines);454         455         if (pages * numColsPage * lines < adapter.getCount()){456             pages++;457         }458 459         System.out.println("pages:" + pages);460         461         scrollHei = lines * viewHeight + spaceing * (lines + 1);462         463         LayoutParams params = new LayoutParams(pages * scrollWid, LayoutParams.WRAP_CONTENT);464         gridView.setLayoutParams(params);465         gridView.setColumnWidth(viewWidth);466         gridView.setHorizontalSpacing(spaceing);467         gridView.setVerticalSpacing(spaceing);468         gridView.setStretchMode(GridView.NO_STRETCH);469         gridView.setNumColumns(numColsPage * pages);470 471         //adapter = new DrawerListAdapter(this, colWid, colHei);472         //listener = new DrawerItemClickListener();473         gridView.setAdapter(adapter);474         //mGridView.setOnItemClickListener(listener);475 476         scrollView.setParameters(pages, 0, scrollWid, spaceing);477         //updateDrawerPageLayout(pageNum, 0);478         // 表情区域还要加上分布显示区479         int pageNumHei = (int) (18 * density); 480         return scrollHei + pageNumHei;481     }482     483         484     private SimpleAdapter getEmoAdapter(){485            HashMap<String, Object> map = new HashMap<String, Object>();486            map.put("img", R.drawable.emo001);487            map.put("text", "<emo001>");488            mEmoList.add(map);489            map = new HashMap<String, Object>();490            map.put("img", R.drawable.emo002);491            map.put("text", "<emo002>");492            mEmoList.add(map);493            map = new HashMap<String, Object>();494            map.put("img", R.drawable.emo003);495            map.put("text", "<emo003>");496            mEmoList.add(map);497            map = new HashMap<String, Object>();498            map.put("img", R.drawable.emo004);499            map.put("text", "<emo004>");500            mEmoList.add(map);501            map = new HashMap<String, Object>();502            map.put("img", R.drawable.emo005);503            map.put("text", "<emo005>");504            mEmoList.add(map);505            map = new HashMap<String, Object>();506            map.put("img", R.drawable.emo006);507            map.put("text", "<emo006>");508            mEmoList.add(map);509            map = new HashMap<String, Object>();510            map.put("img", R.drawable.emo007);511            map.put("text", "<emo007>");512            mEmoList.add(map);513            map = new HashMap<String, Object>();514            map.put("img", R.drawable.emo008);515            map.put("text", "<emo008>");516            mEmoList.add(map);517            map = new HashMap<String, Object>();518            map.put("img", R.drawable.emo009);519            map.put("text", "<emo009>");520            mEmoList.add(map);521            map = new HashMap<String, Object>();522            map.put("img", R.drawable.emo010);523            map.put("text", "<emo010>");524            mEmoList.add(map);525            map = new HashMap<String, Object>();526            map.put("img", R.drawable.emo011);527            map.put("text", "<emo011>");528            mEmoList.add(map);529            map = new HashMap<String, Object>();530            map.put("img", R.drawable.emo012);531            map.put("text", "<emo012>");532            mEmoList.add(map);533            map = new HashMap<String, Object>();534            map.put("img", R.drawable.emo013);535            map.put("text", "<emo013>");536            mEmoList.add(map);537            map = new HashMap<String, Object>();538            map.put("img", R.drawable.emo014);539            map.put("text", "<emo014>");540            mEmoList.add(map);541            map = new HashMap<String, Object>();542            map.put("img", R.drawable.emo015);543            map.put("text", "<emo015>");544            mEmoList.add(map);545            map = new HashMap<String, Object>();546            map.put("img", R.drawable.emo016);547            map.put("text", "<emo016>");548            mEmoList.add(map);549            map = new HashMap<String, Object>();550            map.put("img", R.drawable.emo017);551            map.put("text", "<emo017>");552            mEmoList.add(map);553            map = new HashMap<String, Object>();554            map.put("img", R.drawable.emo018);555            map.put("text", "<emo018>");556            mEmoList.add(map);557            map = new HashMap<String, Object>();558            map.put("img", R.drawable.emo019);559            map.put("text", "<emo019>");560            mEmoList.add(map);561            map = new HashMap<String, Object>();562            map.put("img", R.drawable.emo020);563            map.put("text", "<emo020>");564            mEmoList.add(map);565            map = new HashMap<String, Object>();566            map.put("img", R.drawable.emo021);567            map.put("text", "<emo021>");568            mEmoList.add(map);569            map = new HashMap<String, Object>();570            map.put("img", R.drawable.emo022);571            map.put("text", "<emo022>");572            mEmoList.add(map);573            map = new HashMap<String, Object>();574            map.put("img", R.drawable.emo023);575            map.put("text", "<emo023>");576            mEmoList.add(map);577            map = new HashMap<String, Object>();578            map.put("img", R.drawable.emo024);579            map.put("text", "<emo024>");580            mEmoList.add(map);581            map = new HashMap<String, Object>();582            map.put("img", R.drawable.emo025);583            map.put("text", "<emo025>");584            mEmoList.add(map);585            map = new HashMap<String, Object>();586            map.put("img", R.drawable.emo026);587            map.put("text", "<emo026>");588            mEmoList.add(map);589            map = new HashMap<String, Object>();590            map.put("img", R.drawable.emo027);591            map.put("text", "<emo027>");592            mEmoList.add(map);593            map = new HashMap<String, Object>();594            map.put("img", R.drawable.emo028);595            map.put("text", "<emo028>");596            mEmoList.add(map);597            map = new HashMap<String, Object>();598            map.put("img", R.drawable.emo029);599            map.put("text", "<emo029>");600            mEmoList.add(map);601            map = new HashMap<String, Object>();602            map.put("img", R.drawable.emo030);603            map.put("text", "<emo030>");604            mEmoList.add(map);605            map = new HashMap<String, Object>();606            map.put("img", R.drawable.emo031);607            map.put("text", "<emo031>");608            mEmoList.add(map);609            map = new HashMap<String, Object>();610            map.put("img", R.drawable.emo032);611            map.put("text", "<emo032>");612            mEmoList.add(map);613            map = new HashMap<String, Object>();614            map.put("img", R.drawable.emo033);615            map.put("text", "<emo033>");616            mEmoList.add(map);617            map = new HashMap<String, Object>();618            map.put("img", R.drawable.emo034);619            map.put("text", "<emo034>");620            mEmoList.add(map);621            map = new HashMap<String, Object>();622            map.put("img", R.drawable.emo035);623            map.put("text", "<emo035>");624            mEmoList.add(map);625            map = new HashMap<String, Object>();626            map.put("img", R.drawable.emo036);627            map.put("text", "<emo036>");628            mEmoList.add(map);629            map = new HashMap<String, Object>();630            map.put("img", R.drawable.emo037);631            map.put("text", "<emo037>");632            mEmoList.add(map);633            map = new HashMap<String, Object>();634            map.put("img", R.drawable.emo038);635            map.put("text", "<emo038>");636            mEmoList.add(map);637            map = new HashMap<String, Object>();638            map.put("img", R.drawable.emo039);639            map.put("text", "<emo039>");640            mEmoList.add(map);641            map = new HashMap<String, Object>();642            map.put("img", R.drawable.emo040);643            map.put("text", "<emo040>");644            mEmoList.add(map);645            map = new HashMap<String, Object>();646            map.put("img", R.drawable.emo041);647            map.put("text", "<emo041>");648            mEmoList.add(map);649            map = new HashMap<String, Object>();650            map.put("img", R.drawable.emo042);651            map.put("text", "<emo042>");652            mEmoList.add(map);653            map = new HashMap<String, Object>();654            map.put("img", R.drawable.emo043);655            map.put("text", "<emo043>");656            mEmoList.add(map);657            map = new HashMap<String, Object>();658            map.put("img", R.drawable.emo044);659            map.put("text", "<emo044>");660            mEmoList.add(map);661            map = new HashMap<String, Object>();662            map.put("img", R.drawable.emo045);663            map.put("text", "<emo045>");664            mEmoList.add(map);665            map = new HashMap<String, Object>();666            map.put("img", R.drawable.emo046);667            map.put("text", "<emo046>");668            mEmoList.add(map);669            map = new HashMap<String, Object>();670            map.put("img", R.drawable.emo047);671            map.put("text", "<emo047>");672            mEmoList.add(map);673            map = new HashMap<String, Object>();674            map.put("img", R.drawable.emo048);675            map.put("text", "<emo048>");676            mEmoList.add(map);677            map = new HashMap<String, Object>();678            map.put("img", R.drawable.emo049);679            map.put("text", "<emo049>");680            mEmoList.add(map);681            map = new HashMap<String, Object>();682            map.put("img", R.drawable.emo050);683            map.put("text", "<emo050>");684            mEmoList.add(map);685            map = new HashMap<String, Object>();686            map.put("img", R.drawable.emo051);687            map.put("text", "<emo051>");688            mEmoList.add(map);689            map = new HashMap<String, Object>();690            map.put("img", R.drawable.emo052);691            map.put("text", "<emo052>");692            mEmoList.add(map);693            map = new HashMap<String, Object>();694            map.put("img", R.drawable.emo053);695            map.put("text", "<emo053>");696            mEmoList.add(map);697            map = new HashMap<String, Object>();698            map.put("img", R.drawable.emo054);699            map.put("text", "<emo054>");700            mEmoList.add(map);701            map = new HashMap<String, Object>();702            map.put("img", R.drawable.emo055);703            map.put("text", "<emo055>");704            mEmoList.add(map);705            map = new HashMap<String, Object>();706            map.put("img", R.drawable.emo056);707            map.put("text", "<emo056>");708            mEmoList.add(map);709            map = new HashMap<String, Object>();710            map.put("img", R.drawable.emo057);711            map.put("text", "<emo057>");712            mEmoList.add(map);713            map = new HashMap<String, Object>();714            map.put("img", R.drawable.emo058);715            map.put("text", "<emo058>");716            mEmoList.add(map);717            map = new HashMap<String, Object>();718            map.put("img", R.drawable.emo059);719            map.put("text", "<emo059>");720            mEmoList.add(map);721            map = new HashMap<String, Object>();722            map.put("img", R.drawable.emo060);723            map.put("text", "<emo060>");724            mEmoList.add(map);725            726            /**727             * 上述添加表情效率高,但是代码太冗余,下面的方式代码简单,但是效率较低728             */729            /*730            HashMap<String, Integer> map;731            for(int i = 0; i < 100; i++){732                map = new HashMap<String, Integer>();733                Field field=R.drawable.class.getDeclaredField("image"+i);  734                int resourceId=Integer.parseInt(field.get(null).toString());735                map.put("img", resourceId);736                mEmoList.add(map);737            }738            */739         return new SimpleAdapter(this, mEmoList, R.layout.grid_view_item, 740                     new String[]{"img"}, new int[]{R.id.imageView});741     }742     743     744     long waitTime = 2000;745     long touchTime = 0;746     @Override747     public boolean onKeyDown(int keyCode, KeyEvent event) {748         if(event.getAction() == KeyEvent.ACTION_DOWN && KeyEvent.KEYCODE_BACK == keyCode) {749             long currentTime = System.currentTimeMillis();750             if((currentTime-touchTime)>=waitTime) {751                 Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();752                 touchTime = currentTime;753             }else {754                 finish();755             }756             return true;757         }758         return super.onKeyDown(keyCode, event);759     }760     761 }
复制代码

TaskService.java:

复制代码
  1 package cn.com.farsgiht.bluetoothdemo.task;  2   3 import java.io.BufferedInputStream;  4 import java.io.BufferedOutputStream;  5 import java.io.IOException;  6 import java.io.InputStream;  7 import java.io.OutputStream;  8 import java.io.UnsupportedEncodingException;  9 import java.util.ArrayList; 10 import java.util.Calendar; 11 import java.util.HashMap; 12 import java.util.UUID; 13 import android.app.Service; 14 import android.bluetooth.BluetoothAdapter; 15 import android.bluetooth.BluetoothDevice; 16 import android.bluetooth.BluetoothServerSocket; 17 import android.bluetooth.BluetoothSocket; 18 import android.content.ContentValues; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.database.sqlite.SQLiteDatabase; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.os.IBinder; 25 import android.util.Log; 26 import android.widget.ArrayAdapter; 27 import android.widget.Toast; 28 import cn.com.farsgiht.bluetoothdemo.ChatActivity; 29 import cn.com.farsgiht.bluetoothdemo.UI.ChatListViewAdapter; 30 import cn.com.farsgiht.bluetoothdemo.protocol.DataProtocol; 31 import cn.com.farsgiht.bluetoothdemo.protocol.Message; 32 import cn.com.farsgiht.bluetoothdemo.sound.SoundEffect; 33  34 /** 35  * 任务处理服务 36  * @author Administrator 37  */ 38 public class TaskService extends Service { 39     public static final int BT_STAT_WAIT = 0; 40     public static final int BT_STAT_CONN = 1; 41     public static final int BT_STAT_ONLINE = 2; 42     public static final int BT_STAT_UNKNOWN = 3; 43      44   45     public static final String DEVICE_NAME = "device_name"; 46      47     private final String TAG = "TaskService"; 48     private TaskThread mThread; 49  50     private BluetoothAdapter mBluetoothAdapter; 51      52     private AcceptThread mAcceptThread; 53     private ConnectThread mConnectThread; 54     private ConnectedThread mCommThread; 55      56     private boolean isServerMode = true; 57  58     private static Handler mActivityHandler; 59  60     // 任务队列 61     private static ArrayList<Task> mTaskList = new ArrayList<Task>(); 62  63     private Handler mServiceHandler = new Handler() { 64         @Override 65         public void handleMessage(android.os.Message msg) {         66             switch (msg.what) { 67             case Task.TASK_GET_REMOTE_STATE: 68                 android.os.Message activityMsg = mActivityHandler.obtainMessage(); 69                 activityMsg.what = msg.what; 70                 if (mAcceptThread != null && mAcceptThread.isAlive()) { 71                     activityMsg.obj = "等待连接..."; 72                     activityMsg.arg1 = BT_STAT_WAIT; 73                 } else if (mCommThread != null && mCommThread.isAlive()) { 74                     activityMsg.obj = mCommThread.getRemoteName() + "[在线]"; 75                     activityMsg.arg1 = BT_STAT_ONLINE; 76                 } else if (mConnectThread != null && mConnectThread.isAlive()) { 77                     SoundEffect.getInstance(TaskService.this).play(3); 78                     activityMsg.obj = "正在连接:" 79                             + mConnectThread.getDevice().getName(); 80                     activityMsg.arg1 = BT_STAT_CONN; 81                 } else { 82                     activityMsg.obj = "未知状态"; 83                     activityMsg.arg1 = BT_STAT_UNKNOWN; 84                     SoundEffect.getInstance(TaskService.this).play(2); 85                     // 重新等待连接 86                     mAcceptThread = new AcceptThread(); 87                     mAcceptThread.start(); 88                     isServerMode = true; 89                 } 90  91                 mActivityHandler.sendMessage(activityMsg); 92                 break; 93             default: 94                 break; 95             } 96             super.handleMessage(msg); 97         } 98     }; 99     100     101     102     @Override103     public void onCreate() {104         super.onCreate();105         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();106         if (mBluetoothAdapter == null) {107             Log.e(TAG, "Your device is not support Bluetooth!");108             return;109         }110         mThread = new TaskThread();111         mThread.start();112     }113 114 115     public static void start(Context c, Handler handler){116         mActivityHandler = handler;117         Intent intent = new Intent(c, TaskService.class);118         c.startService(intent);119     }120     121     public static void stop(Context c){122         Intent intent = new Intent(c, TaskService.class);123         c.stopService(intent);124     }125     126 127 128     public static void newTask(Task target) {129         synchronized (mTaskList) {130             mTaskList.add(target);131         }132     }133 134     private class TaskThread extends Thread {135         private boolean isRun = true;136         private int mCount = 0;137 138         public void cancel() {139             isRun = false;140         }141 142         @Override143         public void run() {144             Task task;145             while (isRun) {146 147                 // 有任务148                 if (mTaskList.size() > 0) {149                     synchronized (mTaskList) {150                         // 获得任务151                         task = mTaskList.get(0);152                         doTask(task);153                     }154                 } else {155                     try {156                         Thread.sleep(200);157                         mCount++;158                     } catch (InterruptedException e) {159                     }160                     // 每过10秒钟进行一次状态检查161                     if (mCount >= 50) {162                         mCount = 0;163                         // 检查远程设备状态164                         android.os.Message handlerMsg = mServiceHandler165                                 .obtainMessage();166                         handlerMsg.what = Task.TASK_GET_REMOTE_STATE;167                         mServiceHandler.sendMessage(handlerMsg);168                     }169                 }170             }171         }172 173     }174 //对应三个线程,其中mCommThread是在mConnectThread的run()方法中new出来的175     private void doTask(Task task) {176         switch (task.getTaskID()) {177         case Task.TASK_START_ACCEPT:178             mAcceptThread = new AcceptThread();179             mAcceptThread.start();180             isServerMode = true;181             break;182         case Task.TASK_START_CONN_THREAD:183             if (task.mParams == null || task.mParams.length == 0) {184                 break;185             }186             BluetoothDevice remote = (BluetoothDevice) task.mParams[0];187             mConnectThread = new ConnectThread(remote);188             mConnectThread.start();189             isServerMode = false;190             break;191         case Task.TASK_SEND_MSG:192             boolean sucess = false;193             if (mCommThread == null || !mCommThread.isAlive()194                     || task.mParams == null || task.mParams.length == 0) {195                 Log.e(TAG, "mCommThread or task.mParams null");196             }else{197                 byte[] msg = null;198                 try {199                     200                     msg = DataProtocol.packMsg((String) task.mParams[0]);201                     sucess = mCommThread.write(msg);202      203                 } catch (UnsupportedEncodingException e) {204                     sucess = false;205                 }206             }207             if (!sucess) {208                 android.os.Message returnMsg = mActivityHandler.obtainMessage();209                 returnMsg.what = Task.TASK_SEND_MSG_FAIL;210                 returnMsg.obj = "消息发送失败";211                 mActivityHandler.sendMessage(returnMsg);212             }213             break;214         }215 216         // 移除任务217         mTaskList.remove(task);//每次保证任务列表里面只有一个任务,task = mTaskList.get(0);218     }219 220     @Override221     public void onDestroy() {222         super.onDestroy();223         mThread.cancel();224     }225 226     private final String UUID_STR = "00001101-0000-1000-8000-00805F9B34FB";227 228     /**229      * 等待客户端连接线程230      * 231      * @author Administrator232      */233     private class AcceptThread extends Thread {234         private final BluetoothServerSocket mmServerSocket;235         private boolean isCancel = false;236 237         public AcceptThread() {238             Log.d(TAG, "AcceptThread");239             BluetoothServerSocket tmp = null;240             try {241                 tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(242                         "MT_Chat_Room", UUID.fromString(UUID_STR));243             } catch (IOException e) {244             }245             mmServerSocket = tmp;246         }247 248         public void run() {249             BluetoothSocket socket = null;250             while (true) {251                 try {252                     // 阻塞等待253                     socket = mmServerSocket.accept();254                 } catch (IOException e) {255                     if (!isCancel) {256                         try {257                             mmServerSocket.close();258                         } catch (IOException e1) {259                         }260                         mAcceptThread = new AcceptThread();261                         mAcceptThread.start();262                         isServerMode = true;263                     }264                     break;265                 }266                 if (socket != null) {267                     manageConnectedSocket(socket);268                     try {269                         mmServerSocket.close();270                     } catch (IOException e) {271                     }272                     mAcceptThread = null;273                     break;274                 }275             }276         }277 278         public void cancel() {279             try {280                 Log.d(TAG, "AcceptThread canceled");281                 isCancel = true;282                 isServerMode = false;283                 mmServerSocket.close();284                 mAcceptThread = null;285                 if (mCommThread != null && mCommThread.isAlive()) {286                     mCommThread.cancel();287                 }288             } catch (IOException e) {289             }290         }291     }292 293     /**294      * 作为客户端连接指定的蓝牙设备线程295      * 296      * @author Administrator297      */298     private class ConnectThread extends Thread {299         private final BluetoothSocket mmSocket;300         private final BluetoothDevice mmDevice;301 302         public ConnectThread(BluetoothDevice device) {303 304             Log.d(TAG, "ConnectThread");305 306             if (mAcceptThread != null && mAcceptThread.isAlive()) {307                 mAcceptThread.cancel();308             }309 310             if (mCommThread != null && mCommThread.isAlive()) {311                 mCommThread.cancel();312             }313 314             // Use a temporary object that is later assigned to mmSocket,315             // because mmSocket is final316             BluetoothSocket tmp = null;317             mmDevice = device;318             try {319                 tmp = device.createRfcommSocketToServiceRecord(UUID320                         .fromString(UUID_STR));321             } catch (IOException e) {322                 Log.d(TAG, "createRfcommSocketToServiceRecord error!");323             }324 325             mmSocket = tmp;326         }327 328         public BluetoothDevice getDevice() {329             return mmDevice;330         }331 332         public void run() {333             // Cancel discovery because it will slow down the connection334             mBluetoothAdapter.cancelDiscovery();335             try {336                 // Connect the device through the socket. This will block337                 // until it succeeds or throws an exception338                 mmSocket.connect();339             } catch (IOException connectException) {340                 // Unable to connect; close the socket and get out341                 Log.e(TAG, "Connect server failed");342                 try {343                     mmSocket.close();344                 } catch (IOException closeException) {345                 }346                 mAcceptThread = new AcceptThread();347                 mAcceptThread.start();348                 isServerMode = true;349                 return;350             } // Do work to manage the connection (in a separate thread)351             manageConnectedSocket(mmSocket);352         }353 354         public void cancel() {355             try {356                 mmSocket.close();357             } catch (IOException e) {358             }359             mConnectThread = null;360         }361     }362 363     private void manageConnectedSocket(BluetoothSocket socket) {364         // 启动子线程来维持连接365         mCommThread = new ConnectedThread(socket);366         mCommThread.start();367     }368 369     private class ConnectedThread extends Thread {370         private final BluetoothSocket mmSocket;371         private final InputStream mmInStream;372         private final OutputStream mmOutStream;373         private BufferedOutputStream mmBos;374         private byte[] buffer;375 376         public ConnectedThread(BluetoothSocket socket) {377             Log.d(TAG, "ConnectedThread");378             mmSocket = socket;379             InputStream tmpIn = null;380             OutputStream tmpOut = null;381             try {382                 tmpIn = socket.getInputStream();383                 tmpOut = socket.getOutputStream();384             } catch (IOException e) {385             }386             mmInStream = tmpIn;387             mmOutStream = tmpOut;388             mmBos = new BufferedOutputStream(mmOutStream);389         }390 391         public OutputStream getOutputStream() {392             return mmOutStream;393         }394 395         public boolean write(byte[] msg) {396             if (msg == null)397                 return false;398             try {399                 mmBos.write(msg);400                 mmBos.flush();401                 402                 mActivityHandler.obtainMessage(Task.TASK_SEND_MSG, -1, -1, new String(msg)).sendToTarget();403                 System.out.println("Write:" + msg);404             } catch (IOException e) {405                 return false;406             }407             return true;408         }409 410         public String getRemoteName() {411             return mmSocket.getRemoteDevice().getName();412         }413 414         415         416         417         public void cancel() {418             try {419                 mmSocket.close();420             } catch (IOException e) {421             }422             mCommThread = null;423         }424 425         public void run() {426             try {427                 write(DataProtocol.packMsg(mBluetoothAdapter.getName()428                         + "已经上线\n"));//获取本地蓝牙适配器的蓝牙名称,这一条消息默认发送出去啦,429                                       //但消息记录里面不应该有这条消息,消息记录里面记录按过发送键的消息430             } catch (UnsupportedEncodingException e2) {431             }432             int size;433             Message msg;434             android.os.Message handlerMsg;435             buffer = new byte[1024];436 437             BufferedInputStream bis = new BufferedInputStream(mmInStream);438             // BufferedReader br = new BufferedReader(new439             // InputStreamReader(mmInStream));440             HashMap<String, Object> data;441             while (true) {442                 try {443                     size = bis.read(buffer);444                     msg = DataProtocol.unpackData(buffer);445                     if (msg == null)446                         continue;447 448                     if (mActivityHandler == null) {449                         return;450                     }451 452                     msg.remoteDevName = mmSocket.getRemoteDevice().getName();//得到对方设备的名字453                     if (msg.type == DataProtocol.TYPE_FILE) {454                         // 文件接收处理忽略455 456                     } else if (msg.type == DataProtocol.TYPE_MSG) {457                         data = new HashMap<String, Object>();458                         System.out.println("Read data.");459                         data.put(ChatListViewAdapter.KEY_ROLE,460                                 ChatListViewAdapter.ROLE_TARGET);461                         data.put(ChatListViewAdapter.KEY_NAME,462                                 msg.remoteDevName);463                         data.put(ChatListViewAdapter.KEY_TEXT, msg.msg);464                         465                         // 通过Activity更新到UI上466                         handlerMsg = mActivityHandler.obtainMessage();467                         handlerMsg.what = Task.TASK_RECV_MSG;468                         handlerMsg.obj = data;469                         mActivityHandler.sendMessage(handlerMsg);470                     }471                 } catch (IOException e) {472                     try {473                         mmSocket.close();474                     } catch (IOException e1) {475                     }476                     mCommThread = null;477                     if (isServerMode) {478                         // 检查远程设备状态479                         handlerMsg = mServiceHandler.obtainMessage();480                         handlerMsg.what = Task.TASK_GET_REMOTE_STATE;481                         mServiceHandler.sendMessage(handlerMsg);482                         SoundEffect.getInstance(TaskService.this).play(2);483                         mAcceptThread = new AcceptThread();484                         mAcceptThread.start();485                     }486                     break;487                 }488             }489         }490     }491 492     // ================================================================493 494     @Override495     public IBinder onBind(Intent intent) {496         // TODO Auto-generated method stub497         return null;498     }499 500 }
复制代码
 

实现效果:

             


0 0
原创粉丝点击