Sunday, August 14, 2011

tutorial for spinner in android

/*

* Copyright (C) 2010 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/




package com.android.example.spinner;



import com.android.example.spinner.R;



import android.app.Activity;

import android.content.Context;

import android.content.SharedPreferences;

import android.os.Bundle;

import android.view.View;

import android.widget.AdapterView;

import android.widget.ArrayAdapter;

import android.widget.Spinner;

import android.widget.TextView;

import android.widget.Toast;

import android.widget.AdapterView.OnItemSelectedListener;



/**

* Displays an Android spinner widget backed by data in an array. The

* array is loaded from the strings.xml resources file.

*/


public class SpinnerActivity extends Activity {



/**

* Fields to contain the current position and display contents of the spinner

*/


protected int mPos;

protected String mSelection;



/**

* ArrayAdapter connects the spinner widget to array-based data.

*/


protected ArrayAdapter<CharSequence> mAdapter;



/**

* The initial position of the spinner when it is first installed.

*/


public static final int DEFAULT_POSITION = 2;



/**

* The name of a properties file that stores the position and

* selection when the activity is not loaded.

*/


public static final String PREFERENCES_FILE = "SpinnerPrefs";



/**

* These values are used to read and write the properties file.

* PROPERTY_DELIMITER delimits the key and value in a Java properties file.

* The "marker" strings are used to write the properties into the file

*/


public static final String PROPERTY_DELIMITER = "=";



/**

* The key or label for "position" in the preferences file

*/


public static final String POSITION_KEY = "Position";



/**

* The key or label for "selection" in the preferences file

*/


public static final String SELECTION_KEY = "Selection";



public static final String POSITION_MARKER =

POSITION_KEY
+ PROPERTY_DELIMITER;



public static final String SELECTION_MARKER =

SELECTION_KEY
+ PROPERTY_DELIMITER;



/**

* Initializes the application and the activity.

* 1) Sets the view

* 2) Reads the spinner's backing data from the string resources file

* 3) Instantiates a callback listener for handling selection from the

* spinner

* Notice that this method includes code that can be uncommented to force

* tests to fail.

*

* This method overrides the default onCreate() method for an Activity.

*

* @see android.app.Activity#onCreate(android.os.Bundle)

*/


@Override

public void onCreate(Bundle savedInstanceState) {



/**

* derived classes that use onCreate() overrides must always call the super constructor

*/


super.onCreate(savedInstanceState);



setContentView
(R.layout.main);



Spinner spinner = (Spinner) findViewById(R.id.Spinner01);



/*

* Create a backing mLocalAdapter for the Spinner from a list of the

* planets. The list is defined by XML in the strings.xml file.

*/




this.mAdapter = ArrayAdapter.createFromResource(this, R.array.Planets,

android
.R.layout.simple_spinner_dropdown_item);



/*

* Attach the mLocalAdapter to the spinner.

*/




spinner
.setAdapter(this.mAdapter);



/*

* Create a listener that is triggered when Android detects the

* user has selected an item in the Spinner.

*/




OnItemSelectedListener spinnerListener = new myOnItemSelectedListener(this,this.mAdapter);



/*

* Attach the listener to the Spinner.

*/




spinner
.setOnItemSelectedListener(spinnerListener);





/*

* To demonstrate a failure in the preConditions test,

* uncomment the following line.

* The test will fail because the selection listener for the

* Spinner is not set.

*/


// spinner.setOnItemSelectedListener(null);



}





/**

* A callback listener that implements the

* {@link android.widget.AdapterView.OnItemSelectedListener} interface

* For views based on adapters, this interface defines the methods available

* when the user selects an item from the View.

*

*/


public class myOnItemSelectedListener implements OnItemSelectedListener {



/*

* provide local instances of the mLocalAdapter and the mLocalContext

*/




ArrayAdapter<CharSequence> mLocalAdapter;

Activity mLocalContext;



/**

* Constructor

* @param c - The activity that displays the Spinner.

* @param ad - The Adapter view that

* controls the Spinner.

* Instantiate a new listener object.

*/


public myOnItemSelectedListener(Activity c, ArrayAdapter<CharSequence> ad) {



this.mLocalContext = c;

this.mLocalAdapter = ad;



}



/**

* When the user selects an item in the spinner, this method is invoked by the callback

* chain. Android calls the item selected listener for the spinner, which invokes the

* onItemSelected method.

*

* @see android.widget.AdapterView.OnItemSelectedListener#onItemSelected(

* android.widget.AdapterView, android.view.View, int, long)

* @param parent - the AdapterView for this listener

* @param v - the View for this listener

* @param pos - the 0-based position of the selection in the mLocalAdapter

* @param row - the 0-based row number of the selection in the View

*/


public void onItemSelected(AdapterView parent, View v, int pos, long row) {



SpinnerActivity.this.mPos = pos;

SpinnerActivity.this.mSelection = parent.getItemAtPosition(pos).toString();

/*

* Set the value of the text field in the UI

*/


TextView resultText = (TextView)findViewById(R.id.SpinnerResult);

resultText
.setText(SpinnerActivity.this.mSelection);

}



/**

* The definition of OnItemSelectedListener requires an override

* of onNothingSelected(), even though this implementation does not use it.

* @param parent - The View for this Listener

*/


public void onNothingSelected(AdapterView parent) {



// do nothing



}

}



/**

* Restores the current state of the spinner (which item is selected, and the value

* of that item).

* Since onResume() is always called when an Activity is starting, even if it is re-displaying

* after being hidden, it is the best place to restore state.

*

* Attempts to read the state from a preferences file. If this read fails,

* assume it was just installed, so do an initialization. Regardless, change the

* state of the spinner to be the previous position.

*

* @see android.app.Activity#onResume()

*/


@Override

public void onResume() {



/*

* an override to onResume() must call the super constructor first.

*/




super.onResume();



/*

* Try to read the preferences file. If not found, set the state to the desired initial

* values.

*/




if (!readInstanceState(this)) setInitialState();



/*

* Set the spinner to the current state.

*/




Spinner restoreSpinner = (Spinner)findViewById(R.id.Spinner01);

restoreSpinner
.setSelection(getSpinnerPosition());



}



/**

* Store the current state of the spinner (which item is selected, and the value of that item).

* Since onPause() is always called when an Activity is about to be hidden, even if it is about

* to be destroyed, it is the best place to save state.

*

* Attempt to write the state to the preferences file. If this fails, notify the user.

*

* @see android.app.Activity#onPause()

*/


@Override

public void onPause() {



/*

* an override to onPause() must call the super constructor first.

*/




super.onPause();



/*

* Save the state to the preferences file. If it fails, display a Toast, noting the failure.

*/




if (!writeInstanceState(this)) {

Toast.makeText(this,

"Failed to write state!", Toast.LENGTH_LONG).show();

}

}



/**

* Sets the initial state of the spinner when the application is first run.

*/


public void setInitialState() {



this.mPos = DEFAULT_POSITION;



}



/**

* Read the previous state of the spinner from the preferences file

* @param c - The Activity's Context

*/


public boolean readInstanceState(Context c) {



/*

* The preferences are stored in a SharedPreferences file. The abstract implementation of

* SharedPreferences is a "file" containing a hashmap. All instances of an application

* share the same instance of this file, which means that all instances of an application

* share the same preference settings.

*/




/*

* Get the SharedPreferences object for this application

*/




SharedPreferences p = c.getSharedPreferences(PREFERENCES_FILE, MODE_WORLD_READABLE);

/*

* Get the position and value of the spinner from the file, or a default value if the

* key-value pair does not exist.

*/


this.mPos = p.getInt(POSITION_KEY, SpinnerActivity.DEFAULT_POSITION);

this.mSelection = p.getString(SELECTION_KEY, "");



/*

* SharedPreferences doesn't fail if the code tries to get a non-existent key. The

* most straightforward way to indicate success is to return the results of a test that

* SharedPreferences contained the position key.

*/




return (p.contains(POSITION_KEY));



}



/**

* Write the application's current state to a properties repository.

* @param c - The Activity's Context

*

*/


public boolean writeInstanceState(Context c) {



/*

* Get the SharedPreferences object for this application

*/




SharedPreferences p =

c
.getSharedPreferences(SpinnerActivity.PREFERENCES_FILE, MODE_WORLD_READABLE);



/*

* Get the editor for this object. The editor interface abstracts the implementation of

* updating the SharedPreferences object.

*/




SharedPreferences.Editor e = p.edit();



/*

* Write the keys and values to the Editor

*/




e
.putInt(POSITION_KEY, this.mPos);

e
.putString(SELECTION_KEY, this.mSelection);



/*

* Commit the changes. Return the result of the commit. The commit fails if Android

* failed to commit the changes to persistent storage.

*/




return (e.commit());



}



public int getSpinnerPosition() {

return this.mPos;

}



public void setSpinnerPosition(int pos) {

this.mPos = pos;

}



public String getSpinnerSelection() {

return this.mSelection;

}



public void setSpinnerSelection(String selection) {

this.mSelection = selection;

}

}

