Skip to content

Most visited

Recently visited

navigation
BluetoothChat / src / com.example.android.bluetoothchat /

BluetoothChatFragment.java

1
/*
2
 * Copyright (C) 2014 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.example.android.bluetoothchat;
18
 
19
import android.app.ActionBar;
20
import android.app.Activity;
21
import android.bluetooth.BluetoothAdapter;
22
import android.bluetooth.BluetoothDevice;
23
import android.content.Intent;
24
import android.os.Bundle;
25
import android.os.Handler;
26
import android.os.Message;
27
import android.support.annotation.Nullable;
28
import android.support.v4.app.Fragment;
29
import android.support.v4.app.FragmentActivity;
30
import android.view.KeyEvent;
31
import android.view.LayoutInflater;
32
import android.view.Menu;
33
import android.view.MenuInflater;
34
import android.view.MenuItem;
35
import android.view.View;
36
import android.view.ViewGroup;
37
import android.view.inputmethod.EditorInfo;
38
import android.widget.ArrayAdapter;
39
import android.widget.Button;
40
import android.widget.EditText;
41
import android.widget.ListView;
42
import android.widget.TextView;
43
import android.widget.Toast;
44
 
45
import com.example.android.common.logger.Log;
46
 
47
/**
48
 * This fragment controls Bluetooth to communicate with other devices.
49
 */
50
public class BluetoothChatFragment extends Fragment {
51
 
52
    private static final String TAG = "BluetoothChatFragment";
53
 
54
    // Intent request codes
55
    private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
56
    private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
57
    private static final int REQUEST_ENABLE_BT = 3;
58
 
59
    // Layout Views
60
    private ListView mConversationView;
61
    private EditText mOutEditText;
62
    private Button mSendButton;
63
 
64
    /**
65
     * Name of the connected device
66
     */
67
    private String mConnectedDeviceName = null;
68
 
69
    /**
70
     * Array adapter for the conversation thread
71
     */
72
    private ArrayAdapter<String> mConversationArrayAdapter;
73
 
74
    /**
75
     * String buffer for outgoing messages
76
     */
77
    private StringBuffer mOutStringBuffer;
78
 
79
    /**
80
     * Local Bluetooth adapter
81
     */
82
    private BluetoothAdapter mBluetoothAdapter = null;
83
 
84
    /**
85
     * Member object for the chat services
86
     */
87
    private BluetoothChatService mChatService = null;
88
 
89
    @Override
90
    public void onCreate(Bundle savedInstanceState) {
91
        super.onCreate(savedInstanceState);
92
        setHasOptionsMenu(true);
93
        // Get local Bluetooth adapter
94
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
95
 
96
        // If the adapter is null, then Bluetooth is not supported
97
        if (mBluetoothAdapter == null) {
98
            FragmentActivity activity = getActivity();
99
            Toast.makeText(activity, "Bluetooth is not available", Toast.LENGTH_LONG).show();
100
            activity.finish();
101
        }
102
    }
103
 
104
 
105
    @Override
106
    public void onStart() {
107
        super.onStart();
108
        // If BT is not on, request that it be enabled.
109
        // setupChat() will then be called during onActivityResult
110
        if (!mBluetoothAdapter.isEnabled()) {
111
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
112
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
113
            // Otherwise, setup the chat session
114
        } else if (mChatService == null) {
115
            setupChat();
116
        }
117
    }
118
 
119
    @Override
120
    public void onDestroy() {
121
        super.onDestroy();
122
        if (mChatService != null) {
123
            mChatService.stop();
124
        }
125
    }
126
 
127
    @Override
128
    public void onResume() {
129
        super.onResume();
130
 
131
        // Performing this check in onResume() covers the case in which BT was
132
        // not enabled during onStart(), so we were paused to enable it...
133
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
134
        if (mChatService != null) {
135
            // Only if the state is STATE_NONE, do we know that we haven't started already
136
            if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
137
                // Start the Bluetooth chat services
138
                mChatService.start();
139
            }
140
        }
141
    }
142
 
143
    @Override
144
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
145
                             @Nullable Bundle savedInstanceState) {
146
        return inflater.inflate(R.layout.fragment_bluetooth_chat, container, false);
147
    }
148
 
149
    @Override
150
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
151
        mConversationView = (ListView) view.findViewById(R.id.in);
152
        mOutEditText = (EditText) view.findViewById(R.id.edit_text_out);
153
        mSendButton = (Button) view.findViewById(R.id.button_send);
154
    }
155
 
156
    /**
157
     * Set up the UI and background operations for chat.
158
     */
