• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 package android.bluetooth;
17 
18 import android.content.BroadcastReceiver;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.IntentFilter;
22 import android.os.Message;
23 import android.util.Log;
24 
25 import com.android.internal.util.State;
26 import com.android.internal.util.StateMachine;
27 
28 /**
29  * This state machine is used to serialize the connections
30  * to a particular profile. Currently, we only allow one device
31  * to be connected to a particular profile.
32  * States:
33  *      {@link StableState} : No pending commands. Send the
34  *      command to the appropriate remote device specific state machine.
35  *
36  *      {@link PendingCommandState} : A profile connection / disconnection
37  *      command is being executed. This will result in a profile state
38  *      change. Defer all commands.
39  * @hide
40  */
41 
42 public class BluetoothProfileState extends StateMachine {
43     private static final boolean DBG = true;
44     private static final String TAG = "BluetoothProfileState";
45 
46     public static final int HFP = 0;
47     public static final int A2DP = 1;
48     public static final int HID = 2;
49 
50     static final int TRANSITION_TO_STABLE = 100;
51 
52     private int mProfile;
53     private BluetoothDevice mPendingDevice;
54     private PendingCommandState mPendingCommandState = new PendingCommandState();
55     private StableState mStableState = new StableState();
56 
57     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
58         @Override
59         public void onReceive(Context context, Intent intent) {
60             String action = intent.getAction();
61             BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
62             if (device == null) {
63                 return;
64             }
65             if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
66                 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
67                 if (mProfile == HFP && (newState == BluetoothProfile.STATE_CONNECTED ||
68                     newState == BluetoothProfile.STATE_DISCONNECTED)) {
69                     sendMessage(TRANSITION_TO_STABLE);
70                 }
71             } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
72                 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
73                 if (mProfile == A2DP && (newState == BluetoothProfile.STATE_CONNECTED ||
74                     newState == BluetoothProfile.STATE_DISCONNECTED)) {
75                     sendMessage(TRANSITION_TO_STABLE);
76                 }
77             } else if (action.equals(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED)) {
78                 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
79                 if (mProfile == HID && (newState == BluetoothProfile.STATE_CONNECTED ||
80                     newState == BluetoothProfile.STATE_DISCONNECTED)) {
81                     sendMessage(TRANSITION_TO_STABLE);
82                 }
83             } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
84                 if (device.equals(mPendingDevice)) {
85                     sendMessage(TRANSITION_TO_STABLE);
86                 }
87             }
88         }
89     };
90 
BluetoothProfileState(Context context, int profile)91     public BluetoothProfileState(Context context, int profile) {
92         super("BluetoothProfileState:" + profile);
93         mProfile = profile;
94         addState(mStableState);
95         addState(mPendingCommandState);
96         setInitialState(mStableState);
97 
98         IntentFilter filter = new IntentFilter();
99         filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
100         filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
101         filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
102         filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
103         context.registerReceiver(mBroadcastReceiver, filter);
104     }
105 
106     private class StableState extends State {
107         @Override
enter()108         public void enter() {
109             log("Entering Stable State");
110             mPendingDevice = null;
111         }
112 
113         @Override
processMessage(Message msg)114         public boolean processMessage(Message msg) {
115             if (msg.what != TRANSITION_TO_STABLE) {
116                 transitionTo(mPendingCommandState);
117             }
118             return true;
119         }
120     }
121 
122     private class PendingCommandState extends State {
123         @Override
enter()124         public void enter() {
125             log("Entering PendingCommandState State");
126             dispatchMessage(getCurrentMessage());
127         }
128 
129         @Override
processMessage(Message msg)130         public boolean processMessage(Message msg) {
131             if (msg.what == TRANSITION_TO_STABLE) {
132                 transitionTo(mStableState);
133             } else {
134                 dispatchMessage(msg);
135             }
136             return true;
137         }
138 
dispatchMessage(Message msg)139         private void dispatchMessage(Message msg) {
140             BluetoothDeviceProfileState deviceProfileMgr =
141               (BluetoothDeviceProfileState)msg.obj;
142             int cmd = msg.arg1;
143             if (mPendingDevice == null || mPendingDevice.equals(deviceProfileMgr.getDevice())) {
144                 mPendingDevice = deviceProfileMgr.getDevice();
145                 deviceProfileMgr.sendMessage(cmd);
146             } else {
147                 Message deferMsg = new Message();
148                 deferMsg.arg1 = cmd;
149                 deferMsg.obj = deviceProfileMgr;
150                 deferMessage(deferMsg);
151             }
152         }
153     }
154 
log(String message)155     private void log(String message) {
156         if (DBG) {
157             Log.i(TAG, "Message:" + message);
158         }
159     }
160 }
161