tutorial for radiogroup and radio button

Using RadioGroups and RadioButtons, You often use radio buttons when a user should be allowed to only select one item from a small group of items. For instance, a question asking for gender can give three options: male, female, and unspecified. Only one of these options should be checked at a time.The RadioButton objects are similar to CheckBox objects.They have a text label next to them, set via the text attribute, and they have a state (checked or unchecked). However, you can 148 Chapter 7 Exploring User Interface Screen Elements group RadioButton objects inside a RadioGroup that handles enforcing their combined states so that only one RadioButton can be checked at a time. If the user selects a RadioButton that is already checked, it does not become unchecked. However, you can provide the user with an action to clear the state of the entire RadioGroup so that none of the buttons are checked.

Here we have an XML layout resource with a RadioGroup containing four RadioButton objects (shown in Figure 7.7, toward the bottom of the screen).The RadioButton objects have text labels,“Option 1,” and so on.The XML layout resource definition is shown here:


You handle actions on these RadioButton objects through the RadioGroup object.The following example shows registering for clicks on the RadioButton objects within the


RadioGroup:
final RadioGroup group = (RadioGroup)findViewById(R.id.RadioGroup01);
final TextView tv = (TextView)
findViewById(R.id.TextView01);
group.setOnCheckedChangeListener(new
RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(
Using Buttons, Check Boxes, and Radio Groups 149
RadioGroup group, int checkedId) {
if (checkedId != -1) {
RadioButton rb = (RadioButton)
findViewById(checkedId);
if (rb != null) {
tv.setText(“You chose: “ + rb.getText());
}
} else {
tv.setText(“Choose 1”);
}
}
});