159
    private void setupChat() {
160
        Log.d(TAG, "setupChat()");
161
 
162
        // Initialize the array adapter for the conversation thread
163
        mConversationArrayAdapter = new ArrayAdapter<String>(getActivity(), R.layout.message);
164
 
165
        mConversationView.setAdapter(mConversationArrayAdapter);
166
 
167
        // Initialize the compose field with a listener for the return key
168
        mOutEditText.setOnEditorActionListener(mWriteListener);
169
 
170
        // Initialize the send button with a listener that for click events
171
        mSendButton.setOnClickListener(new View.OnClickListener() {
172
            public void onClick(View v) {
173
                // Send a message using content of the edit text widget
174
                View view = getView();
175
                if (null != view) {
176
                    TextView textView = (TextView) view.findViewById(R.id.edit_text_out);
177
                    String message = textView.getText().toString();
178
                    sendMessage(message);
179
                }
180
            }
181
        });
182
 
183
        // Initialize the BluetoothChatService to perform bluetooth connections
184
        mChatService = new BluetoothChatService(getActivity(), mHandler);
185
 
186
        // Initialize the buffer for outgoing messages
187
        mOutStringBuffer = new StringBuffer("");
188
    }
189
 
190
    /**
191
     * Makes this device discoverable for 300 seconds (5 minutes).
192
     */
193
    private void ensureDiscoverable() {
194
        if (mBluetoothAdapter.getScanMode() !=
195
                BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
196
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
197
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
198
            startActivity(discoverableIntent);
199
        }
200
    }
201
 
202
    /**
203
     * Sends a message.
204
     *
205
     * @param message A string of text to send.
206
     */
207
    private void sendMessage(String message) {
208
        // Check that we're actually connected before trying anything
209
        if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
210
            Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
211
            return;
212
        }
213
 
214
        // Check that there's actually something to send
215
        if (message.length() > 0) {
216
            // Get the message bytes and tell the BluetoothChatService to write
217
            byte[] send = message.getBytes();
218
            mChatService.write(send);
219
 
220
            // Reset out string buffer to zero and clear the edit text field
221
            mOutStringBuffer.setLength(0);
222
            mOutEditText.setText(mOutStringBuffer);
223
        }
224
    }
225
 
226
    /**
227
     * The action listener for the EditText widget, to listen for the return key
228
     */
229
    private TextView.OnEditorActionListener mWriteListener
230
            = new TextView.OnEditorActionListener() {
231
        public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
232
            // If the action is a key-up event on the return key, send the message
233
            if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
234
                String message = view.getText().toString();
235
                sendMessage(message);
236
            }
237
            return true;
238
        }
239
    };
240
 
241
    /**
242
     * Updates the status on the action bar.
243
     *
244
     * @param resId a string resource ID
245
     */
246
    private void setStatus(int resId) {
247
        FragmentActivity activity = getActivity();
248
        if (null == activity) {
249
            return;
250
        }
251
        final ActionBar actionBar = activity.getActionBar();
252
        if (null == actionBar) {
253
            return;
254
        }
255
        actionBar.setSubtitle(resId);
256
    }
257
 
258
    /**
259
     * Updates the status on the action bar.
260
     *
261
     * @param subTitle status
262
     */
263
    private void setStatus(CharSequence subTitle) {
264
        FragmentActivity activity = getActivity();
265
        if (null == activity) {
266
            return;
267
        }
268
        final ActionBar actionBar = activity.getActionBar();
269
        if (null == actionBar) {
270
            return;
271
        }
272
        actionBar.setSubtitle(subTitle);
273
    }
274
 
275
    /**
276
     * The Handler that gets information back from the BluetoothChatService
277
     */
278
    private final Handler mHandler = new Handler() {
279
        @Override
280
        public void handleMessage(Message msg) {
281
            FragmentActivity activity = getActivity();
282
            switch (msg.what) {
283
                case Constants.MESSAGE_STATE_CHANGE:
284
                    switch (msg.arg1) {
285
                        case BluetoothChatService.STATE_CONNECTED:
286
                            setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
287
                            mConversationArrayAdapter.clear();
288
                            break;
289
                        case BluetoothChatService.STATE_CONNECTING:
290
                            setStatus(R.string.title_connecting);
291
                            break;
292
                        case BluetoothChatService.STATE_LISTEN:
293
                        case BluetoothChatService.STATE_NONE:
294
                            setStatus(R.string.title_not_connected);
295
                            break;
296
                    }
297
                    break;
298
                case Constants.MESSAGE_WRITE:
299
                    byte[] writeBuf = (byte[]) msg.obj;
300
                    // construct a string from the buffer
301
                    String writeMessage = new String(writeBuf);
302
                    mConversationArrayAdapter.add("Me:  " + writeMessage);
303
                    break;
304
                case Constants.MESSAGE_READ:
305
                    byte[] readBuf = (byte[]) msg.obj;
306
                    // construct a string from the valid bytes in the buffer
307
                    String readMessage = new String(readBuf, 0, msg.arg1);
308
                    mConversationArrayAdapter.add(mConnectedDeviceName + ":  " + readMessage);
309
                    break;
310
                case Constants.MESSAGE_DEVICE_NAME:
311
                    // save the connected device's name
312
                    mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
313
                    if (null != activity) {
314
                        Toast.makeText(activity, "Connected to "
315
                                + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
316
                    }
317
                    break;
318
                case Constants.MESSAGE_TOAST:
319
                    if (null != activity) {
320
                        Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
321
                                Toast.LENGTH_SHORT).show();
322
                    }
323
                    break;
324
            }
325
        }
326
    };
327
 
328
    public void onActivityResult(int requestCode, int resultCode, Intent data) {