android.Manifest.permission.BLUETOOTH_ADMIN;
static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private static final int ADAPTER_SERVICE_TYPE=Service.START_STICKY;
+
+ static {
+ classInitNative();
+ }
+
+ private static AdapterService sAdapterService;
+ public static AdapterService getAdapterService(){
+ return sAdapterService;
+ }
+
private IBluetoothManager mBluetoothManager;
private IBluetooth mBluetoothService;
private AdapterProperties mAdapterProperties;
private int mAdapterState;
private Context mContext;
- private static AdapterService sAdapterService;
private AdapterState mAdapterStateMachine;
private BondStateMachine mBondStateMachine;
private JniCallbacks mJniCallbacks;
private RemoteDevices mRemoteDevices;
- private boolean mStopPending;
- private boolean mStartPending;
private boolean mProfilesStarted;
private boolean mNativeAvailable;
private HashMap<String,Integer> mProfileServicesState = new HashMap<String,Integer>();
-
- //In case Bluetooth app crashes, we need to reinit JNI
- private static boolean mIsJniInited;
- private static synchronized void initJni() {
- if (!mIsJniInited) {
- if (DBG) Log.d(TAG,"Initializing JNI Library");
- System.loadLibrary("bluetooth_jni");
- classInitNative();
- mIsJniInited=true;
- }
- }
-
- public static AdapterService getAdapterService(){
- return sAdapterService;
- }
+ private int mCurrentRequestId;
public void onProfileConnectionStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
Message m = mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED);
}
private void processProfileServiceStateChanged(String serviceName, int state) {
- if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state);
boolean doUpdate=false;
+ boolean isTurningOn;
+ boolean isTurningOff;
+
synchronized (mProfileServicesState) {
Integer prevState = mProfileServicesState.get(serviceName);
if (prevState != null && prevState != state) {
doUpdate=true;
}
}
+ if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state +", doUpdate = " + doUpdate);
+
if (!doUpdate) {
return;
}
- if (mStopPending) {
+
+ synchronized (mAdapterStateMachine) {
+ isTurningOff = mAdapterStateMachine.isTurningOff();
+ isTurningOn = mAdapterStateMachine.isTurningOn();
+ }
+
+ if (isTurningOff) {
//Process stop or disable pending
//Check if all services are stopped if so, do cleanup
//if (DBG) Log.d(TAG,"Checking if all profiles are stopped...");
while (i.hasNext()) {
Map.Entry<String,Integer> entry = i.next();
if (BluetoothAdapter.STATE_OFF != entry.getValue()) {
- //Log.d(TAG, "Profile still running: " entry.getKey());
+ Log.d(TAG, "Profile still running: " + entry.getKey());
return;
}
}
}
if (DBG) Log.d(TAG, "All profile services stopped...");
- processStopped();
- } else if (mStartPending) {
+ onProfilesStopped();
+ } else if (isTurningOn) {
//Process start pending
//Check if all services are started if so, update state
//if (DBG) Log.d(TAG,"Checking if all profiles are running...");
while (i.hasNext()) {
Map.Entry<String,Integer> entry = i.next();
if (BluetoothAdapter.STATE_ON != entry.getValue()) {
- //Log.d(TAG, "Profile still not running:" + entry.getKey());
+ Log.d(TAG, "Profile still not running:" + entry.getKey());
return;
}
}
}
if (DBG) Log.d(TAG, "All profile services started.");
- processStarted();
+ onProfilesStarted();
}
}
@Override
public void onCreate() {
super.onCreate();
- if (DBG) Log.d(TAG, "onCreate");
+ if (DBG) debugLog("onCreate");
mContext = this;
sAdapterService = this;
- initJni(); //We always check and init JNI in case we crashed and restarted
- mRemoteDevices = RemoteDevices.getInstance(this, mContext);
- mRemoteDevices.init();
- mAdapterProperties = AdapterProperties.getInstance(this, mContext);
- mAdapterProperties.init();
+ mAdapterProperties = new AdapterProperties(this, mContext);
mAdapterStateMachine = new AdapterState(this, mContext, mAdapterProperties);
- mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties);
- mJniCallbacks = JniCallbacks.getInstance(mRemoteDevices, mAdapterProperties,
- mAdapterStateMachine, mBondStateMachine);
+ mJniCallbacks = JniCallbacks.getInstance(null, mAdapterProperties,mAdapterStateMachine,null);
initNative();
mNativeAvailable=true;
+ mAdapterStateMachine.start();
//Load the name and address
getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR);
@Override
public IBinder onBind(Intent intent) {
- if (DBG) Log.d(TAG, "onBind");
+ if (DBG) debugLog("onBind");
return mBinder;
}
public boolean onUnbind(Intent intent) {
- if (DBG) Log.d(TAG,"onUnbind");
+ if (DBG) debugLog("onUnbind");
return super.onUnbind(intent);
}
public void onDestroy() {
- if (DBG) Log.d(TAG, "onDestroy()");
- super.onDestroy();
+ debugLog("****onDestroy()********");
+ mHandler.removeMessages(MESSAGE_SHUTDOWN);
+ cleanup();
}
public int onStartCommand(Intent intent ,int flags, int startId) {
- if (DBG) Log.d(TAG, "onStartCommand");
+
+ mCurrentRequestId = startId;
+ if (DBG) debugLog("onStartCommand: flags = " + flags + ", startId = " + startId);
if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "Permission denied!");
- return START_STICKY;
+ return ADAPTER_SERVICE_TYPE;
+ }
+
+ //Check if we are restarting
+ if (intent == null) {
+ debugLog("Restarting AdapterService");
+ return ADAPTER_SERVICE_TYPE;
}
+ //Get action and check if valid. If invalid, ignore and return
String action = intent.getStringExtra(EXTRA_ACTION);
- if (DBG) Log.d(TAG,"onStartCommand(): action = " + action);
- if (ACTION_SERVICE_STATE_CHANGED.equals(action)) {
- int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.ERROR);
- if (DBG) Log.d(TAG,"onStartCommand(): state = " + Utils.debugGetAdapterStateString(state));
- if (state == BluetoothAdapter.STATE_OFF) {
- Message m = mHandler.obtainMessage(MESSAGE_STOP);
- mHandler.sendMessage(m);
- } else if (state == BluetoothAdapter.STATE_ON) {
- Message m = mHandler.obtainMessage(MESSAGE_START);
- mHandler.sendMessage(m);
- }
+ debugLog("onStartCommand(): action = " + action);
+ if (!ACTION_SERVICE_STATE_CHANGED.equals(action)) {
+ Log.w(TAG,"Unknown action: " + action);
+ return ADAPTER_SERVICE_TYPE;
}
- return START_STICKY;
- }
- final private IBluetoothManagerCallback mManagerCallback =
- new IBluetoothManagerCallback.Stub() {
- public void onBluetoothServiceUp(IBluetooth bluetoothService) {
- if (DBG) Log.d(TAG, "onBluetoothServiceUp");
- synchronized (mManagerCallback) {
- mBluetoothService = bluetoothService;
- }
- }
+ //Check state of request. If invalid, ignore and return
+ int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.ERROR);
+ debugLog("onStartCommand(): state = " + Utils.debugGetAdapterStateString(state));
- public void onBluetoothServiceDown() {
- if (DBG) Log.d(TAG, "onBluetoothServiceDown");
- synchronized (mManagerCallback) {
- mBluetoothService = null;
- }
- }
- };
+ //Cancel any pending shutdown requests
+ synchronized (mHandler) {
+ mHandler.removeMessages(MESSAGE_SHUTDOWN);
+ }
- private void processStart() {
- if (DBG) Log.d(TAG,"start() called, mStartPending= " + mStartPending + ", mProfilesStarted=" + mProfilesStarted);
- if (mProfilesStarted || mStartPending) return;
- if (DBG) Log.d(TAG,"starting bluetooth state machine and profiles..");
+ if (state == BluetoothAdapter.STATE_OFF) {
+ Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
+ m.arg1= startId;
+ mAdapterStateMachine.sendMessage(m);
+ } else if (state == BluetoothAdapter.STATE_ON) {
+ Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
+ m.arg1= startId;
+ mAdapterStateMachine.sendMessage(m);
+ } else {
+ Log.w(TAG,"Invalid state: " + action);
+ return ADAPTER_SERVICE_TYPE;
+ }
+ return ADAPTER_SERVICE_TYPE;
+ }
- mStartPending=true;
+ void processStart() {
+ if (DBG) debugLog("processStart()");
- mAdapterStateMachine.start();
- mBondStateMachine.start();
+ //Initialize data objects
+ for (int i=0; i < SUPPORTED_PROFILE_SERVICES.length;i++) {
+ mProfileServicesState.put(SUPPORTED_PROFILE_SERVICES[i].getName(),BluetoothAdapter.STATE_OFF);
+ }
+
+ mRemoteDevices = new RemoteDevices(this, mContext);
+ mRemoteDevices.init();
+ mAdapterProperties.init(mRemoteDevices);
+ mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties, mRemoteDevices);
+ mJniCallbacks.init(mRemoteDevices, mAdapterProperties,mAdapterStateMachine,mBondStateMachine);
- //Get bluetooth service for profiles
+ //Init BluetoothManager
+ if (DBG) {debugLog("processStart(): Initializing Bluetooth Manager");}
IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
mBluetoothManager = IBluetoothManager.Stub.asInterface(b);
if (mBluetoothManager != null) {
try {
+ Log.d(TAG, "FRED: Registering manager callback " + mManagerCallback);
mBluetoothService = mBluetoothManager.registerAdapter(mManagerCallback);
} catch (RemoteException re) {
Log.e(TAG, "",re);
}
}
+ //Start Bond State Machine
+ if (DBG) {debugLog("processStart(): Starting Bond State Machine");}
+ mBondStateMachine.start();
+
//Start profile services
if (SUPPORTED_PROFILE_SERVICES.length==0 || mProfilesStarted) {
//Skip starting profiles and go to next step
- processStarted();
+ if (DBG) {debugLog("processStart(): Profile Services started");}
+ Message m = mAdapterStateMachine.obtainMessage(AdapterState.STARTED);
+ mAdapterStateMachine.sendMessage(m);
} else {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_START_TIMEOUT), MAX_TIMEOUT_MS);
- for (int i=0; i <SUPPORTED_PROFILE_SERVICES.length;i++) {
- startProfileService(SUPPORTED_PROFILE_SERVICES[i]);
- }
+ //Startup all profile services
+ setProfileServiceState(SUPPORTED_PROFILE_SERVICES,BluetoothAdapter.STATE_ON);
}
}
- private void processStartTimeout(){
- //FIXME:
- Log.e(TAG,"************Start Timed out!!!*******************");
- mStartPending = false;
- sendIntent(BluetoothAdapter.STATE_OFF);
- //Stop
- }
-
- private void processStarted() {
- Log.d(TAG, "processStarted()");
- mHandler.removeMessages(MESSAGE_START_TIMEOUT);
- mProfilesStarted = true;
- //Enable bluetooth
- Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
+ void startBluetoothDisable() {
+ Log.d(TAG,"startBluetoothDisable()");
+ Message m = mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE);
mAdapterStateMachine.sendMessage(m);
}
- void onBluetoothEnableTimeout() {
- Log.e(TAG, "Timeout occurred while enabling bluetooth...");
- sendIntent(BluetoothAdapter.STATE_OFF);
- //FIXME: stop services and cleanup
- }
-
- void onBluetoothEnabled() {
- Log.d(TAG, "onBluetoothEnabled()");
- Message m = mHandler.obtainMessage(MESSAGE_ENABLED);
- mHandler.sendMessage(m);
+ void onProfilesStarted(){
+ Log.d(TAG,"onProfilesStarted()");
+ mProfilesStarted=true;
+ Message m = mAdapterStateMachine.obtainMessage(AdapterState.STARTED);
+ mAdapterStateMachine.sendMessage(m);
}
- void processEnabled() {
- mStartPending = false;
- mStopPending=false;
- sendIntent(BluetoothAdapter.STATE_ON);
+ void onProfilesStopped() {
+ Log.d(TAG,"onProfilesStopped()");
+ mProfilesStarted=false;
+ //Message m = mAdapterStateMachine.obtainMessage(AdapterState.DISABLE);
+ Message m = mAdapterStateMachine.obtainMessage(AdapterState.STOPPED);
+ mAdapterStateMachine.sendMessage(m);
}
- //Called as part of disable or independently (when just getting address)
- private void processStop() {
- if (DBG) Log.d(TAG,"stop() called, mStopPending= " + mStopPending + ", mProfilesStarted=" + mProfilesStarted);
- if (mStopPending) return;
- mStopPending=true;
+ boolean stopProfileServices() {
if (SUPPORTED_PROFILE_SERVICES.length==0 || !mProfilesStarted) {
- cleanup();
- } else {
- Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
- mAdapterStateMachine.sendMessage(m);
+ if (DBG) {debugLog("processDisable(): No profiles services to stop or already stopped.");}
+ return false;
}
+ setProfileServiceState(SUPPORTED_PROFILE_SERVICES,BluetoothAdapter.STATE_OFF);
+ return true;
}
- void onBluetoothDisabled() {
- Log.d(TAG, "onBluetoothDisabled()");
- Message m = mHandler.obtainMessage(MESSAGE_DISABLED);
- mHandler.sendMessage(m);
- }
-
- void onBluetoothDisableTimeout() {
- Log.e(TAG, "Timeout occurred while disable bluetooth...");
- Message m = mHandler.obtainMessage(MESSAGE_DISABLED);
- mHandler.sendMessage(m);
- }
-
- private void processDisabled() {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_STOP_TIMEOUT), MAX_TIMEOUT_MS);
- for (int i=SUPPORTED_PROFILE_SERVICES.length-1; i >=0;i--) {
- stopProfileService(SUPPORTED_PROFILE_SERVICES[i]);
- }
- }
-
- private void processStopTimeout() {
- //FIXME:
- Log.e(TAG,"************Stop Timed out!!!*******************");
- processStopped();
- }
-
- private void processStopped() {
+ void processStopped() {
Log.d(TAG, "processStopped()");
- mHandler.removeMessages(MESSAGE_STOP_TIMEOUT);
if (mBluetoothManager != null) {
try {
+ Log.d(TAG,"FRED: Unregistering manager callback " + mManagerCallback);
mBluetoothManager.unregisterAdapter(mManagerCallback);
} catch (RemoteException re) {
Log.e(TAG, "",re);
}
}
mBondStateMachine.quit();
- mAdapterStateMachine.quit();
- sendIntent(BluetoothAdapter.STATE_OFF);
- cleanup();
+ mBondStateMachine.cleanup();
+ mBondStateMachine = null;
}
- void cleanup () {
- if (DBG) Log.d(TAG, "cleanup()");
-
- if (mBondStateMachine != null) {
- mBondStateMachine.cleanup();
- mBondStateMachine = null;
+ void startShutdown(int requestId) {
+ debugLog("startShutdown(): requestId = " + requestId + ", currentRequestId=" + mCurrentRequestId);
+ if (requestId <0) {
+ Log.w(TAG, "Ignoring shutdown request. Invalid requestId");
+ return;
}
- if (mAdapterStateMachine != null) {
- mAdapterStateMachine.cleanup();
- mAdapterStateMachine = null;
+
+ Message m = mHandler.obtainMessage(MESSAGE_SHUTDOWN);
+ synchronized(mHandler) {
+ mHandler.sendMessageDelayed(m, SHUTDOWN_TIMEOUT);
}
+ stopSelfResult(requestId);
+ }
+
+ void cleanup () {
+ if (DBG)debugLog("cleanup()");
+
if (mNativeAvailable) {
Log.d(TAG, "Cleaning up adapter native....");
cleanupNative();
Log.d(TAG, "Done cleaning up adapter native....");
mNativeAvailable=false;
}
- mStartPending = false;
- mStopPending=false;
- mProfilesStarted = false;
- stopSelf();
- }
- private void sendIntent(int newState) {
- int oldState = mAdapterProperties.getState();
- Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, oldState);
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mAdapterProperties.setState(newState);
- mContext.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
- //infoLog("Bluetooth State Change Intent: " + oldState + " -> " + newState);
+ if (mAdapterStateMachine != null) {
+ mAdapterStateMachine.quit();
+ mAdapterStateMachine.cleanup();
+ mAdapterStateMachine = null;
+ }
+
+ if (mRemoteDevices != null) {
+ mRemoteDevices.cleanup();
+ mRemoteDevices = null;
+ }
+
+ if (mAdapterProperties != null) {
+ mAdapterProperties.cleanup();
+ mAdapterProperties = null;
+ }
+
+ mProfileServicesState.clear();
+ if (DBG)debugLog("cleanup() done");
}
+ final private IBluetoothManagerCallback mManagerCallback =
+ new IBluetoothManagerCallback.Stub() {
+ public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+ if (DBG) Log.d(TAG, "onBluetoothServiceUp");
+ synchronized (mManagerCallback) {
+ mBluetoothService = bluetoothService;
+ }
+ }
+
+ public void onBluetoothServiceDown() {
+ if (DBG) Log.d(TAG, "onBluetoothServiceDown " + this);
+ synchronized (mManagerCallback) {
+ mBluetoothService = null;
+ }
+ }
+ };
+
private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1;
- private static final int MESSAGE_START=2;
- private static final int MESSAGE_STOP=3;
- private static final int MESSAGE_ENABLED=4;
- private static final int MESSAGE_DISABLED=5;
- private static final int MESSAGE_START_TIMEOUT=10;
- private static final int MESSAGE_STOP_TIMEOUT=11;
private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20;
- private static final int MAX_TIMEOUT_MS=3000;
+ private static final int MESSAGE_SHUTDOWN= 100;
+ private static final int SHUTDOWN_TIMEOUT=2000;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- if (DBG) Log.d (TAG, "Message: " + msg.what);
+ if (DBG) debugLog("Message: " + msg.what);
switch (msg.what) {
- case MESSAGE_START: {
- processStart();
- }
- break;
- case MESSAGE_START_TIMEOUT: {
- processStartTimeout();
- }
- break;
- case MESSAGE_ENABLED: {
- processEnabled();
- }
- break;
- case MESSAGE_STOP: {
- processStop();
- }
- break;
- case MESSAGE_STOP_TIMEOUT: {
- processStopTimeout();
- }
- break;
- case MESSAGE_DISABLED: {
- processDisabled();
+ case MESSAGE_SHUTDOWN: {
+ if (DBG) Log.d(TAG,"***SHUTDOWN: TIMEOUT!!! Forcing shutdown...");
+ stopSelf();
}
break;
case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {
- Log.d(TAG, "MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
+ if(DBG) debugLog("MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
processProfileServiceStateChanged((String) msg.obj, msg.arg1);
}
break;
case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: {
- Log.d(TAG, "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED");
+ if (DBG) debugLog( "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED");
processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR));
}
break;
};
@SuppressWarnings("rawtypes")
- private void startProfileService(Class service) {
- String serviceName = service.getName();
- Integer serviceState = mProfileServicesState.get(serviceName);
- if(serviceState != null && serviceState != BluetoothAdapter.STATE_OFF) {
- Log.w(TAG, "Unable to start service "+serviceName+". Invalid state: " + serviceState);
+ private void setProfileServiceState(Class[] services, int state) {
+ if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
+ Log.w(TAG,"setProfileServiceState(): invalid state...Leaving...");
return;
}
- mProfileServicesState.put(serviceName,BluetoothAdapter.STATE_TURNING_ON);
- Intent i = new Intent(this,service);
- //i.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
- //i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
- if (DBG) Log.d(TAG, "Starting profile service "+serviceName);
- startService(i);
- }
+ int expectedCurrentState= BluetoothAdapter.STATE_OFF;
+ int pendingState = BluetoothAdapter.STATE_TURNING_ON;
+ if (state == BluetoothAdapter.STATE_OFF) {
+ expectedCurrentState= BluetoothAdapter.STATE_ON;
+ pendingState = BluetoothAdapter.STATE_TURNING_OFF;
+ }
- @SuppressWarnings("rawtypes")
- private void stopProfileService(Class service) {
- String serviceName = service.getName();
- Integer serviceState = mProfileServicesState.get(service.getName());
- if(serviceState == null || serviceState != BluetoothAdapter.STATE_ON) {
- Log.w(TAG, "Unable to stop service " + serviceName + ". Invalid state: " + serviceState);
- return;
+ for (int i=0; i <services.length;i++) {
+ String serviceName = services[i].getName();
+ Integer serviceState = mProfileServicesState.get(serviceName);
+ if(serviceState != null && serviceState != expectedCurrentState) {
+ Log.w(TAG, "Unable to " + (state == BluetoothAdapter.STATE_OFF? "start" : "stop" ) +" service " +
+ serviceName+". Invalid state: " + serviceState);
+ continue;
+ }
+
+ if (DBG) {
+ Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " +
+ serviceName);
+ }
+
+ mProfileServicesState.put(serviceName,pendingState);
+ Intent intent = new Intent(this,services[i]);
+ intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
+ intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);
+ startService(intent);
}
- mProfileServicesState.put(serviceName, BluetoothAdapter.STATE_TURNING_OFF);
- Intent i = new Intent(this, service);
- i.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
- i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
- if (DBG) Log.d(TAG, "Stopping profile service "+serviceName);
- startService(i);
}
/**
public int getState() {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
return mAdapterProperties.getState();
}
public boolean enable() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
- Log.d(TAG,"enable() called...");
+ if (DBG) debugLog("enable() called...");
Message m =
mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
m.arg1 = 1; //persist state
public boolean disable(boolean persist) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
- Log.d(TAG,"disable() called...");
+ if (DBG) debugLog("disable() called...");
int val = (persist ? 1 : 0);
Message m =
mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
public String getName() {
enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
- return mAdapterProperties.getName();
+ try {
+ return mAdapterProperties.getName();
+ } catch (Throwable t) {
+ Log.d(TAG, "Unexpected exception while calling getName()",t);
+ }
+ return null;
}
public boolean setName(String name) {
return -1;
}
- private static void debugLog(String msg) {
- Log.d(TAG, msg);
+ private void debugLog(String msg) {
+ Log.d(TAG +"(" +hashCode()+")", msg);
}
- private static void errorLog(String msg) {
- Log.e(TAG, msg);
+ private void errorLog(String msg) {
+ Log.e(TAG +"(" +hashCode()+")", msg);
}
private native static void classInitNative();
private static final String TAG = "BluetoothAdapterState";
static final int USER_TURN_ON = 1;
- static final int USER_TURN_OFF = 2;
- static final int AIRPLANE_MODE_ON = 3;
- static final int AIRPLANE_MODE_OFF = 4;
- static final int ENABLED_READY = 5;
- static final int DISABLED = 6;
- static final int ENABLE_TIMEOUT = 7;
+ static final int STARTED=2;
+ static final int ENABLED_READY = 3;
+ // static final int POST_ENABLE =4;
- private static final int ENABLE_TIMEOUT_DELAY = 6000; // 6 secs
+ static final int USER_TURN_OFF = 20;
+ static final int BEGIN_DISABLE = 21;
+ static final int ALL_DEVICES_DISCONNECTED = 22;
+ // static final int DISABLE=23;
+ static final int DISABLED = 24;
+ static final int STOPPED=25;
+ static final int START_TIMEOUT = 100;
+ static final int ENABLE_TIMEOUT = 101;
+ static final int DISABLE_TIMEOUT = 103;
+ static final int STOP_TIMEOUT = 104;
+
+ static final int USER_TURN_OFF_DELAY_MS=500;
+
+ //TODO: tune me
+ private static final int ENABLE_TIMEOUT_DELAY = 8000;
+ private static final int DISABLE_TIMEOUT_DELAY = 8000;
+ private static final int START_TIMEOUT_DELAY = 5000;
+ private static final int STOP_TIMEOUT_DELAY = 5000;
+ private static final int PROPERTY_OP_DELAY =2000;
private AdapterService mAdapterService;
private Context mContext;
private AdapterProperties mAdapterProperties;
- private boolean mPendingPersistEnable;
private PendingCommandState mPendingCommandState = new PendingCommandState();
private OnState mOnState = new OnState();
private OffState mOffState = new OffState();
- public boolean isCurrentlyOn() {
- return mOnState == getCurrentState();
+ public boolean isTurningOn() {
+ boolean isTurningOn= mPendingCommandState.isTurningOn();
+ Log.d(TAG,"isTurningOn()=" + isTurningOn);
+ return isTurningOn;
}
+
+ public boolean isTurningOff() {
+ boolean isTurningOff= mPendingCommandState.isTurningOff();
+ Log.d(TAG,"isTurningOff()=" + isTurningOff);
+ return isTurningOff;
+ }
+
public AdapterState(AdapterService service, Context context,
AdapterProperties adapterProperties) {
super("BluetoothAdapterState:");
private class OffState extends State {
@Override
public void enter() {
- infoLog("Entering Off State");
+ infoLog("Entering OffState");
}
@Override
Log.d(TAG, "Received quit request...");
return false;
}
+ int requestId = msg.arg1;
switch(msg.what) {
case USER_TURN_ON:
- int persist = msg.arg1;
- //if (persist == 1) mAdapterService.persistBluetoothSetting(true);
- //Persist enable state only once enable completes
- mPendingPersistEnable = (persist ==1);
+ if (DBG) Log.d(TAG,"CURRENT_STATE=OFF, MESSAGE = USER_TURN_ON, requestId= " + msg.arg1);
sendIntent(BluetoothAdapter.STATE_TURNING_ON);
- boolean ret = mAdapterService.enableNative();
- if (!ret) {
- Log.e(TAG, "Error while turning Bluetooth On");
- sendIntent(BluetoothAdapter.STATE_OFF);
- } else {
- sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);
- transitionTo(mPendingCommandState);
- }
+ mPendingCommandState.setTurningOn(true);
+ transitionTo(mPendingCommandState);
+ sendMessageDelayed(START_TIMEOUT, START_TIMEOUT_DELAY);
+ mAdapterService.processStart();
break;
case USER_TURN_OFF:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=OFF, MESSAGE = USER_TURN_OFF, requestId= " + msg.arg1);
+ //Handle case of service started and stopped without enable
+ mAdapterService.startShutdown(requestId);
break;
default:
- Log.e(TAG, "Received unhandled state: " + msg.what);
+ if (DBG) Log.d(TAG,"ERROR: UNEXPECTED MESSAGE: CURRENT_STATE=OFF, MESSAGE = " + msg.what );
return false;
}
return true;
public boolean processMessage(Message msg) {
switch(msg.what) {
case USER_TURN_OFF:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=ON, MESSAGE = USER_TURN_OFF, requestId= " + msg.arg1);
sendIntent(BluetoothAdapter.STATE_TURNING_OFF);
+ mPendingCommandState.setTurningOff(true);
+ mPendingCommandState.setOffRequestId(msg.arg1);
+ transitionTo(mPendingCommandState);
+
// Invoke onBluetoothDisable which shall trigger a
// setScanMode to SCAN_MODE_NONE
+ Message m = obtainMessage(BEGIN_DISABLE);
+ m.arg1 = msg.arg1;
+ sendMessageDelayed(m, PROPERTY_OP_DELAY);
mAdapterProperties.onBluetoothDisable();
-
- // stack takes care of disconnecting profiles, send disable here
- boolean ret = mAdapterService.disableNative();
- if (!ret) {
- Log.e(TAG, "Error while turning Bluetooth Off");
- sendIntent(BluetoothAdapter.STATE_ON);
- } else {
- transitionTo(mPendingCommandState);
- }
break;
+
case USER_TURN_ON:
- //case AIRPLANE_MODE_OFF:
- //ignore
+ if (DBG) Log.d(TAG,"CURRENT_STATE=ON, MESSAGE = USER_TURN_ON, requestId= " + msg.arg1);
+ Log.i(TAG,"Bluetooth already ON, ignoring USER_TURN_ON");
break;
default:
- Log.e(TAG, "Received unhandled state: " + msg.what);
+ if (DBG) Log.d(TAG,"ERROR: UNEXPECTED MESSAGE: CURRENT_STATE=ON, MESSAGE = " + msg.what );
return false;
}
return true;
}
private class PendingCommandState extends State {
- @Override
+ private boolean mIsTurningOn;
+ private boolean mIsTurningOff;
+
+ private int mRequestId;
+
public void enter() {
- infoLog("Entering PendingCommandState State");
+ infoLog("Entering PendingCommandState State: isTurningOn()=" + isTurningOn() + ", isTurningOff()=" + isTurningOff());
+ }
+
+ public void setTurningOn(boolean isTurningOn) {
+ mIsTurningOn = isTurningOn;
+ }
+
+ public boolean isTurningOn() {
+ return mIsTurningOn;
+ }
+
+ public void setTurningOff(boolean isTurningOff) {
+ mIsTurningOff = isTurningOff;
+ }
+
+ public boolean isTurningOff() {
+ return mIsTurningOff;
+ }
+
+ public void setOffRequestId(int requestId) {
+ mRequestId = requestId;
+ }
+
+ public int getOffRequestId() {
+ return mRequestId;
}
@Override
public boolean processMessage(Message msg) {
+ boolean isTurningOn= isTurningOn();
+ boolean isTurningOff = isTurningOff();
switch (msg.what) {
case USER_TURN_ON:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = USER_TURN_ON, requestId= " + msg.arg1
+ + ", isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ if (isTurningOn) {
+ Log.i(TAG,"CURRENT_STATE=PENDING: Alreadying turning on bluetooth... Ignoring USER_TURN_ON...");
+ } else {
+ Log.i(TAG,"CURRENT_STATE=PENDING: Deferring request USER_TURN_ON");
+ deferMessage(msg);
+ }
+ break;
case USER_TURN_OFF:
- case AIRPLANE_MODE_ON:
- case AIRPLANE_MODE_OFF:
- deferMessage(msg);
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = USER_TURN_ON, requestId= " + msg.arg1
+ + ", isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ if (isTurningOff) {
+ Log.i(TAG,"CURRENT_STATE=PENDING: Alreadying turning off bluetooth... Ignoring USER_TURN_OFF...");
+ } else {
+ Log.i(TAG,"CURRENT_STATE=PENDING: Deferring request USER_TURN_OFF");
+ deferMessage(msg);
+ }
break;
+ case STARTED: {
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = STARTED, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ //Remove start timeout
+ removeMessages(START_TIMEOUT);
+
+ //Enable
+ boolean ret = mAdapterService.enableNative();
+ if (!ret) {
+ Log.e(TAG, "Error while turning Bluetooth On");
+ sendIntent(BluetoothAdapter.STATE_OFF);
+ transitionTo(mOffState);
+ } else {
+ sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);
+ }
+ }
+ break;
+
case ENABLED_READY:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = ENABLE_READY, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
removeMessages(ENABLE_TIMEOUT);
- transitionTo(mOnState);
mAdapterProperties.onBluetoothReady();
- mAdapterService.onBluetoothEnabled();
+ mPendingCommandState.setTurningOn(false);
+ transitionTo(mOnState);
+ sendIntent(BluetoothAdapter.STATE_ON);
+ break;
+
+ case BEGIN_DISABLE: {
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = BEGIN_DISABLE" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ removeMessages(BEGIN_DISABLE); //Remove extra message we setup in USER_TURN_OFF
+ //Log.d(TAG,"CURRENT_STATE=ON, MESSAGE = BEGIN_DISABLE_ON, requestId= " + msg.arg1);
+ sendMessageDelayed(DISABLE_TIMEOUT, DISABLE_TIMEOUT_DELAY);
+ boolean ret = mAdapterService.disableNative();
+ if (!ret) {
+ removeMessages(DISABLE_TIMEOUT);
+ Log.e(TAG, "Error while turning Bluetooth Off");
+ //FIXME: what about post enable services
+ mPendingCommandState.setTurningOff(false);
+ mPendingCommandState.setOffRequestId(-1);
+ sendIntent(BluetoothAdapter.STATE_ON);
+ }
+ }
break;
case DISABLED:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = DISABLED, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ removeMessages(DISABLE_TIMEOUT);
+ sendMessageDelayed(STOP_TIMEOUT, STOP_TIMEOUT_DELAY);
+ if (mAdapterService.stopProfileServices()) {
+ Log.d(TAG,"Stopping profile services that were post enabled");
+ break;
+ }
+ //Fall through if no post-enabled services or services already stopped
+ case STOPPED:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = STOPPED, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ removeMessages(STOP_TIMEOUT);
+ setTurningOff(false);
+ int requestId= getOffRequestId();
+ setOffRequestId(-1);
+ transitionTo(mOffState);
+ sendIntent(BluetoothAdapter.STATE_OFF);
+ mAdapterService.processStopped();
+ mAdapterService.startShutdown(requestId);
+ break;
+ case START_TIMEOUT:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = START_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ errorLog("Error enabling Bluetooth");
+ mPendingCommandState.setTurningOn(false);
transitionTo(mOffState);
- mAdapterService.onBluetoothDisabled();
+ sendIntent(BluetoothAdapter.STATE_OFF);
break;
case ENABLE_TIMEOUT:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = ENABLE_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
errorLog("Error enabling Bluetooth");
+ mPendingCommandState.setTurningOn(false);
transitionTo(mOffState);
- mAdapterService.onBluetoothEnableTimeout();
+ sendIntent(BluetoothAdapter.STATE_OFF);
+ break;
+ case STOP_TIMEOUT:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = STOP_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ errorLog("Error stopping Bluetooth profiles");
+ mPendingCommandState.setTurningOff(false);
+ transitionTo(mOffState);
+ break;
+ case DISABLE_TIMEOUT:
+ if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = DISABLE_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
+ errorLog("Error disabling Bluetooth");
+ mPendingCommandState.setTurningOff(false);
+ transitionTo(mOnState);
break;
default:
- Log.e(TAG, "Received unhandled event:" + msg.what);
+ if (DBG) Log.d(TAG,"ERROR: UNEXPECTED MESSAGE: CURRENT_STATE=PENDING, MESSAGE = " + msg.what );
return false;
}
return true;