As this layout example demonstrates, there is nothing special that you need to do to make the RadioGroup and internal RadioButton objects work properly.The preceding code illustrates how to register to receive a notification whenever the RadioButton selection
changes.

The code demonstrates that the notification contains the resource identifier for the specific RadioButton that the user chose, as assigned in the layout file.To do something interesting with this, you need to provide a mapping between this resource identifier (or the text label) to the corresponding functionality in your code. In the example,we query for the button that was selected, get its text, and assign its text to another TextView control that we have on the screen.

As mentioned, the entire RadioGroup can be cleared so that none of the RadioButton objects are selected.The following example demonstrates how to do this in response to a button click outside of the RadioGroup:

final Button clear_choice = (Button) findViewById(R.id.Button01);
clear_choice.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
RadioGroup group = (RadioGroup)
findViewById(R.id.RadioGroup01);
if (group != null) {
group.clearCheck();
}
}
}

The action of calling the clearCheck() method triggers a call to the onCheckedChangedListener() callback method.This is why we have to make sure that the resource identifier we received is valid. Right after a call to the clearCheck() method, it is not a valid identifier but instead is set to the value -1 to indicate that no RadioButton is currently checked.

Download android software n game



www.androidmarket.com

Friday, August 12, 2011

Tutorial for Bluetooth

BluetoothChat

/*

* Copyright (C) 2009 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/




package com.example.android.BluetoothChat;



import android.app.ActionBar;

import android.app.Activity;

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.content.Intent;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

import android.view.KeyEvent;

import android.view.Menu;

import android.view.MenuInflater;

import android.view.MenuItem;

import android.view.View;

import android.view.Window;

import android.view.View.OnClickListener;

import android.view.inputmethod.EditorInfo;

import android.widget.ArrayAdapter;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.Toast;



/**

* This is the main Activity that displays the current chat session.

*/


public class BluetoothChat extends Activity {

// Debugging

private static final String TAG = "BluetoothChat";

private static final boolean D = true;



// Message types sent from the BluetoothChatService Handler

public static final int MESSAGE_STATE_CHANGE = 1;

public static final int MESSAGE_READ = 2;

public static final int MESSAGE_WRITE = 3;

public static final int MESSAGE_DEVICE_NAME = 4;

public static final int MESSAGE_TOAST = 5;



// Key names received from the BluetoothChatService Handler

public static final String DEVICE_NAME = "device_name";

public static final String TOAST = "toast";



// Intent request codes

private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;

private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;

private static final int REQUEST_ENABLE_BT = 3;



// Layout Views

private ListView mConversationView;

private EditText mOutEditText;

private Button mSendButton;



// Name of the connected device

private String mConnectedDeviceName = null;

// Array adapter for the conversation thread

private ArrayAdapter<String> mConversationArrayAdapter;

// String buffer for outgoing messages

private StringBuffer mOutStringBuffer;

// Local Bluetooth adapter

private BluetoothAdapter mBluetoothAdapter = null;

// Member object for the chat services

private BluetoothChatService mChatService = null;





@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

if(D) Log.e(TAG, "+++ ON CREATE +++");



// Set up the window layout

setContentView
(R.layout.main);



// Get local Bluetooth adapter

mBluetoothAdapter
= BluetoothAdapter.getDefaultAdapter();



// If the adapter is null, then Bluetooth is not supported

if (mBluetoothAdapter == null) {

Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();

finish
();

return;

}

}



@Override

public void onStart() {

super.onStart();

if(D) Log.e(TAG, "++ ON START ++");



// If BT is not on, request that it be enabled.

// setupChat() will then be called during onActivityResult

if (!mBluetoothAdapter.isEnabled()) {

Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult
(enableIntent, REQUEST_ENABLE_BT);

// Otherwise, setup the chat session

} else {

if (mChatService == null) setupChat();

}

}



