summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorPraveen Bharathi <pbharathi@motorola.com>2010-10-06 15:23:14 -0500
committerEric Laurent <elaurent@google.com>2010-11-01 18:41:19 -0700
commit21e941bf43362ddc6639a9f2d0828053360f53d7 (patch)
tree686b10bd26b899198a744c6e38d4ffa6585714b7 /services
parent879ed85598800bd2d87b7fe96d0a763d9b954a6e (diff)
downloadframeworks_base-21e941bf43362ddc6639a9f2d0828053360f53d7.zip
frameworks_base-21e941bf43362ddc6639a9f2d0828053360f53d7.tar.gz
frameworks_base-21e941bf43362ddc6639a9f2d0828053360f53d7.tar.bz2
Added support for dock headset observer
Change-Id: I06b2e65e3bfa10735e6c7fd3349afa9ae7d45292 Signed-off-by: Praveen Bharathi <pbharathi@motorola.com>
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioPolicyManagerBase.cpp22
-rw-r--r--services/java/com/android/server/DockObserver.java9
-rw-r--r--services/java/com/android/server/HeadsetObserver.java183
-rw-r--r--services/java/com/android/server/SystemServer.java18
-rw-r--r--services/java/com/android/server/WiredAccessoryObserver.java258
5 files changed, 292 insertions, 198 deletions
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 65d9ef7..86d4c9f 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -356,7 +356,9 @@ void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSyst
break;
case AudioSystem::FOR_MEDIA:
if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
- config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE) {
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE) {
LOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
return;
}
@@ -372,7 +374,10 @@ void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSyst
break;
case AudioSystem::FOR_DOCK:
if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
- config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) {
+ config != AudioSystem::FORCE_BT_DESK_DOCK &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK) {
LOGW("setForceUse() invalid config %d for FOR_DOCK", config);
}
forceVolumeReeval = true;
@@ -1366,6 +1371,7 @@ status_t AudioPolicyManagerBase::handleA2dpDisconnection(AudioSystem::audio_devi
void AudioPolicyManagerBase::closeA2dpOutputs()
{
+
LOGV("setDeviceConnectionState() closing A2DP and duplicated output!");
if (mDuplicatedOutput != 0) {
@@ -1558,6 +1564,8 @@ uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
if (device) break;
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
#ifdef WITH_A2DP
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (mPhoneState != AudioSystem::MODE_IN_CALL) {
@@ -1617,6 +1625,12 @@ uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
}
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
#ifdef WITH_A2DP
if (mA2dpOutput != 0) {
if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) {
@@ -1797,7 +1811,9 @@ float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_hand
(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AudioSystem::DEVICE_OUT_WIRED_HEADSET |
- AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
+ AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
+ AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) &&
(getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) &&
streamDesc.mCanBeMuted) {
volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index bee8872..f993093 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -103,7 +103,6 @@ class DockObserver extends UEventObserver {
FileReader file = new FileReader(DOCK_STATE_PATH);
int len = file.read(buffer, 0, 1024);
mPreviousDockState = mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
-
} catch (FileNotFoundException e) {
Slog.w(TAG, "This kernel does not have dock station support");
} catch (Exception e) {
@@ -158,13 +157,17 @@ class DockObserver extends UEventObserver {
{
String whichSound = null;
if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+ (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+ (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
whichSound = Settings.System.DESK_UNDOCK_SOUND;
} else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
whichSound = Settings.System.CAR_UNDOCK_SOUND;
}
} else {
- if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+ (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+ (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
whichSound = Settings.System.DESK_DOCK_SOUND;
} else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
whichSound = Settings.System.CAR_DOCK_SOUND;
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
deleted file mode 100644
index 6f0a91d..0000000
--- a/services/java/com/android/server/HeadsetObserver.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.ActivityManagerNative;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.UEventObserver;
-import android.util.Slog;
-import android.media.AudioManager;
-
-import java.io.FileReader;
-import java.io.FileNotFoundException;
-
-/**
- * <p>HeadsetObserver monitors for a wired headset.
- */
-class HeadsetObserver extends UEventObserver {
- private static final String TAG = HeadsetObserver.class.getSimpleName();
- private static final boolean LOG = true;
-
- private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/h2w";
- private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
- private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name";
-
- private static final int BIT_HEADSET = (1 << 0);
- private static final int BIT_HEADSET_NO_MIC = (1 << 1);
- private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC);
- private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
-
- private int mHeadsetState;
- private int mPrevHeadsetState;
- private String mHeadsetName;
-
- private final Context mContext;
- private final WakeLock mWakeLock; // held while there is a pending route change
-
- public HeadsetObserver(Context context) {
- mContext = context;
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetObserver");
- mWakeLock.setReferenceCounted(false);
-
- startObserving(HEADSET_UEVENT_MATCH);
-
- init(); // set initial status
- }
-
- @Override
- public void onUEvent(UEventObserver.UEvent event) {
- if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
-
- try {
- update(event.get("SWITCH_NAME"), Integer.parseInt(event.get("SWITCH_STATE")));
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Could not parse switch state from event " + event);
- }
- }
-
- private synchronized final void init() {
- char[] buffer = new char[1024];
-
- String newName = mHeadsetName;
- int newState = mHeadsetState;
- mPrevHeadsetState = mHeadsetState;
- try {
- FileReader file = new FileReader(HEADSET_STATE_PATH);
- int len = file.read(buffer, 0, 1024);
- newState = Integer.valueOf((new String(buffer, 0, len)).trim());
-
- file = new FileReader(HEADSET_NAME_PATH);
- len = file.read(buffer, 0, 1024);
- newName = new String(buffer, 0, len).trim();
-
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "This kernel does not have wired headset support");
- } catch (Exception e) {
- Slog.e(TAG, "" , e);
- }
-
- update(newName, newState);
- }
-
- private synchronized final void update(String newName, int newState) {
- // Retain only relevant bits
- int headsetState = newState & SUPPORTED_HEADSETS;
- int newOrOld = headsetState | mHeadsetState;
- int delay = 0;
- // reject all suspect transitions: only accept state changes from:
- // - a: 0 heaset to 1 headset
- // - b: 1 headset to 0 headset
- if (mHeadsetState == headsetState || ((newOrOld & (newOrOld - 1)) != 0)) {
- return;
- }
-
- mHeadsetName = newName;
- mPrevHeadsetState = mHeadsetState;
- mHeadsetState = headsetState;
-
- if (headsetState == 0) {
- Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
- // It can take hundreds of ms flush the audio pipeline after
- // apps pause audio playback, but audio route changes are
- // immediate, so delay the route change by 1000ms.
- // This could be improved once the audio sub-system provides an
- // interface to clear the audio pipeline.
- delay = 1000;
- } else {
- // Insert the same delay for headset connection so that the connection event is not
- // broadcast before the disconnection event in case of fast removal/insertion
- if (mHandler.hasMessages(0)) {
- delay = 1000;
- }
- }
- mWakeLock.acquire();
- mHandler.sendMessageDelayed(mHandler.obtainMessage(0,
- mHeadsetState,
- mPrevHeadsetState,
- mHeadsetName),
- delay);
- }
-
- private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) {
- int allHeadsets = SUPPORTED_HEADSETS;
- for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
- if ((curHeadset & allHeadsets) != 0) {
- sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName);
- allHeadsets &= ~curHeadset;
- }
- }
- }
-
- private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
- if ((headsetState & headset) != (prevHeadsetState & headset)) {
- // Pack up the values and broadcast them to everyone
- Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- int state = 0;
- int microphone = 0;
-
- if ((headset & HEADSETS_WITH_MIC) != 0) {
- microphone = 1;
- }
- if ((headsetState & headset) != 0) {
- state = 1;
- }
- intent.putExtra("state", state);
- intent.putExtra("name", headsetName);
- intent.putExtra("microphone", microphone);
-
- if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
- // TODO: Should we require a permission?
- ActivityManagerNative.broadcastStickyIntent(intent, null);
- }
- }
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- sendIntents(msg.arg1, msg.arg2, (String)msg.obj);
- mWakeLock.release();
- }
- };
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 237ab80..54f7441 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -121,7 +121,7 @@ class ServerThread extends Thread {
WindowManagerService wm = null;
BluetoothService bluetooth = null;
BluetoothA2dpService bluetoothA2dp = null;
- HeadsetObserver headset = null;
+ WiredAccessoryObserver wiredAccessory = null;
DockObserver dock = null;
UsbObserver usb = null;
UiModeManagerService uiMode = null;
@@ -388,14 +388,6 @@ class ServerThread extends Thread {
}
try {
- Slog.i(TAG, "Headset Observer");
- // Listen for wired headset changes
- headset = new HeadsetObserver(context);
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting HeadsetObserver", e);
- }
-
- try {
Slog.i(TAG, "Dock Observer");
// Listen for dock station changes
dock = new DockObserver(context, power);
@@ -404,6 +396,14 @@ class ServerThread extends Thread {
}
try {
+ Slog.i(TAG, "Wired Accessory Observer");
+ // Listen for wired headset changes
+ wiredAccessory = new WiredAccessoryObserver(context);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting WiredAccessoryObserver", e);
+ }
+
+ try {
Slog.i(TAG, "USB Observer");
// Listen for USB changes
usb = new UsbObserver(context);
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
new file mode 100644
index 0000000..ab92fdf
--- /dev/null
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.UEventObserver;
+import android.util.Slog;
+import android.media.AudioManager;
+import android.util.Log;
+
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+
+/**
+ * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock.
+ */
+class WiredAccessoryObserver extends UEventObserver {
+ private static final String TAG = WiredAccessoryObserver.class.getSimpleName();
+ private static final boolean LOG = true;
+ private static final int MAX_AUDIO_PORTS = 2; /* h2w & USB Audio */
+ private static final String uEventInfo[][] = { {"DEVPATH=/devices/virtual/switch/h2w",
+ "/sys/class/switch/h2w/state",
+ "/sys/class/switch/h2w/name"},
+ {"DEVPATH=/devices/virtual/switch/usb_audio",
+ "/sys/class/switch/usb_audio/state",
+ "/sys/class/switch/usb_audio/name"} };
+
+ private static final int BIT_HEADSET = (1 << 0);
+ private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+ private static final int BIT_USB_HEADSET_ANLG = (1 << 2);
+ private static final int BIT_USB_HEADSET_DGTL = (1 << 3);
+ private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+ BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL);
+ private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
+
+ private int mHeadsetState;
+ private int mPrevHeadsetState;
+ private String mHeadsetName;
+ private int switchState;
+
+ private final Context mContext;
+ private final WakeLock mWakeLock; // held while there is a pending route change
+
+ public WiredAccessoryObserver(Context context) {
+ mContext = context;
+ PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver");
+ mWakeLock.setReferenceCounted(false);
+
+ // At any given time both headsets could be inserted
+ // one on the board and one on the dock
+ // observe two UEVENTs
+ for (int i = 0; i <= MAX_AUDIO_PORTS; i++) {
+ startObserving(uEventInfo[i][0]);
+ }
+ init(); // set initial status
+ }
+
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
+
+ try {
+ if ((event.get("SWITCH_NAME")).equals("usb_audio")) {
+ if (Integer.parseInt(event.get("SWITCH_STATE")) == 1) {
+ switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+ BIT_USB_HEADSET_DGTL)) |
+ (Integer.parseInt(event.get("SWITCH_STATE")) << 2));
+ } else if (Integer.parseInt(event.get("SWITCH_STATE")) == 2) {
+ switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+ BIT_USB_HEADSET_ANLG)) |
+ (Integer.parseInt(event.get("SWITCH_STATE")) << 3));
+ }
+ else switchState = (mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC));
+ }
+ else {
+ switchState = ((mHeadsetState & (BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL)) |
+ (Integer.parseInt(event.get("SWITCH_STATE"))));
+ }
+ update(event.get("SWITCH_NAME"), switchState);
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Could not parse switch state from event " + event);
+ }
+ }
+
+ private synchronized final void init() {
+ char[] buffer = new char[1024];
+
+ String newName = mHeadsetName;
+ int newState = mHeadsetState;
+ mPrevHeadsetState = mHeadsetState;
+
+ for (int i = 0; i <= MAX_AUDIO_PORTS; i++) {
+ try {
+ FileReader file = new FileReader(uEventInfo[i][1]);
+ int len = file.read(buffer, 0, 1024);
+ newState = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+ file = new FileReader(uEventInfo[i][2]);
+ len = file.read(buffer, 0, 1024);
+ newName = new String(buffer, 0, len).trim();
+
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "This kernel does not have wired headset support");
+ } catch (Exception e) {
+ Slog.e(TAG, "" , e);
+ }
+
+ update(newName, newState);
+ }
+ }
+
+ private synchronized final void update(String newName, int newState) {
+ // Retain only relevant bits
+ int headsetState = newState & SUPPORTED_HEADSETS;
+ int newOrOld = headsetState | mHeadsetState;
+ int delay = 0;
+ int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
+ int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
+ int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC);
+ boolean h2wStateChange = true;
+ boolean usbStateChange = true;
+ // reject all suspect transitions: only accept state changes from:
+ // - a: 0 heaset to 1 headset
+ // - b: 1 headset to 0 headset
+ Log.v(TAG, "newState = "+newState+", headsetState = "+headsetState+", mHeadsetState = "+mHeadsetState);
+ if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) {
+ Log.e(TAG, "unsetting h2w flag");
+ h2wStateChange = false;
+ }
+ // - c: 0 usb headset to 1 usb headset
+ // - d: 1 usb headset to 0 usb headset
+ if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) {
+ Log.e(TAG, "unsetting usb flag");
+ usbStateChange = false;
+ }
+ if (!h2wStateChange && !usbStateChange) {
+ Log.e(TAG, "invalid transition, returning ...");
+ return;
+ }
+
+ mHeadsetName = newName;
+ mPrevHeadsetState = mHeadsetState;
+ mHeadsetState = headsetState;
+
+ if (headsetState == 0) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ // It can take hundreds of ms flush the audio pipeline after
+ // apps pause audio playback, but audio route changes are
+ // immediate, so delay the route change by 1000ms.
+ // This could be improved once the audio sub-system provides an
+ // interface to clear the audio pipeline.
+ delay = 1000;
+ } else {
+ // Insert the same delay for headset connection so that the connection event is not
+ // broadcast before the disconnection event in case of fast removal/insertion
+ if (mHandler.hasMessages(0)) {
+ delay = 1000;
+ }
+ }
+ mWakeLock.acquire();
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(0,
+ mHeadsetState,
+ mPrevHeadsetState,
+ mHeadsetName),
+ delay);
+ }
+
+ private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) {
+ int allHeadsets = SUPPORTED_HEADSETS;
+ for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
+ if ((curHeadset & allHeadsets) != 0) {
+ sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName);
+ allHeadsets &= ~curHeadset;
+ }
+ }
+ }
+
+ private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
+ if ((headsetState & headset) != (prevHeadsetState & headset)) {
+
+ int state = 0;
+ if ((headsetState & headset) != 0) {
+ state = 1;
+ }
+ if((headset == BIT_USB_HEADSET_ANLG) || (headset == BIT_USB_HEADSET_DGTL)) {
+ Intent intent;
+
+ // Pack up the values and broadcast them to everyone
+ if (headset == BIT_USB_HEADSET_ANLG) {
+ intent = new Intent(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra("state", state);
+ intent.putExtra("name", headsetName);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ } else if (headset == BIT_USB_HEADSET_DGTL) {
+ intent = new Intent(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra("state", state);
+ intent.putExtra("name", headsetName);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ }
+
+ if (LOG) Slog.v(TAG, "Intent.ACTION_USB_HEADSET_PLUG: state: "+state+" name: "+headsetName);
+ // TODO: Should we require a permission?
+ }
+ if((headset == BIT_HEADSET) || (headset == BIT_HEADSET_NO_MIC)) {
+
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ //int state = 0;
+ int microphone = 0;
+
+ if ((headset & HEADSETS_WITH_MIC) != 0) {
+ microphone = 1;
+ }
+
+ intent.putExtra("state", state);
+ intent.putExtra("name", headsetName);
+ intent.putExtra("microphone", microphone);
+
+ if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
+ // TODO: Should we require a permission?
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ }
+ }
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ sendIntents(msg.arg1, msg.arg2, (String)msg.obj);
+ mWakeLock.release();
+ }
+ };
+}