1cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondepackage com.android.bluetooth.sap;
2cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
3cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport java.io.BufferedInputStream;
4cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport java.io.BufferedOutputStream;
5cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport java.io.IOException;
6cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport java.io.InputStream;
7cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport java.io.OutputStream;
8cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport java.util.concurrent.CountDownLatch;
9cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
10cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport com.android.bluetooth.R;
11cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.app.AlarmManager;
12cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.app.Notification;
13cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.app.NotificationManager;
14cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.app.PendingIntent;
15cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.bluetooth.BluetoothDevice;
16cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.bluetooth.BluetoothSocket;
17cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.content.BroadcastReceiver;
18cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.content.Context;
19cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.content.Intent;
20cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.content.IntentFilter;
21cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.content.SyncResult;
22cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.os.Handler;
23cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.os.Handler.Callback;
24cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.os.HandlerThread;
25cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.os.Looper;
26cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.os.Message;
27cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.os.Parcel;
28cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.os.SystemClock;
29cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.telephony.TelephonyManager;
30cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport android.util.Log;
31cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde//import com.android.internal.telephony.RIL;
32cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondeimport com.google.protobuf.micro.CodedOutputStreamMicro;
33cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
34cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
35cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde/**
36cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * The SapServer uses two threads, one for reading messages from the RFCOMM socket and
37cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * one for writing the responses.
38cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * Incoming requests are decoded in the "main" SapServer, by the decoder build into SapMEssage.
39cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * The relevant RIL calls are made from the message handler thread through the rild-bt socket.
40cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * The RIL replies are read in the SapRilReceiver, and passed to the SapServer message handler
41cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * to be written to the RFCOMM socket.
42cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * All writes to the RFCOMM and rild-bt socket must be synchronized, hence to write e.g. an error
43cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * response, send a message to the Sap Handler thread. (There are helper functions to do this)
44cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde * Communication to the RIL is through an intent, and a BroadcastReceiver.
45cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde */
46cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bondepublic class SapServer extends Thread implements Callback {
47cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private static final String TAG = "SapServer";
48cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private static final String TAG_HANDLER = "SapServerHandler";
49cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public static final boolean DEBUG = SapService.DEBUG;
50cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public static final boolean VERBOSE = SapService.VERBOSE;
51cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public static final boolean PTS_TEST = SapService.PTS_TEST;
52cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
53cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private enum SAP_STATE    {
54cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        DISCONNECTED, CONNECTING, CONNECTING_CALL_ONGOING, CONNECTED,
55cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        CONNECTED_BUSY, DISCONNECTING;
56cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
57cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
58cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private SAP_STATE mState = SAP_STATE.DISCONNECTED;
59cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
60cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private Context mContext = null;
61cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* RFCOMM socket I/O streams */
62cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private BufferedOutputStream mRfcommOut = null;
63cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private BufferedInputStream mRfcommIn = null;
64cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* The RIL output stream - the input stream is owned by the SapRilReceiver object */
65cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private CodedOutputStreamMicro mRilBtOutStream = null;
66cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* References to the SapRilReceiver object */
67cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private SapRilReceiver mRilBtReceiver = null;
68cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private Thread mRilBtReceiverThread = null;
69cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* The message handler members */
70cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private Handler mSapHandler = null;
71cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private HandlerThread mHandlerThread = null;
72cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* Reference to the SAP service - which created this instance of the SAP server */
73cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private Handler mSapServiceHandler = null;
74cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
75cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* flag for when user forces disconnect of rfcomm */
76cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private boolean mIsLocalInitDisconnect = false;
77cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private CountDownLatch mDeinitSignal = new CountDownLatch(1);
78cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
79cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* Message ID's handled by the message handler */
80cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public static final int SAP_MSG_RFC_REPLY =   0x00;
81cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public static final int SAP_MSG_RIL_CONNECT = 0x01;
82cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public static final int SAP_MSG_RIL_REQ =     0x02;
83a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde    public static final int SAP_MSG_RIL_IND =     0x03;
84a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde    public static final int SAP_RIL_SOCK_CLOSED = 0x04;
85cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
86b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde    public static final String SAP_DISCONNECT_ACTION =
87b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            "com.android.bluetooth.sap.action.DISCONNECT_ACTION";
88b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde    public static final String SAP_DISCONNECT_TYPE_EXTRA =
89b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            "com.android.bluetooth.sap.extra.DISCONNECT_TYPE";
90cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth;
91cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private static final int DISCONNECT_TIMEOUT_IMMEDIATE = 5000; /* ms */
92cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private static final int DISCONNECT_TIMEOUT_RFCOMM = 2000; /* ms */
93cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private PendingIntent pDiscIntent = null; // Holds a reference to disconnect timeout intents
94b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde
95cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* We store the mMaxMessageSize, as we need a copy of it when the init. sequence completes */
96cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private int mMaxMsgSize = 0;
97cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /* keep track of the current RIL test mode */
98cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private int mTestMode = SapMessage.INVALID_VALUE; // used to set the RIL in test mode
99cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
100cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
101cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * SapServer constructor
102cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param serviceHandler The handler to send a SapService.MSG_SERVERSESSION_CLOSE when closing
103cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param inStream The socket input stream
104cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param outStream The socket output stream
105cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
106b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde    public SapServer(Handler serviceHandler, Context context, InputStream inStream,
107b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            OutputStream outStream) {
108cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mContext = context;
109cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mSapServiceHandler = serviceHandler;
110cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
111cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        /* Open in- and output streams */
112cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mRfcommIn = new BufferedInputStream(inStream);
113cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mRfcommOut = new BufferedOutputStream(outStream);
114cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
115cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        /* Register for phone state change and the RIL cfm message */
116cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        IntentFilter filter = new IntentFilter();
117cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
118cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        filter.addAction(SAP_DISCONNECT_ACTION);
119cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mContext.registerReceiver(mIntentReceiver, filter);
120cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
121cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
122cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
123cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * This handles the response from RIL.
124cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
125cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
126cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        @Override
127cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        public void onReceive(Context context, Intent intent) {
128cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
129cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(VERBOSE) Log.i(TAG, "ACTION_PHONE_STATE_CHANGED intent received in state "
130cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                                        + mState.name()
131cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                                        + "PhoneState: "
132cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                                        + intent.getStringExtra(TelephonyManager.EXTRA_STATE));
133cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(mState == SAP_STATE.CONNECTING_CALL_ONGOING) {
134cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
135cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    if(state != null) {
136cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        if(state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
137cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            if(DEBUG) Log.i(TAG, "sending RIL.ACTION_RIL_RECONNECT_OFF_REQ intent");
138cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            SapMessage fakeConReq = new SapMessage(SapMessage.ID_CONNECT_REQ);
139cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            fakeConReq.setMaxMsgSize(mMaxMsgSize);
140cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            onConnectRequest(fakeConReq);
141cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        }
142cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    }
143cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                }
144a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            } else if (intent.getAction().equals(SAP_DISCONNECT_ACTION)) {
145a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                int disconnectType = intent.getIntExtra(SapServer.SAP_DISCONNECT_TYPE_EXTRA,
146a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                        SapMessage.DISC_GRACEFULL);
147cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                Log.v(TAG, " - Received SAP_DISCONNECT_ACTION type: " + disconnectType);
148cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
149a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                if(disconnectType == SapMessage.DISC_RFCOMM) {
150a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                    // At timeout we need to close the RFCOMM socket to complete shutdown
151a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                    shutdown();
152a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                } else if( mState != SAP_STATE.DISCONNECTED
153a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                    && mState != SAP_STATE.DISCONNECTING ) {
154a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                    // The user pressed disconnect - initiate disconnect sequence.
155a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                    sendDisconnectInd(disconnectType);
156a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                }
157cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } else {
158cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                Log.w(TAG, "RIL-BT received unexpected Intent: " + intent.getAction());
159cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
160cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
161cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    };
162cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
163cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
164cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Set RIL driver in test mode - only possible if SapMessage is build with TEST == true
165cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * The value set by this function will take effect at the next connect request received
166cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * in DISCONNECTED state.
167cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param testMode Use SapMessage.TEST_MODE_XXX
168cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
169cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public void setTestMode(int testMode) {
170cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(SapMessage.TEST) {
171cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mTestMode = testMode;
172cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
173cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
174cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
175cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void sendDisconnectInd(int discType) {
176cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(VERBOSE) Log.v(TAG, "in sendDisconnectInd()");
177cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
178cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(discType != SapMessage.DISC_FORCED){
179cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(VERBOSE) Log.d(TAG, "Sending  disconnect ("+discType+") indication to client");
180cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* Send disconnect to client */
181cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            SapMessage discInd = new SapMessage(SapMessage.ID_DISCONNECT_IND);
182cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            discInd.setDisconnectionType(discType);
183cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sendClientMessage(discInd);
184cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
185cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* Handle local disconnect procedures */
186cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if (discType == SapMessage.DISC_GRACEFULL)
187cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            {
188cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                /* Update the notification to allow the user to initiate a force disconnect */
189cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                setNotification(SapMessage.DISC_IMMEDIATE, PendingIntent.FLAG_CANCEL_CURRENT);
190cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
191cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } else if (discType == SapMessage.DISC_IMMEDIATE){
192b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                /* Request an immediate disconnect, but start a timer to force disconnect if the
193b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                 * client do not obey our request. */
194cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                startDisconnectTimer(SapMessage.DISC_FORCED, DISCONNECT_TIMEOUT_IMMEDIATE);
195cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
196cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
197cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } else {
198cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            SapMessage msg = new SapMessage(SapMessage.ID_DISCONNECT_REQ);
199cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* Force disconnect of RFCOMM - but first we need to clean up. */
200cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            clearPendingRilResponses(msg);
201cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
202b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            /* We simply need to forward to RIL, but not change state to busy - hence send and set
203b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde               message to null. */
204cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            changeState(SAP_STATE.DISCONNECTING);
205cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sendRilThreadMessage(msg);
206cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mIsLocalInitDisconnect = true;
207cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
208cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
209cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
210cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    void setNotification(int type, int flags)
211cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    {
212cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        String title, text, button, ticker;
213cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        Notification notification;
214cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(VERBOSE) Log.i(TAG, "setNotification type: " + type);
215cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        /* put notification up for the user to be able to disconnect from the client*/
216cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        Intent sapDisconnectIntent = new Intent(SapServer.SAP_DISCONNECT_ACTION);
217cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(type == SapMessage.DISC_GRACEFULL){
218cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            title = mContext.getString(R.string.bluetooth_sap_notif_title);
219cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            button = mContext.getString(R.string.bluetooth_sap_notif_disconnect_button);
220cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            text = mContext.getString(R.string.bluetooth_sap_notif_message);
221cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            ticker = mContext.getString(R.string.bluetooth_sap_notif_ticker);
222cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }else{
223cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            title = mContext.getString(R.string.bluetooth_sap_notif_title);
224cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            button = mContext.getString(R.string.bluetooth_sap_notif_force_disconnect_button);
225cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            text = mContext.getString(R.string.bluetooth_sap_notif_disconnecting);
226cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            ticker = mContext.getString(R.string.bluetooth_sap_notif_ticker);
227cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
228cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(!PTS_TEST)
229cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        {
230cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sapDisconnectIntent.putExtra(SapServer.SAP_DISCONNECT_TYPE_EXTRA, type);
231b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            PendingIntent pIntentDisconnect = PendingIntent.getBroadcast(mContext, type,
232b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    sapDisconnectIntent,flags);
233cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            notification = new Notification.Builder(mContext).setOngoing(true)
234cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .addAction(android.R.drawable.stat_sys_data_bluetooth, button, pIntentDisconnect)
235cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .setContentTitle(title)
236cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .setTicker(ticker)
237cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .setContentText(text)
238cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
239cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .setAutoCancel(false)
240cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .setPriority(Notification.PRIORITY_MAX)
241cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .setOnlyAlertOnce(true)
242cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                .build();
243cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }else{
244cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
245b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            sapDisconnectIntent.putExtra(SapServer.SAP_DISCONNECT_TYPE_EXTRA,
246b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    SapMessage.DISC_GRACEFULL);
247cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            Intent sapForceDisconnectIntent = new Intent(SapServer.SAP_DISCONNECT_ACTION);
248b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            sapForceDisconnectIntent.putExtra(SapServer.SAP_DISCONNECT_TYPE_EXTRA,
249b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    SapMessage.DISC_IMMEDIATE);
250b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            PendingIntent pIntentDisconnect = PendingIntent.getBroadcast(mContext,
251b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    SapMessage.DISC_GRACEFULL, sapDisconnectIntent,flags);
252b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            PendingIntent pIntentForceDisconnect = PendingIntent.getBroadcast(mContext,
253b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    SapMessage.DISC_IMMEDIATE, sapForceDisconnectIntent,flags);
254cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            notification = new Notification.Builder(mContext).setOngoing(true)
255b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    .addAction(android.R.drawable.stat_sys_data_bluetooth,
256b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            mContext.getString(R.string.bluetooth_sap_notif_disconnect_button),
257b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            pIntentDisconnect)
258b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    .addAction(android.R.drawable.stat_sys_data_bluetooth,
259b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            mContext.getString(R.string.bluetooth_sap_notif_force_disconnect_button),
260b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            pIntentForceDisconnect)
261cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .setContentTitle(title)
262cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .setTicker(ticker)
263cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .setContentText(text)
264cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
265cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .setAutoCancel(false)
266cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .setPriority(Notification.PRIORITY_MAX)
267cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .setOnlyAlertOnce(true)
268cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    .build();
269cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
270cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
271a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde        // cannot be set with the builder
272a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde        notification.flags |= Notification.FLAG_NO_CLEAR |Notification.FLAG_ONLY_ALERT_ONCE;
273cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
274cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        NotificationManager notificationManager =
275cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
276cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
277cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        notificationManager.notify(NOTIFICATION_ID, notification);
278cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
279a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde
280a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde    void clearNotification() {
281a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde        NotificationManager notificationManager =
282a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
283a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde        notificationManager.cancel(SapServer.NOTIFICATION_ID);
284a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde    }
285a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde
286cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
287cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * The SapServer RFCOMM reader thread. Sets up the handler thread and handle
288cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * all read from the RFCOMM in-socket. This thread also handle writes to the RIL socket.
289cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
290cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    @Override
291cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public void run() {
292cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        try {
293b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            /* SAP is not time critical, hence lowering priority to ensure critical tasks are
294b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde             * executed in a timely manner. */
295cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
296cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
297cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* Start the SAP message handler thread */
298b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            mHandlerThread = new HandlerThread("SapServerHandler",
299b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    android.os.Process.THREAD_PRIORITY_BACKGROUND);
300cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mHandlerThread.start();
301b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde
302b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            // This will return when the looper is ready
303b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            Looper sapLooper = mHandlerThread.getLooper();
304cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mSapHandler = new Handler(sapLooper, this);
305cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
306bbb071e6d73df46230ec654e3066a46f6e35a88dCasper Bonde            mRilBtReceiver = new SapRilReceiver(mSapHandler, mSapServiceHandler);
307cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mRilBtReceiverThread = new Thread(mRilBtReceiver, "RilBtReceiver");
308cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            setNotification(SapMessage.DISC_GRACEFULL,0);
309cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            boolean done = false;
310cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            while (!done) {
311cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(VERBOSE) Log.i(TAG, "Waiting for incomming RFCOMM message...");
312cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                int requestType = mRfcommIn.read();
313cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(requestType == -1) {
314cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    done = true; // EOF reached
315cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                } else {
316cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    SapMessage msg = SapMessage.readMessage(requestType, mRfcommIn);
317bbb071e6d73df46230ec654e3066a46f6e35a88dCasper Bonde                    /* notify about an incoming message from the BT Client */
318bbb071e6d73df46230ec654e3066a46f6e35a88dCasper Bonde                    SapService.notifyUpdateWakeLock(mSapServiceHandler);
319cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    if(msg != null && mState != SAP_STATE.DISCONNECTING)
320cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    {
321cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        switch (requestType) {
322cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        case SapMessage.ID_CONNECT_REQ:
323b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            if(VERBOSE) Log.d(TAG, "CONNECT_REQ - MaxMsgSize: "
324b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                                    + msg.getMaxMsgSize());
325cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            onConnectRequest(msg);
326cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            msg = null; /* don't send ril connect yet */
327cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            break;
328cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        case SapMessage.ID_DISCONNECT_REQ: /* No params */
329cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            /*
330b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * 1) send RIL_REQUEST_SIM_SAP_DISCONNECT
331b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             *      (block for all incoming requests, as they are not
332b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             *       allowed, don't even send an error_resp)
333cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                             * 2) on response disconnect ril socket.
334cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                             * 3) when disconnected send RIL.ACTION_RIL_RECONNECT_OFF_REQ
335b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * 4) on RIL.ACTION_RIL_RECONNECT_CFM
336b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             *       send SAP_DISCONNECT_RESP to client.
337cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                             * 5) Start RFCOMM disconnect timer
338b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * 6.a) on rfcomm disconnect:
339b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             *       cancel timer and initiate cleanup
340b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * 6.b) on rfcomm disc. timeout:
341b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             *       close socket-streams and initiate cleanup */
342cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            if(VERBOSE) Log.d(TAG, "DISCONNECT_REQ");
343cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
344cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            clearPendingRilResponses(msg);
345b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde
346b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            changeState(SAP_STATE.DISCONNECTING);
347b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde
348cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            sendRilThreadMessage(msg);
349b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            /* We simply need to forward to RIL, but not change state to busy
350b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * - hence send and set message to null. */
351cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            msg = null; // don't send twice
352cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            /*cancel the timer for the hard-disconnect intent*/
353cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            stopDisconnectTimer();
354cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            break;
355cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        case SapMessage.ID_POWER_SIM_OFF_REQ: // Fall through
356cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        case SapMessage.ID_RESET_SIM_REQ:
357b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            /* Forward these to the RIL regardless of the state, and clear any
358b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * pending resp */
359cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            clearPendingRilResponses(msg);
360cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            break;
361a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                        case SapMessage.ID_SET_TRANSPORT_PROTOCOL_REQ:
362a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                            /* The RIL might support more protocols that specified in the SAP,
363b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * allow only the valid values. */
364a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                            if(mState == SAP_STATE.CONNECTED
365a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                    && msg.getTransportProtocol() != 0
366a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                    && msg.getTransportProtocol() != 1) {
367a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                Log.w(TAG, "Invalid TransportProtocol received:"
368a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                        + msg.getTransportProtocol());
369a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                // We shall only handle one request at the time, hence return error
370a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                SapMessage errorReply = new SapMessage(SapMessage.ID_ERROR_RESP);
371a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                sendClientMessage(errorReply);
372a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                msg = null;
373a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                            }
374a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                            // Fall through
375cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        default:
376b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            /* Remaining cases just needs to be forwarded to the RIL unless we are
377b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * in busy state. */
378cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            if(mState != SAP_STATE.CONNECTED) {
379b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                                Log.w(TAG, "Message received in STATE != CONNECTED - state = "
380b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                                        + mState.name());
381b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                                // We shall only handle one request at the time, hence return error
382a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                SapMessage errorReply = new SapMessage(SapMessage.ID_ERROR_RESP);
383a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                sendClientMessage(errorReply);
384cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                                msg = null;
385cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            }
386cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        }
387cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
388cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        if(msg != null && msg.getSendToRil() == true) {
389cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            changeState(SAP_STATE.CONNECTED_BUSY);
390cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            sendRilThreadMessage(msg);
391cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        }
392cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
393b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    } else {
394b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                        //An unknown message or in disconnecting state - send error indication
395cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        Log.e(TAG, "Unable to parse message.");
396cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        SapMessage atrReply = new SapMessage(SapMessage.ID_ERROR_RESP);
397cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        sendClientMessage(atrReply);
398cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    }
399cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                }
400cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } // end while
401cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } catch (NullPointerException e) {
402cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            Log.w(TAG, e);
403cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } catch (IOException e) {
404cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* This is expected during shutdown */
405cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            Log.i(TAG, "IOException received, this is probably a shutdown signal, cleaning up...");
406cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } catch (Exception e) {
407cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* TODO: Change to the needed Exception types when done testing */
408cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            Log.w(TAG, e);
409cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } finally {
410cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            // Do cleanup even if an exception occurs
411cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            stopDisconnectTimer();
412cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* In case of e.g. a RFCOMM close while connected:
413cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde             *        - Initiate a FORCED shutdown
414cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde             *        - Wait for RIL deinit to complete
415cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde             */
416cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(mState != SAP_STATE.DISCONNECTED) {
417cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(mState != SAP_STATE.DISCONNECTING &&
418cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        mIsLocalInitDisconnect != true) {
419cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    sendDisconnectInd(SapMessage.DISC_FORCED);
420cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                }
421cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(DEBUG) Log.i(TAG, "Waiting for deinit to complete");
422cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                try {
423cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    mDeinitSignal.await();
424cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                } catch (InterruptedException e) {
425cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    Log.e(TAG, "Interrupt received while waitinf for de-init to complete", e);
426cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                }
427cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
428a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde
429a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            if(mIntentReceiver != null) {
430a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                mContext.unregisterReceiver(mIntentReceiver);
431a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                mIntentReceiver = null;
432a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            }
433a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            stopDisconnectTimer();
434a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            clearNotification();
435a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde
436cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(mHandlerThread != null) try {
437cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                mHandlerThread.quit();
438cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                mHandlerThread.join();
439a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                mHandlerThread = null;
440cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } catch (InterruptedException e) {}
441cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(mRilBtReceiverThread != null) try {
442a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                if(mRilBtReceiver != null) {
443a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                    mRilBtReceiver.shutdown();
444a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                    mRilBtReceiver = null;
445a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                }
446cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                mRilBtReceiverThread.join();
447a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                mRilBtReceiverThread = null;
448cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } catch (InterruptedException e) {}
449cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
450cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(mRfcommIn != null) try {
451cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(VERBOSE) Log.i(TAG, "Closing mRfcommIn...");
452cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                mRfcommIn.close();
453a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                mRfcommIn = null;
454cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } catch (IOException e) {}
455cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
456cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(mRfcommOut != null) try {
457cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(VERBOSE) Log.i(TAG, "Closing mRfcommOut...");
458cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                mRfcommOut.close();
459a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                mRfcommOut = null;
460cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } catch (IOException e) {}
461cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
462cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if (mSapServiceHandler != null) {
463cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                Message msg = Message.obtain(mSapServiceHandler);
464cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                msg.what = SapService.MSG_SERVERSESSION_CLOSE;
465cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                msg.sendToTarget();
466cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if (DEBUG) Log.d(TAG, "MSG_SERVERSESSION_CLOSE sent out.");
467cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
468cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            Log.i(TAG, "All done exiting thread...");
469cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
470cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
471cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
472cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
473cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
474cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * This function needs to determine:
475b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde     *  - if the maxMsgSize is acceptable - else reply CON_STATUS_ERROR_MAX_MSG_SIZE_UNSUPPORTED
476b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde     *      + new maxMsgSize if too big
477cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *  - connect to the RIL-BT socket
478cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *  - if a call is ongoing reply CON_STATUS_OK_ONGOING_CALL.
479cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *  - if all ok, just respond CON_STATUS_OK.
480cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *
481cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param msg the incoming SapMessage
482cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
483cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void onConnectRequest(SapMessage msg) {
484cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        SapMessage reply = new SapMessage(SapMessage.ID_CONNECT_RESP);
485cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
486cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(mState == SAP_STATE.CONNECTING) {
487cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* A connect request might have been rejected because of maxMessageSize negotiation, and
488cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde             * this is a new connect request. Simply forward to RIL, and stay in connecting state.
489cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde             * */
490cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            reply = null;
491cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sendRilMessage(msg);
492cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            stopDisconnectTimer();
493cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
494cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } else if(mState != SAP_STATE.DISCONNECTED && mState != SAP_STATE.CONNECTING_CALL_ONGOING) {
495cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            reply.setConnectionStatus(SapMessage.CON_STATUS_ERROR_CONNECTION);
496cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } else {
497cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            // Store the MaxMsgSize for future use
498cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mMaxMsgSize = msg.getMaxMsgSize();
499b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            // All parameters OK, examine if a call is ongoing and start the RIL-BT listener thread
500cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if (isCallOngoing() == true) {
501b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                /* If a call is ongoing we set the state, inform the SAP client and wait for a state
502b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                 * change intent from the TelephonyManager with state IDLE. */
503cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                changeState(SAP_STATE.CONNECTING_CALL_ONGOING);
504cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                reply.setConnectionStatus(SapMessage.CON_STATUS_OK_ONGOING_CALL);
505cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } else {
506cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                /* no call is ongoing, initiate the connect sequence:
507cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                 *  1) Start the SapRilReceiver thread (open the rild-bt socket)
508cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                 *  2) Send a RIL_SIM_SAP_CONNECT request to RILD
509cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                 *  3) Send a RIL_SIM_RESET request and a connect confirm to the SAP client */
510cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                changeState(SAP_STATE.CONNECTING);
511cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(mRilBtReceiverThread != null) {
512b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                     // Open the RIL socket, and wait for the complete message: SAP_MSG_RIL_CONNECT
513cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    mRilBtReceiverThread.start();
514cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    // Don't send reply yet
515cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    reply = null;
516cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                } else {
517cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    reply = new SapMessage(SapMessage.ID_CONNECT_RESP);
518cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    reply.setConnectionStatus(SapMessage.CON_STATUS_ERROR_CONNECTION);
519cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    sendClientMessage(reply);
520cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                }
521cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
522cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
523cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(reply != null)
524cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sendClientMessage(reply);
525cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
526cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
527cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void clearPendingRilResponses(SapMessage msg) {
528cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(mState == SAP_STATE.CONNECTED_BUSY) {
529cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            msg.setClearRilQueue(true);
530cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
531cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
532cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
533cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Send RFCOMM message to the Sap Server Handler Thread
534cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param sapMsg The message to send
535cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
536cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void sendClientMessage(SapMessage sapMsg) {
537cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        Message newMsg = mSapHandler.obtainMessage(SAP_MSG_RFC_REPLY, sapMsg);
538cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mSapHandler.sendMessage(newMsg);
539cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
540cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
541cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
542cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Send a RIL message to the SapServer message handler thread
543cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param sapMsg
544cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
545cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void sendRilThreadMessage(SapMessage sapMsg) {
546cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        Message newMsg = mSapHandler.obtainMessage(SAP_MSG_RIL_REQ, sapMsg);
547cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mSapHandler.sendMessage(newMsg);
548cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
549cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
550cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
551cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Examine if a call is ongoing, by asking the telephony manager
552cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @return false if the phone is IDLE (can be used for SAP), true otherwise.
553cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
554cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private boolean isCallOngoing() {
555b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde        TelephonyManager tManager =
556b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
557cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(tManager.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
558cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return false;
559cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
560cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        return true;
561cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
562cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
563cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
564cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Change the SAP Server state.
565cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * We add thread protection, as we access the state from two threads.
566cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param newState
567cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
568cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void changeState(SAP_STATE newState) {
569cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(DEBUG) Log.i(TAG_HANDLER,"Changing state from " + mState.name() +
570cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                                        " to " + newState.name());
571cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        synchronized (this) {
572cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mState = newState;
573cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
574cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
575cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
576cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
577cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /*************************************************************************
578cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * SAP Server Message Handler Thread Functions
579cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *************************************************************************/
580cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
581cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
582cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * The SapServer message handler thread implements the SAP state machine.
583cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *  - Handle all outgoing communication to the out-socket. Either replies from the RIL or direct
584cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *    messages send from the SapServe (e.g. connect_resp).
585cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *  - Handle all outgoing communication to the RIL-BT socket.
586cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     *  - Handle all replies from the RIL
587cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
588cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    @Override
589cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    public boolean handleMessage(Message msg) {
590b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde        if(VERBOSE) Log.i(TAG_HANDLER,"Handling message (ID: " + msg.what + "): "
591b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                + getMessageName(msg.what));
592cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
593cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        SapMessage sapMsg = null;
594cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
595cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        switch(msg.what) {
596cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RFC_REPLY:
597cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sapMsg = (SapMessage) msg.obj;
598cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            handleRfcommReply(sapMsg);
599cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            break;
600cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RIL_CONNECT:
601cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* The connection to rild-bt have been established. Store the outStream handle
602cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde             * and send the connect request. */
603cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mRilBtOutStream = mRilBtReceiver.getRilBtOutStream();
604cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(mTestMode != SapMessage.INVALID_VALUE) {
605cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                SapMessage rilTestModeReq = new SapMessage(SapMessage.ID_RIL_SIM_ACCESS_TEST_REQ);
606cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                rilTestModeReq.setTestMode(mTestMode);
607cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                sendRilMessage(rilTestModeReq);
608cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                mTestMode = SapMessage.INVALID_VALUE;
609cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
610cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            SapMessage rilSapConnect = new SapMessage(SapMessage.ID_CONNECT_REQ);
611cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            rilSapConnect.setMaxMsgSize(mMaxMsgSize);
612cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sendRilMessage(rilSapConnect);
613cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            break;
614cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RIL_REQ:
615cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sapMsg = (SapMessage) msg.obj;
616cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(sapMsg != null) {
617cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                sendRilMessage(sapMsg);
618cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
619cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            break;
620cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RIL_IND:
621cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sapMsg = (SapMessage) msg.obj;
622cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            handleRilInd(sapMsg);
623cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            break;
624a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde        case SAP_RIL_SOCK_CLOSED:
625a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            /* The RIL socket was closed unexpectedly, send immediate disconnect indication
626a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde               - close RFCOMM after timeout if no response. */
627a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            sendDisconnectInd(SapMessage.DISC_IMMEDIATE);
628a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            startDisconnectTimer(SapMessage.DISC_RFCOMM, DISCONNECT_TIMEOUT_RFCOMM);
629a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            break;
630cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        default:
631cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            /* Message not handled */
632cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return false;
633cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
634cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        return true; // Message handles
635cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
636cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
637cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
638cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Close the in/out rfcomm streams, to trigger a shutdown of the SapServer main thread.
639cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Use this after completing the deinit sequence.
640cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
641cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void shutdown() {
642cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
643cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(DEBUG) Log.i(TAG_HANDLER, "in Shutdown()");
644cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        try {
645cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mRfcommOut.close();
646cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } catch (IOException e) {}
647cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        try {
648cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            mRfcommIn.close();
649cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
650cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } catch (IOException e) {}
651cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mRfcommIn = null;
652cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        mRfcommOut = null;
653cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        stopDisconnectTimer();
654a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde        clearNotification();
655cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
656cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
657cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void startDisconnectTimer(int discType, int timeMs) {
658cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
659cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        stopDisconnectTimer();
660cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        synchronized (this) {
661cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            Intent sapDisconnectIntent = new Intent(SapServer.SAP_DISCONNECT_ACTION);
662cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sapDisconnectIntent.putExtra(SAP_DISCONNECT_TYPE_EXTRA, discType);
663cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            AlarmManager alarmManager =
664cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
665cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            pDiscIntent = PendingIntent.getBroadcast(mContext,
666cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                                                    discType,
667b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                                                    sapDisconnectIntent,
668b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                                                    PendingIntent.FLAG_CANCEL_CURRENT);
669b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
670b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    SystemClock.elapsedRealtime() + timeMs, pDiscIntent);
671cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
672cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(VERBOSE) Log.d(TAG_HANDLER, "Setting alarm for " + timeMs +
673cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    " ms to activate disconnect type " + discType);
674cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
675cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
676cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
677cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void stopDisconnectTimer() {
678cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        synchronized (this) {
679cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(pDiscIntent != null)
680cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            {
681cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                AlarmManager alarmManager =
682cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
683cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                alarmManager.cancel(pDiscIntent);
684cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                pDiscIntent.cancel();
685cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                if(VERBOSE) {
686cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    Log.d(TAG_HANDLER, "Canceling disconnect alarm");
687cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                }
688cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                pDiscIntent = null;
689cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
690cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
691cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
692cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
693cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
694cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Here we handle the replies to the SAP client, normally forwarded directly from the RIL.
695cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * We do need to handle some of the messages in the SAP profile, hence we look at the messages
696cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * here before they go to the client
697cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param sapMsg the message to send to the SAP client
698cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
699cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void handleRfcommReply(SapMessage sapMsg) {
700cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(sapMsg != null) {
701cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
702b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            if(DEBUG) Log.i(TAG_HANDLER, "handleRfcommReply() handling "
703b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    + SapMessage.getMsgTypeName(sapMsg.getMsgType()));
704cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
705cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            switch(sapMsg.getMsgType()) {
706cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
707cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                case SapMessage.ID_CONNECT_RESP:
708cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    if (sapMsg.getConnectionStatus() == SapMessage.CON_STATUS_OK) {
709cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        // This is successful connect response from RIL/modem.
710cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        changeState(SAP_STATE.CONNECTED);
711cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    } else if(sapMsg.getConnectionStatus() == SapMessage.CON_STATUS_OK_ONGOING_CALL
712cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                              && mState != SAP_STATE.CONNECTING_CALL_ONGOING) {
713cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        changeState(SAP_STATE.CONNECTING_CALL_ONGOING);
714cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    } else if(mState == SAP_STATE.CONNECTING_CALL_ONGOING) {
715b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                        /* Hold back the connect resp if a call was ongoing when the connect req
716b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                         *  was received.
717b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                         */
718b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                        if(VERBOSE) Log.i(TAG, "Hold back the connect resp, as a call was ongoing" +
719b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                                " when the initial response were sent.");
720cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        sapMsg = null;
721cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    } else if(sapMsg.getConnectionStatus() != SapMessage.CON_STATUS_OK) {
722b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                        /* Most likely the peer will try to connect again, hence we keep the
723b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                         * connection to RIL open and stay in connecting state.
724b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                         *
725b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                         * Start timer to do shutdown if a new connect request is not received in
726b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                         * time. */
727cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        startDisconnectTimer(SapMessage.DISC_FORCED, DISCONNECT_TIMEOUT_RFCOMM);
728cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    }
729cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    break;
730cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                case SapMessage.ID_DISCONNECT_RESP:
731cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    if(mState == SAP_STATE.DISCONNECTING) {
732a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                        /* Close the RIL-BT output Stream and signal to SapRilReceiver to close
733a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                         * down the input stream. */
734a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                        if(DEBUG) Log.i(TAG, "ID_DISCONNECT_RESP received in SAP_STATE." +
735a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                                "DISCONNECTING.");
736a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde
737a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                        /* Send the disconnect resp, and wait for the client to close the Rfcomm,
738a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                         * but start a timeout timer, just to be sure. Use alarm, to ensure we wake
739a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                         * the host to close the connection to minimize power consumption. */
740cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        SapMessage disconnectResp = new SapMessage(SapMessage.ID_DISCONNECT_RESP);
741cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        changeState(SAP_STATE.DISCONNECTED);
742cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        sapMsg = disconnectResp;
743a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                        startDisconnectTimer(SapMessage.DISC_RFCOMM, DISCONNECT_TIMEOUT_RFCOMM);
744a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                        mDeinitSignal.countDown(); /* Signal deinit complete */
745cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    } else { /* DISCONNECTED */
746cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        mDeinitSignal.countDown(); /* Signal deinit complete */
747cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        if(mIsLocalInitDisconnect == true) {
748cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            if(VERBOSE) Log.i(TAG_HANDLER, "This is a FORCED disconnect.");
749b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            /* We needed to force the disconnect, hence no hope for the client to
750b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * close the RFCOMM connection, hence we do it here. */
751cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            shutdown();
752cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            sapMsg = null;
753cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        } else {
754b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                            /* The client must disconnect the RFCOMM, but in case it does not, we
755b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * need to do it.
756b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * We start an alarm, and if it triggers, we must send the
757b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                             * MSG_SERVERSESSION_CLOSE */
758cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            if(VERBOSE) Log.i(TAG_HANDLER, "This is a NORMAL disconnect.");
759cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            startDisconnectTimer(SapMessage.DISC_RFCOMM, DISCONNECT_TIMEOUT_RFCOMM);
760cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        }
761cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    }
762cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    break;
763cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                case SapMessage.ID_STATUS_IND:
764cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    /* Some car-kits only "likes" status indication when connected, hence discard
765cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                     * any arriving outside this state */
766cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    if(mState == SAP_STATE.DISCONNECTED ||
767cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            mState == SAP_STATE.CONNECTING ||
768cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                            mState == SAP_STATE.DISCONNECTING) {
769cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                        sapMsg = null;
770cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    }
771cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                    break;
772cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                default:
773cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                // Nothing special, just send the message
774cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
775cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
776cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
777cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        /* Update state variable based on the number of pending commands. We are only able to
778cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde         * handle one request at the time, except from disconnect, sim off and sim reset.
779cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde         * Hence if one of these are received while in busy state, we might have a crossing
780cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde         * response, hence we must stay in BUSY state if we have an ongoing RIL request. */
781cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(mState == SAP_STATE.CONNECTED_BUSY) {
782cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(SapMessage.getNumPendingRilMessages() == 0) {
783cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                changeState(SAP_STATE.CONNECTED);
784cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
785cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
786cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
787cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        // This is the default case - just send the message to the SAP client.
788cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(sapMsg != null)
789cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sendReply(sapMsg);
790cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
791cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
792cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void handleRilInd(SapMessage sapMsg) {
793cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        if(sapMsg == null)
794cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return;
795cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
796cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        switch(sapMsg.getMsgType()) {
797cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SapMessage.ID_DISCONNECT_IND:
798cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        {
799cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            if(mState != SAP_STATE.DISCONNECTED && mState != SAP_STATE.DISCONNECTING){
800cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                /* we only send disconnect indication to the client if we are actually connected*/
801cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                SapMessage reply = new SapMessage(SapMessage.ID_DISCONNECT_IND);
802cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                reply.setDisconnectionType(sapMsg.getDisconnectionType()) ;
803cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                sendClientMessage(reply);
804cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            } else {
805cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                /* TODO: This was introduced to handle disconnect indication from RIL */
806cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde                sendDisconnectInd(sapMsg.getDisconnectionType());
807cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            }
808cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            break;
809cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
810cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
811cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        default:
812b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde            if(DEBUG) Log.w(TAG_HANDLER,"Unhandled message - type: "
813b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                    + SapMessage.getMsgTypeName(sapMsg.getMsgType()));
814cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
815cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
816cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
817cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
818cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * This is only to be called from the handlerThread, else use sendRilThreadMessage();
819cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * @param sapMsg
820cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
821cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void sendRilMessage(SapMessage sapMsg) {
822b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde        if(VERBOSE) Log.i(TAG_HANDLER, "sendRilMessage() - "
823b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                + SapMessage.getMsgTypeName(sapMsg.getMsgType()));
824cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        try {
825cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sapMsg.writeReqToStream(mRilBtOutStream);
826cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        } catch (IOException e) {
827cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            Log.e(TAG_HANDLER, "Unable to send message to RIL", e);
828cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            SapMessage errorReply = new SapMessage(SapMessage.ID_ERROR_RESP);
829cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            sendClientMessage(errorReply);
830cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
831cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
832cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
833cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    /**
834cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     * Only call this from the sapHandler thread.
835cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde     */
836cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private void sendReply(SapMessage msg) {
837b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde        if(VERBOSE) Log.i(TAG_HANDLER, "sendReply() RFCOMM - "
838b6791189b3c8be04b521b8520aed006f012304d1Casper Bonde                + SapMessage.getMsgTypeName(msg.getMsgType()));
839a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde        if(mRfcommOut != null) { // Needed to handle brutal shutdown from car-kit and out of range
840a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            try {
841a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                msg.write(mRfcommOut);
842a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                mRfcommOut.flush();
843a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            } catch (IOException e) {
844a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                Log.w(TAG_HANDLER, e);
845a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                /* As we cannot write to the rfcomm channel we are disconnected.
846a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde                   Shutdown and prepare for a new connect. */
847a49b4e45faf378e3848c4f6eb468e0a14565aa6cCasper Bonde            }
848cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
849cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
850cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
851cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    private static String getMessageName(int messageId) {
852cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        switch (messageId) {
853cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RFC_REPLY:
854cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return "SAP_MSG_REPLY";
855cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RIL_CONNECT:
856cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return "SAP_MSG_RIL_CONNECT";
857cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RIL_REQ:
858cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return "SAP_MSG_RIL_REQ";
859cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        case SAP_MSG_RIL_IND:
860cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return "SAP_MSG_RIL_IND";
861cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        default:
862cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde            return "Unknown message ID";
863cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde        }
864cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde    }
865cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde
866cee0d1b1f13b4401a895be650605fa307e70bdb6Casper Bonde}
867