@Override

public synchronized void onResume() {

super.onResume();

if(D) Log.e(TAG, "+ ON RESUME +");



// Performing this check in onResume() covers the case in which BT was

// not enabled during onStart(), so we were paused to enable it...

// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.

if (mChatService != null) {

// Only if the state is STATE_NONE, do we know that we haven't started already

if (mChatService.getState() == BluetoothChatService.STATE_NONE) {

// Start the Bluetooth chat services

mChatService
.start();

}

}

}



private void setupChat() {

Log.d(TAG, "setupChat()");



// Initialize the array adapter for the conversation thread

mConversationArrayAdapter
= new ArrayAdapter<String>(this, R.layout.message);

mConversationView
= (ListView) findViewById(R.id.in);

mConversationView
.setAdapter(mConversationArrayAdapter);



// Initialize the compose field with a listener for the return key

mOutEditText
= (EditText) findViewById(R.id.edit_text_out);

mOutEditText
.setOnEditorActionListener(mWriteListener);



// Initialize the send button with a listener that for click events

mSendButton
= (Button) findViewById(R.id.button_send);

mSendButton
.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

// Send a message using content of the edit text widget

TextView view = (TextView) findViewById(R.id.edit_text_out);

String message = view.getText().toString();

sendMessage
(message);

}

});



// Initialize the BluetoothChatService to perform bluetooth connections

mChatService
= new BluetoothChatService(this, mHandler);



// Initialize the buffer for outgoing messages

mOutStringBuffer
= new StringBuffer("");

}



@Override

public synchronized void onPause() {

super.onPause();

if(D) Log.e(TAG, "- ON PAUSE -");

}



@Override

public void onStop() {

super.onStop();

if(D) Log.e(TAG, "-- ON STOP --");

}



@Override

public void onDestroy() {

super.onDestroy();

// Stop the Bluetooth chat services

if (mChatService != null) mChatService.stop();

if(D) Log.e(TAG, "--- ON DESTROY ---");

}



private void ensureDiscoverable() {

if(D) Log.d(TAG, "ensure discoverable");

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);

}

}



/**

* Sends a message.

* @param message A string of text to send.

*/


private void sendMessage(String message) {

// Check that we're actually connected before trying anything

if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {

Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();

return;

}



// Check that there's actually something to send

if (message.length() > 0) {

// Get the message bytes and tell the BluetoothChatService to write

byte[] send = message.getBytes();

mChatService
.write(send);



// Reset out string buffer to zero and clear the edit text field

mOutStringBuffer
.setLength(0);

mOutEditText
.setText(mOutStringBuffer);

}

}



// The action listener for the EditText widget, to listen for the return key

private TextView.OnEditorActionListener mWriteListener =

new TextView.OnEditorActionListener() {

public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {

// If the action is a key-up event on the return key, send the message

if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {

String message = view.getText().toString();

sendMessage
(message);

}

if(D) Log.i(TAG, "END onEditorAction");

return true;

}

};



private final void setStatus(int resId) {

final ActionBar actionBar = getActionBar();

actionBar
.setSubtitle(resId);

}



private final void setStatus(CharSequence subTitle) {

final ActionBar actionBar = getActionBar();

actionBar
.setSubtitle(subTitle);

}



// The Handler that gets information back from the BluetoothChatService

private final Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case MESSAGE_STATE_CHANGE:

if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);

switch (msg.arg1) {

case BluetoothChatService.STATE_CONNECTED:

setStatus
(getString(R.string.title_connected_to, mConnectedDeviceName));

mConversationArrayAdapter
.clear();

break;

case BluetoothChatService.STATE_CONNECTING:

setStatus
(R.string.title_connecting);

break;

case BluetoothChatService.STATE_LISTEN:

case BluetoothChatService.STATE_NONE:

setStatus
(R.string.title_not_connected);

break;

}

break;

case MESSAGE_WRITE:

byte[] writeBuf = (byte[]) msg.obj;

// construct a string from the buffer

String writeMessage = new String(writeBuf);

mConversationArrayAdapter
.add("Me: " + writeMessage);

break;

case MESSAGE_READ:

byte[] readBuf = (byte[]) msg.obj;

// construct a string from the valid bytes in the buffer

String readMessage = new String(readBuf, 0, msg.arg1);

mConversationArrayAdapter
.add(mConnectedDeviceName+": " + readMessage);

break;

case MESSAGE_DEVICE_NAME:

// save the connected device's name

mConnectedDeviceName
= msg.getData().getString(DEVICE_NAME);

Toast.makeText(getApplicationContext(), "Connected to "

+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();

break;

case MESSAGE_TOAST:

Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),

Toast.LENGTH_SHORT).show();

break;

}

}

};



