OSDN Git Service

b/2498180 b/2568119 Retry if BT dock disconnects unexpectedly
[android-x86/packages-apps-Settings.git] / src / com / android / settings / bluetooth / DockEventReceiver.java
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.settings.bluetooth;
18
19 import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
20
21 import android.app.Service;
22 import android.bluetooth.BluetoothA2dp;
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothHeadset;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.os.PowerManager;
31 import android.util.Log;
32
33 public class DockEventReceiver extends BroadcastReceiver {
34
35     private static final boolean DEBUG = DockService.DEBUG;
36
37     private static final String TAG = "DockEventReceiver";
38
39     public static final String ACTION_DOCK_SHOW_UI =
40         "com.android.settings.bluetooth.action.DOCK_SHOW_UI";
41
42     private static final int EXTRA_INVALID = -1234;
43
44     private static final Object mStartingServiceSync = new Object();
45
46     private static final long WAKELOCK_TIMEOUT = 5000;
47
48     private static PowerManager.WakeLock mStartingService;
49
50     @Override
51     public void onReceive(Context context, Intent intent) {
52         if (intent == null)
53             return;
54
55         int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, intent.getIntExtra(
56                 BluetoothAdapter.EXTRA_STATE, EXTRA_INVALID));
57         BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
58
59         if (DEBUG) {
60             Log.d(TAG, "Action: " + intent.getAction() + " State:" + state + " Device: "
61                     + (device == null ? "null" : device.getName()));
62         }
63
64         if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())
65                 || ACTION_DOCK_SHOW_UI.endsWith(intent.getAction())) {
66             if (device == null) {
67                 if (DEBUG) Log.d(TAG, "Device is missing");
68                 return;
69             }
70
71             switch (state) {
72                 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
73                 case Intent.EXTRA_DOCK_STATE_CAR:
74                 case Intent.EXTRA_DOCK_STATE_DESK:
75                     Intent i = new Intent(intent);
76                     i.setClass(context, DockService.class);
77                     beginStartingService(context, i);
78                     break;
79                 default:
80                     if (DEBUG) Log.e(TAG, "Unknown state");
81                     break;
82             }
83         } else if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) {
84             /*
85              *  Reconnect to the dock if:
86              *  1) it is a dock
87              *  2) it is disconnected
88              *  3) the disconnect is initiated remotely
89              *  4) the dock is still docked (check can only be done in the Service)
90              */
91             if (device == null) {
92                 if (DEBUG) Log.d(TAG, "Device is missing");
93                 return;
94             }
95
96             int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
97                     BluetoothHeadset.STATE_CONNECTED);
98             if (newState != BluetoothHeadset.STATE_DISCONNECTED) return;
99
100             int source = intent.getIntExtra(BluetoothHeadset.EXTRA_DISCONNECT_INITIATOR,
101                     BluetoothHeadset.LOCAL_DISCONNECT);
102             if (source != BluetoothHeadset.REMOTE_DISCONNECT) return;
103
104             // Too bad, the dock state can't be checked from a BroadcastReceiver.
105             Intent i = new Intent(intent);
106             i.setClass(context, DockService.class);
107             beginStartingService(context, i);
108
109         } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) {
110             /*
111              *  Reconnect to the dock if:
112              *  1) it is a dock
113              *  2) it is an unexpected disconnect i.e. didn't go through disconnecting state
114              *  3) the dock is still docked (check can only be done in the Service)
115              */
116             if (device == null) {
117                 if (DEBUG) Log.d(TAG, "Device is missing");
118                 return;
119             }
120
121             int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0);
122             int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, 0);
123             if (newState == BluetoothA2dp.STATE_DISCONNECTED &&
124                     oldState != BluetoothA2dp.STATE_DISCONNECTING) {
125                 // Too bad, the dock state can't be checked from a BroadcastReceiver.
126                 Intent i = new Intent(intent);
127                 i.setClass(context, DockService.class);
128                 beginStartingService(context, i);
129             }
130
131         } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
132             int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
133             if (btState != BluetoothAdapter.STATE_TURNING_ON) {
134                 Intent i = new Intent(intent);
135                 i.setClass(context, DockService.class);
136                 beginStartingService(context, i);
137             }
138         }
139     }
140
141     /**
142      * Start the service to process the current event notifications, acquiring
143      * the wake lock before returning to ensure that the service will run.
144      */
145     public static void beginStartingService(Context context, Intent intent) {
146         synchronized (mStartingServiceSync) {
147             if (mStartingService == null) {
148                 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
149                 mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
150                         "StartingDockService");
151             }
152
153             mStartingService.acquire(WAKELOCK_TIMEOUT);
154
155             if (context.startService(intent) == null) {
156                 Log.e(TAG, "Can't start DockService");
157             }
158         }
159     }
160
161     /**
162      * Called back by the service when it has finished processing notifications,
163      * releasing the wake lock if the service is now stopping.
164      */
165     public static void finishStartingService(Service service, int startId) {
166         synchronized (mStartingServiceSync) {
167             if (mStartingService != null) {
168                 if (DEBUG) Log.d(TAG, "stopSelf id = "+ startId);
169                 service.stopSelfResult(startId);
170             }
171         }
172     }
173 }