10217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan/*
20217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * Copyright (C) 2017 The Android Open Source Project
30217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan *
40217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * Licensed under the Apache License, Version 2.0 (the "License");
50217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * you may not use this file except in compliance with the License.
60217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * You may obtain a copy of the License at
70217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan *
80217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan *      http://www.apache.org/licenses/LICENSE-2.0
90217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan *
100217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * Unless required by applicable law or agreed to in writing, software
110217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * distributed under the License is distributed on an "AS IS" BASIS,
120217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * See the License for the specific language governing permissions and
140217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * limitations under the License.
150217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan */
160217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
170217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanpackage com.android.car.messenger;
180217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
190217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.app.Service;
200217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.bluetooth.BluetoothAdapter;
210217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.bluetooth.BluetoothDevice;
220217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.bluetooth.BluetoothMapClient;
230217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.bluetooth.BluetoothProfile;
240217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.content.BroadcastReceiver;
250217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.content.Context;
260217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.content.Intent;
270217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.content.IntentFilter;
2860060c1692a932c32d5449443c477a53d5112884roger xueimport android.os.Binder;
290217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.os.IBinder;
300217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.util.Log;
310217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanimport android.widget.Toast;
320217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
330217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan/**
340217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * Background started service that hosts messaging components.
350217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * <p>
360217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * The MapConnector manages connecting to the BT MAP service and the MapMessageMonitor listens for
370217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * new incoming messages and publishes notifications. Actions in the notifications trigger command
380217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * intents to this service (e.g. auto-reply, play message).
390217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * <p>
400217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan * This service and its helper components run entirely in the main thread.
410217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan */
420217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathanpublic class MessengerService extends Service {
430217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final String TAG = "MessengerService";
440217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
450217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
460217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    // Used to start this service at boot-complete. Takes no arguments.
470217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final String ACTION_START = "com.android.car.messenger.ACTION_START";
480217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    // Used to auto-reply to messages from a sender (invoked from Notification).
490217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final String ACTION_AUTO_REPLY = "com.android.car.messenger.ACTION_AUTO_REPLY";
500217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    // Used to play-out messages from a sender (invoked from Notification).
510217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final String ACTION_PLAY_MESSAGES = "com.android.car.messenger.ACTION_PLAY_MESSAGES";
524a5024d82db356bc7c6e0848c80f4f0d7e213a0eSrinivas Visvanathan    // Used to stop further audio notifications from the conversation.
534a5024d82db356bc7c6e0848c80f4f0d7e213a0eSrinivas Visvanathan    static final String ACTION_MUTE_CONVERSATION =
544a5024d82db356bc7c6e0848c80f4f0d7e213a0eSrinivas Visvanathan            "com.android.car.messenger.ACTION_MUTE_CONVERSATION";
551d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue    // Used to resume further audio notifications from the conversation.
561d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue    static final String ACTION_UNMUTE_CONVERSATION =
571d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue            "com.android.car.messenger.ACTION_UNMUTE_CONVERSATION";
580217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    // Used to clear notification state when user dismisses notification.
590217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final String ACTION_CLEAR_NOTIFICATION_STATE =
600217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            "com.android.car.messenger.ACTION_CLEAR_NOTIFICATION_STATE";
610217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    // Used to stop current play-out (invoked from Notification).
620217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final String ACTION_STOP_PLAYOUT = "com.android.car.messenger.ACTION_STOP_PLAYOUT";
630217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
640217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    // Common extra for ACTION_AUTO_REPLY and ACTION_PLAY_MESSAGES.
650217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    static final String EXTRA_SENDER_KEY = "com.android.car.messenger.EXTRA_SENDER_KEY";
660217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
67dc905655368f1847bd63e823804ce611086cc487Lujiang Xue    static final String EXTRA_REPLY_MESSAGE = "com.android.car.messenger.EXTRA_REPLY_MESSAGE";
68dc905655368f1847bd63e823804ce611086cc487Lujiang Xue
6960060c1692a932c32d5449443c477a53d5112884roger xue    // Used to notify that this service started to play out the messages.
7060060c1692a932c32d5449443c477a53d5112884roger xue    static final String ACTION_PLAY_MESSAGES_STARTED =
7160060c1692a932c32d5449443c477a53d5112884roger xue            "com.android.car.messenger.ACTION_PLAY_MESSAGES_STARTED";
7260060c1692a932c32d5449443c477a53d5112884roger xue
7360060c1692a932c32d5449443c477a53d5112884roger xue    // Used to notify that this service finished playing out the messages.
7460060c1692a932c32d5449443c477a53d5112884roger xue    static final String ACTION_PLAY_MESSAGES_STOPPED =
7560060c1692a932c32d5449443c477a53d5112884roger xue            "com.android.car.messenger.ACTION_PLAY_MESSAGES_STOPPED";
7660060c1692a932c32d5449443c477a53d5112884roger xue
770217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    private MapMessageMonitor mMessageMonitor;
780217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    private MapDeviceMonitor mDeviceMonitor;
790217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    private BluetoothMapClient mMapClient;
8060060c1692a932c32d5449443c477a53d5112884roger xue    private final IBinder mBinder = new LocalBinder();
8160060c1692a932c32d5449443c477a53d5112884roger xue
8260060c1692a932c32d5449443c477a53d5112884roger xue    public class LocalBinder extends Binder {
8360060c1692a932c32d5449443c477a53d5112884roger xue        MessengerService getService() {
8460060c1692a932c32d5449443c477a53d5112884roger xue            return MessengerService.this;
8560060c1692a932c32d5449443c477a53d5112884roger xue        }
8660060c1692a932c32d5449443c477a53d5112884roger xue    }
870217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
880217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    @Override
890217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    public void onCreate() {
900217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (DBG) {
910217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            Log.d(TAG, "onCreate");
920217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
930217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
940217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        mMessageMonitor = new MapMessageMonitor(this);
950217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        mDeviceMonitor = new MapDeviceMonitor();
960217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        connectToMap();
970217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    }
980217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
990217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    private void connectToMap() {
1000217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (DBG) {
1010217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            Log.d(TAG, "Connecting to MAP service");
1020217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
1030217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1040217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (adapter == null) {
1050217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            // This *should* never happen. Unless there's some severe internal error?
1060217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            Log.wtf(TAG, "BluetoothAdapter is null! Internal error?");
1070217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            return;
1080217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
1090217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
1100217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (!adapter.getProfileProxy(this, mMapServiceListener, BluetoothProfile.MAP_CLIENT)) {
1110217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            // This *should* never happen.  Unless arguments passed are incorrect somehow...
1120217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            Log.wtf(TAG, "Unable to get MAP profile! Possible programmer error?");
1130217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            return;
1140217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
1150217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    }
1160217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
1170217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    @Override
1180217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    public int onStartCommand(Intent intent, int flags, int startId) {
1190217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (DBG) {
1206f316f0069b6b8f162fd67b0b042a6c3676227d9Srinivas Visvanathan            Log.d(TAG, "Handling intent: " + intent);
1210217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
1220217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
1230217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        // Service will be restarted even if its killed/dies. It will never stop itself.
1240217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        // It may be restarted with null intent or one of the other intents e.g. REPLY, PLAY etc.
1250217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        final int result = START_STICKY;
1260217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
1270217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (intent == null || ACTION_START.equals(intent.getAction())) {
1280217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            // These are NO-OP's since they're just used to bring up this service.
1290217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            return result;
1300217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
1310217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
1320217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (!hasRequiredArgs(intent)) {
1330217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            return result;
1340217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
1350217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        switch (intent.getAction()) {
1360217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_AUTO_REPLY:
13722bc7d8f0b1a18737e951ff3352c089670cc7ab3Srinivas Visvanathan                boolean success;
1380217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                if (mMapClient != null) {
13922bc7d8f0b1a18737e951ff3352c089670cc7ab3Srinivas Visvanathan                    success = mMessageMonitor.sendAutoReply(
140dc905655368f1847bd63e823804ce611086cc487Lujiang Xue                            intent.getParcelableExtra(EXTRA_SENDER_KEY),
141dc905655368f1847bd63e823804ce611086cc487Lujiang Xue                            mMapClient,
142dc905655368f1847bd63e823804ce611086cc487Lujiang Xue                            intent.getStringExtra(EXTRA_REPLY_MESSAGE));
1430217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                } else {
1440217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                    Log.e(TAG, "Unable to send reply; MAP profile disconnected!");
14522bc7d8f0b1a18737e951ff3352c089670cc7ab3Srinivas Visvanathan                    success = false;
1460217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                }
14722bc7d8f0b1a18737e951ff3352c089670cc7ab3Srinivas Visvanathan                if (!success) {
1480217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                    Toast.makeText(this, R.string.auto_reply_failed_message, Toast.LENGTH_SHORT)
1490217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                            .show();
1500217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                }
1510217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                break;
1520217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_PLAY_MESSAGES:
1530217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                mMessageMonitor.playMessages(intent.getParcelableExtra(EXTRA_SENDER_KEY));
1540217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                break;
1554a5024d82db356bc7c6e0848c80f4f0d7e213a0eSrinivas Visvanathan            case ACTION_MUTE_CONVERSATION:
1561d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue                mMessageMonitor.toggleMuteConversation(
1571d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue                        intent.getParcelableExtra(EXTRA_SENDER_KEY), true);
1581d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue                break;
1591d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue            case ACTION_UNMUTE_CONVERSATION:
1601d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue                mMessageMonitor.toggleMuteConversation(
1611d3c7eb3eb086dcb452f492867e30121535a9465Lujiang Xue                        intent.getParcelableExtra(EXTRA_SENDER_KEY), false);
1624a5024d82db356bc7c6e0848c80f4f0d7e213a0eSrinivas Visvanathan                break;
1630217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_STOP_PLAYOUT:
1640217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                mMessageMonitor.stopPlayout();
1650217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                break;
1660217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_CLEAR_NOTIFICATION_STATE:
1670217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                mMessageMonitor.clearNotificationState(intent.getParcelableExtra(EXTRA_SENDER_KEY));
1680217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                break;
1690217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            default:
1700217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                Log.e(TAG, "Ignoring unknown intent: " + intent.getAction());
1710217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
1720217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        return result;
1730217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    }
1740217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
17560060c1692a932c32d5449443c477a53d5112884roger xue    /**
17660060c1692a932c32d5449443c477a53d5112884roger xue     * @return {code true} if the service is playing the TTS of the message.
17760060c1692a932c32d5449443c477a53d5112884roger xue     */
17860060c1692a932c32d5449443c477a53d5112884roger xue    public boolean isPlaying() {
17960060c1692a932c32d5449443c477a53d5112884roger xue        return mMessageMonitor.isPlaying();
18060060c1692a932c32d5449443c477a53d5112884roger xue    }
18160060c1692a932c32d5449443c477a53d5112884roger xue
1820217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    private boolean hasRequiredArgs(Intent intent) {
1830217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        switch (intent.getAction()) {
1840217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_AUTO_REPLY:
1850217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_PLAY_MESSAGES:
1864a5024d82db356bc7c6e0848c80f4f0d7e213a0eSrinivas Visvanathan            case ACTION_MUTE_CONVERSATION:
1870217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_CLEAR_NOTIFICATION_STATE:
1880217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                if (!intent.hasExtra(EXTRA_SENDER_KEY)) {
1890217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                    Log.w(TAG, "Intent is missing sender-key extra: " + intent.getAction());
1900217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                    return false;
1910217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                }
1920217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                return true;
1930217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            case ACTION_STOP_PLAYOUT:
1940217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                // No args.
1950217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                return true;
1960217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            default:
1970217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                // For unknown actions, default to true. We'll report error on these later.
1980217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                return true;
1990217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2000217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    }
2010217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2020217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    @Override
2030217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    public void onDestroy() {
2040217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (DBG) {
2050217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            Log.d(TAG, "onDestroy");
2060217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2070217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        if (mMapClient != null) {
2080217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            mMapClient.close();
2090217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2100217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        mDeviceMonitor.cleanup();
2110217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        mMessageMonitor.cleanup();
2120217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    }
2130217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2140217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    @Override
2150217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    public IBinder onBind(Intent intent) {
21660060c1692a932c32d5449443c477a53d5112884roger xue        return mBinder;
2170217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    }
2180217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2190217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    // NOTE: These callbacks are invoked on the main thread.
2200217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    private final BluetoothProfile.ServiceListener mMapServiceListener =
2210217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            new BluetoothProfile.ServiceListener() {
2220217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        @Override
2230217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        public void onServiceConnected(int profile, BluetoothProfile proxy) {
2240217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            mMapClient = (BluetoothMapClient) proxy;
2250217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            if (MessengerService.DBG) {
2260217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                Log.d(TAG, "Connected to MAP service!");
2270217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            }
2280217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2290217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            // Since we're connected, we will received broadcasts for any new messages
2300217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            // in the MapMessageMonitor.
2310217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2320217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2330217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        @Override
2340217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        public void onServiceDisconnected(int profile) {
2350217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            if (MessengerService.DBG) {
2360217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                Log.d(TAG, "Disconnected from MAP service!");
2370217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            }
2380217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            mMapClient = null;
2390217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            mMessageMonitor.handleMapDisconnect();
2400217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2410217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    };
2420217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2430217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    private class MapDeviceMonitor extends BroadcastReceiver {
2440217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        MapDeviceMonitor() {
2450217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            if (DBG) {
2460217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                Log.d(TAG, "Registering Map device monitor");
2470217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            }
2480217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            IntentFilter intentFilter = new IntentFilter();
2490217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            intentFilter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
2500217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            registerReceiver(this, intentFilter, android.Manifest.permission.BLUETOOTH, null);
2510217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2520217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2530217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        void cleanup() {
2540217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            unregisterReceiver(this);
2550217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2560217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan
2570217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        @Override
2580217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        public void onReceive(Context context, Intent intent) {
2590217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
2600217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            int previousState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
2610217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2620217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            if (state == -1 || previousState == -1 || device == null) {
2630217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                Log.w(TAG, "Skipping broadcast, missing required extra");
2640217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                return;
2650217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            }
2660217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            if (previousState == BluetoothProfile.STATE_CONNECTED
2670217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                    && state != BluetoothProfile.STATE_CONNECTED) {
2680217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                if (DBG) {
2690217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                    Log.d(TAG, "Device losing MAP connection: " + device);
2700217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                }
2710217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan                mMessageMonitor.handleDeviceDisconnect(device);
2720217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan            }
2730217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan        }
2740217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan    }
2750217b09b25c8a2cb0408790979eff327aec42d45Srinivas Visvanathan}
276