public void onActivityResult(int requestCode, int resultCode, Intent data) {

if(D) Log.d(TAG, "onActivityResult " + resultCode);

switch (requestCode) {

case REQUEST_CONNECT_DEVICE_SECURE:

// When DeviceListActivity returns with a device to connect

if (resultCode == Activity.RESULT_OK) {

connectDevice
(data, true);

}

break;

case REQUEST_CONNECT_DEVICE_INSECURE:

// When DeviceListActivity returns with a device to connect

if (resultCode == Activity.RESULT_OK) {

connectDevice
(data, false);

}

break;

case REQUEST_ENABLE_BT:

// When the request to enable Bluetooth returns

if (resultCode == Activity.RESULT_OK) {

// Bluetooth is now enabled, so set up a chat session

setupChat
();

} else {

// User did not enable Bluetooth or an error occurred

Log.d(TAG, "BT not enabled");

Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();

finish
();

}

}

}



private void connectDevice(Intent data, boolean secure) {

// Get the device MAC address

String address = data.getExtras()

.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);

// Get the BluetoothDevice object

BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

// Attempt to connect to the device

mChatService
.connect(device, secure);

}



@Override

public boolean onCreateOptionsMenu(Menu menu) {

MenuInflater inflater = getMenuInflater();

inflater
.inflate(R.menu.option_menu, menu);

return true;

}



@Override

public boolean onOptionsItemSelected(MenuItem item) {

Intent serverIntent = null;

switch (item.getItemId()) {

case R.id.secure_connect_scan:

// Launch the DeviceListActivity to see devices and do scan

serverIntent
= new Intent(this, DeviceListActivity.class);

startActivityForResult
(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);

return true;

case R.id.insecure_connect_scan:

// Launch the DeviceListActivity to see devices and do scan

serverIntent
= new Intent(this, DeviceListActivity.class);

startActivityForResult
(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);

return true;

case R.id.discoverable:

// Ensure this device is discoverable by others

ensureDiscoverable
();

return true;

}

return false;

}



}



BluetoothChatServices



/*

* Copyright (C) 2009 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/




package com.example.android.BluetoothChat;



import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.UUID;



import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.bluetooth.BluetoothServerSocket;

import android.bluetooth.BluetoothSocket;

import android.content.Context;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.util.Log;



/**

* This class does all the work for setting up and managing Bluetooth

* connections with other devices. It has a thread that listens for

* incoming connections, a thread for connecting with a device, and a

* thread for performing data transmissions when connected.

*/


public class BluetoothChatService {

// Debugging

private static final String TAG = "BluetoothChatService";

private static final boolean D = true;



// Name for the SDP record when creating server socket

private static final String NAME_SECURE = "BluetoothChatSecure";

private static final String NAME_INSECURE = "BluetoothChatInsecure";



// Unique UUID for this application

private static final UUID MY_UUID_SECURE =

UUID
.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");

private static final UUID MY_UUID_INSECURE =

UUID
.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");



// Member fields

private final BluetoothAdapter mAdapter;

private final Handler mHandler;

private AcceptThread mSecureAcceptThread;

private AcceptThread mInsecureAcceptThread;

private ConnectThread mConnectThread;

private ConnectedThread mConnectedThread;

private int mState;



// Constants that indicate the current connection state

public static final int STATE_NONE = 0; // we're doing nothing

public static final int STATE_LISTEN = 1; // now listening for incoming connections

public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection

public static final int STATE_CONNECTED = 3; // now connected to a remote device



/**

* Constructor. Prepares a new BluetoothChat session.

* @param context The UI Activity Context

* @param handler A Handler to send messages back to the UI Activity

*/


public BluetoothChatService(Context context, Handler handler) {

mAdapter
= BluetoothAdapter.getDefaultAdapter();

mState
= STATE_NONE;

mHandler
= handler;

}



/**

* Set the current state of the chat connection

* @param state An integer defining the current connection state

*/


private synchronized void setState(int state) {

if (D) Log.d(TAG, "setState() " + mState + " -> " + state);

mState
= state;



// Give the new state to the Handler so the UI Activity can update

mHandler
.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();

}



/**

* Return the current connection state. */


public synchronized int getState() {

return mState;

}



/**

* Start the chat service. Specifically start AcceptThread to begin a

* session in listening (server) mode. Called by the Activity onResume() */


public synchronized void start() {

if (D) Log.d(TAG, "start");



// Cancel any thread attempting to make a connection

if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}



// Cancel any thread currently running a connection

if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}



setState
(STATE_LISTEN);



// Start the thread to listen on a BluetoothServerSocket

if (mSecureAcceptThread == null) {

mSecureAcceptThread
= new AcceptThread(true);

mSecureAcceptThread
.start();

}

if (mInsecureAcceptThread == null) {

mInsecureAcceptThread
= new AcceptThread(false);

mInsecureAcceptThread
.start();

}

}



/**

* Start the ConnectThread to initiate a connection to a remote device.

* @param device The BluetoothDevice to connect

* @param secure Socket Security type - Secure (true) , Insecure (false)

*/


public synchronized void connect(BluetoothDevice device, boolean secure) {

if (D) Log.d(TAG, "connect to: " + device);



// Cancel any thread attempting to make a connection

if (mState == STATE_CONNECTING) {

if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

}



// Cancel any thread currently running a connection

if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}



// Start the thread to connect with the given device

mConnectThread
= new ConnectThread(device, secure);

mConnectThread
.start();

setState
(STATE_CONNECTING);

}



/**

* Start the ConnectedThread to begin managing a Bluetooth connection

* @param socket The BluetoothSocket on which the connection was made

* @param device The BluetoothDevice that has been connected

*/


public synchronized void connected(BluetoothSocket socket, BluetoothDevice

device
, final String socketType) {

if (D) Log.d(TAG, "connected, Socket Type:" + socketType);



// Cancel the thread that completed the connection

if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}



// Cancel any thread currently running a connection

if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}



// Cancel the accept thread because we only want to connect to one device

if (mSecureAcceptThread != null) {

mSecureAcceptThread
.cancel();

mSecureAcceptThread
= null;

}

if (mInsecureAcceptThread != null) {

mInsecureAcceptThread
.cancel();

mInsecureAcceptThread
= null;

}



// Start the thread to manage the connection and perform transmissions

mConnectedThread
= new ConnectedThread(socket, socketType);

mConnectedThread
.start();



// Send the name of the connected device back to the UI Activity

Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);

Bundle bundle = new Bundle();

bundle
.putString(BluetoothChat.DEVICE_NAME, device.getName());

msg
.setData(bundle);

mHandler
.sendMessage(msg);



setState
(STATE_CONNECTED);

}



/**

* Stop all threads

*/


public synchronized void stop() {

if (D) Log.d(TAG, "stop");



if (mConnectThread != null) {

mConnectThread
.cancel();

mConnectThread
= null;

}



if (mConnectedThread != null) {

mConnectedThread
.cancel();

mConnectedThread
= null;

}



if (mSecureAcceptThread != null) {

mSecureAcceptThread
.cancel();

mSecureAcceptThread
= null;

}



if (mInsecureAcceptThread != null) {

mInsecureAcceptThread
.cancel();

mInsecureAcceptThread
= null;

}

setState
(STATE_NONE);

}



/**

* Write to the ConnectedThread in an unsynchronized manner

* @param out The bytes to write

* @see ConnectedThread#write(byte[])

*/


public void write(byte[] out) {

// Create temporary object

ConnectedThread r;

// Synchronize a copy of the ConnectedThread

synchronized (this) {

if (mState != STATE_CONNECTED) return;

r
= mConnectedThread;

}

// Perform the write unsynchronized

r
.write(out);

}



/**

* Indicate that the connection attempt failed and notify the UI Activity.

*/


private void connectionFailed() {

// Send a failure message back to the Activity

Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);

Bundle bundle = new Bundle();

bundle
.putString(BluetoothChat.TOAST, "Unable to connect device");

msg
.setData(bundle);

mHandler
.sendMessage(msg);



// Start the service over to restart listening mode

BluetoothChatService.this.start();

}



/**

* Indicate that the connection was lost and notify the UI Activity.

*/


private void connectionLost() {

// Send a failure message back to the Activity

Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);

Bundle bundle = new Bundle();

bundle
.putString(BluetoothChat.TOAST, "Device connection was lost");

msg
.setData(bundle);

mHandler
.sendMessage(msg);



// Start the service over to restart listening mode

BluetoothChatService.this.start();

}



/**

* This thread runs while listening for incoming connections. It behaves

* like a server-side client. It runs until a connection is accepted

* (or until cancelled).

*/


private class AcceptThread extends Thread {

// The local server socket

private final BluetoothServerSocket mmServerSocket;

private String mSocketType;



public AcceptThread(boolean secure) {

BluetoothServerSocket tmp = null;

mSocketType
= secure ? "Secure":"Insecure";



// Create a new listening server socket

try {

if (secure) {

tmp
= mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,

MY_UUID_SECURE
);

} else {

tmp
= mAdapter.listenUsingInsecureRfcommWithServiceRecord(

NAME_INSECURE
, MY_UUID_INSECURE);

}

} catch (IOException e) {

Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);

}

mmServerSocket
= tmp;

}



public void run() {

if (D) Log.d(TAG, "Socket Type: " + mSocketType +

"BEGIN mAcceptThread" + this);

setName
("AcceptThread" + mSocketType);



BluetoothSocket socket = null;



// Listen to the server socket if we're not connected

while (mState != STATE_CONNECTED) {

try {

// This is a blocking call and will only return on a

// successful connection or an exception

socket
= mmServerSocket.accept();

} catch (IOException e) {

Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);

break;

}



// If a connection was accepted

if (socket != null) {

synchronized (BluetoothChatService.this) {

switch (mState) {

case STATE_LISTEN:

case STATE_CONNECTING:

// Situation normal. Start the connected thread.

connected
(socket, socket.getRemoteDevice(),

mSocketType
);

break;

case STATE_NONE:

case STATE_CONNECTED:

// Either not ready or already connected. Terminate new socket.

try {

socket
.close();

} catch (IOException e) {

Log.e(TAG, "Could not close unwanted socket", e);

}

break;

}

}

}

}

if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);



}



public void cancel() {

if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);

try {

mmServerSocket
.close();

} catch (IOException e) {

Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);

}

}

}





/**

* This thread runs while attempting to make an outgoing connection

* with a device. It runs straight through; the connection either

* succeeds or fails.

*/


private class ConnectThread extends Thread {

private final BluetoothSocket mmSocket;

private final BluetoothDevice mmDevice;

private String mSocketType;



public ConnectThread(BluetoothDevice device, boolean secure) {

mmDevice
= device;

BluetoothSocket tmp = null;

mSocketType
= secure ? "Secure" : "Insecure";



// Get a BluetoothSocket for a connection with the

// given BluetoothDevice

try {

if (secure) {

tmp
= device.createRfcommSocketToServiceRecord(

MY_UUID_SECURE
);

} else {

tmp
= device.createInsecureRfcommSocketToServiceRecord(

MY_UUID_INSECURE
);

}

} catch (IOException e) {

Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);

}

mmSocket
= tmp;

}



public void run() {

Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);

setName
("ConnectThread" + mSocketType);



// Always cancel discovery because it will slow down a connection

mAdapter
.cancelDiscovery();



// Make a connection to the BluetoothSocket

try {

// This is a blocking call and will only return on a

// successful connection or an exception

mmSocket
.connect();

} catch (IOException e) {

// Close the socket

try {

mmSocket
.close();

} catch (IOException e2) {

Log.e(TAG, "unable to close() " + mSocketType +

" socket during connection failure", e2);

}

connectionFailed
();

return;

}



// Reset the ConnectThread because we're done

synchronized (BluetoothChatService.this) {

mConnectThread
= null;

}



// Start the connected thread

connected
(mmSocket, mmDevice, mSocketType);

}



public void cancel() {

try {

mmSocket
.close();

} catch (IOException e) {

Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);

}

}

}



/**

* This thread runs during a connection with a remote device.

* It handles all incoming and outgoing transmissions.

*/


private class ConnectedThread extends Thread {

private final BluetoothSocket mmSocket;

private final InputStream mmInStream;

private final OutputStream mmOutStream;



public ConnectedThread(BluetoothSocket socket, String socketType) {

Log.d(TAG, "create ConnectedThread: " + socketType);

mmSocket
= socket;

InputStream tmpIn = null;

OutputStream tmpOut = null;



// Get the BluetoothSocket input and output streams

try {

tmpIn
= socket.getInputStream();

tmpOut
= socket.getOutputStream();

} catch (IOException e) {

Log.e(TAG, "temp sockets not created", e);

}



mmInStream
= tmpIn;

mmOutStream
= tmpOut;

}



public void run() {

Log.i(TAG, "BEGIN mConnectedThread");

byte[] buffer = new byte[1024];

int bytes;



// Keep listening to the InputStream while connected

while (true) {

try {

// Read from the InputStream

bytes
= mmInStream.read(buffer);



// Send the obtained bytes to the UI Activity

mHandler
.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)

.sendToTarget();

} catch (IOException e) {

Log.e(TAG, "disconnected", e);

connectionLost
();

// Start the service over to restart listening mode

BluetoothChatService.this.start();

break;

}

}

}



/**

* Write to the connected OutStream.

* @param buffer The bytes to write

*/


public void write(byte[] buffer) {

try {

mmOutStream
.write(buffer);



// Share the sent message back to the UI Activity

mHandler
.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)

.sendToTarget();

} catch (IOException e) {

Log.e(TAG, "Exception during write", e);

}

}



public void cancel() {

try {

mmSocket
.close();

} catch (IOException e) {

Log.e(TAG, "close() of connect socket failed", e);

}

}

}

}



Device List Activity



/*

* Copyright (C) 2009 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/




package com.example.android.BluetoothChat;



import java.util.Set;



import android.app.Activity;

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.view.Window;

import android.view.View.OnClickListener;

import android.widget.AdapterView;

import android.widget.ArrayAdapter;

import android.widget.Button;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.AdapterView.OnItemClickListener;



/**

* This Activity appears as a dialog. It lists any paired devices and

* devices detected in the area after discovery. When a device is chosen

* by the user, the MAC address of the device is sent back to the parent

* Activity in the result Intent.

*/


public class DeviceListActivity extends Activity {

// Debugging

private static final String TAG = "DeviceListActivity";

private static final boolean D = true;



// Return Intent extra

public static String EXTRA_DEVICE_ADDRESS = "device_address";



// Member fields

private BluetoothAdapter mBtAdapter;

private ArrayAdapter<String> mPairedDevicesArrayAdapter;

private ArrayAdapter<String> mNewDevicesArrayAdapter;



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);



// Setup the window

requestWindowFeature
(Window.FEATURE_INDETERMINATE_PROGRESS);

setContentView
(R.layout.device_list);



// Set result CANCELED in case the user backs out

setResult
(Activity.RESULT_CANCELED);



// Initialize the button to perform device discovery

Button scanButton = (Button) findViewById(R.id.button_scan);

scanButton
.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

doDiscovery
();

v
.setVisibility(View.GONE);

}

});



// Initialize array adapters. One for already paired devices and

// one for newly discovered devices

mPairedDevicesArrayAdapter
= new ArrayAdapter<String>(this, R.layout.device_name);

mNewDevicesArrayAdapter
= new ArrayAdapter<String>(this, R.layout.device_name);



// Find and set up the ListView for paired devices

ListView pairedListView = (ListView) findViewById(R.id.paired_devices);

pairedListView
.setAdapter(mPairedDevicesArrayAdapter);

pairedListView
.setOnItemClickListener(mDeviceClickListener);



// Find and set up the ListView for newly discovered devices

ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);

newDevicesListView
.setAdapter(mNewDevicesArrayAdapter);

newDevicesListView
.setOnItemClickListener(mDeviceClickListener);



// Register for broadcasts when a device is discovered

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

this.registerReceiver(mReceiver, filter);



// Register for broadcasts when discovery has finished

filter
= new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

this.registerReceiver(mReceiver, filter);



// Get the local Bluetooth adapter

mBtAdapter
= BluetoothAdapter.getDefaultAdapter();



// Get a set of currently paired devices

Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();



// If there are paired devices, add each one to the ArrayAdapter

if (pairedDevices.size() > 0) {

findViewById
(R.id.title_paired_devices).setVisibility(View.VISIBLE);

for (BluetoothDevice device : pairedDevices) {

mPairedDevicesArrayAdapter
.add(device.getName() + "\n" + device.getAddress());

}

} else {

String noDevices = getResources().getText(R.string.none_paired).toString();

mPairedDevicesArrayAdapter
.add(noDevices);

}

}



@Override

protected void onDestroy() {

super.onDestroy();



// Make sure we're not doing discovery anymore

if (mBtAdapter != null) {

mBtAdapter
.cancelDiscovery();

}



// Unregister broadcast listeners

this.unregisterReceiver(mReceiver);

}



/**

* Start device discover with the BluetoothAdapter

*/


private void doDiscovery() {

if (D) Log.d(TAG, "doDiscovery()");



// Indicate scanning in the title

setProgressBarIndeterminateVisibility
(true);

setTitle
(R.string.scanning);



// Turn on sub-title for new devices

findViewById
(R.id.title_new_devices).setVisibility(View.VISIBLE);



// If we're already discovering, stop it

if (mBtAdapter.isDiscovering()) {

mBtAdapter
.cancelDiscovery();

}



// Request discover from BluetoothAdapter

mBtAdapter
.startDiscovery();

}



// The on-click listener for all devices in the ListViews

private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {

public void onItemClick(AdapterView av, View v, int arg2, long arg3) {

// Cancel discovery because it's costly and we're about to connect

mBtAdapter
.cancelDiscovery();



// Get the device MAC address, which is the last 17 chars in the View

String info = ((TextView) v).getText().toString();

String address = info.substring(info.length() - 17);



// Create the result Intent and include the MAC address

Intent intent = new Intent();

intent
.putExtra(EXTRA_DEVICE_ADDRESS, address);



// Set result and finish this Activity

setResult
(Activity.RESULT_OK, intent);

finish
();

}

};



// The BroadcastReceiver that listens for discovered devices and

// changes the title when discovery is finished

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();



// When discovery finds a device

if (BluetoothDevice.ACTION_FOUND.equals(action)) {

// Get the BluetoothDevice object from the Intent

BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

// If it's already paired, skip it, because it's been listed already

if (device.getBondState() != BluetoothDevice.BOND_BONDED) {

mNewDevicesArrayAdapter
.add(device.getName() + "\n" + device.getAddress());

}

// When discovery is finished, change the Activity title

} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {

setProgressBarIndeterminateVisibility
(false);

setTitle
(R.string.select_device);

if (mNewDevicesArrayAdapter.getCount() == 0) {

String noDevices = getResources().getText(R.string.none_found).toString();

mNewDevicesArrayAdapter
.add(noDevices);

}

}

}

};



}