audio: route audio to bluetooth when possible
Change-Id: I2a446e8fb8114b036ee85c463c387ee2a42bd7f4
Tuleap: #1407
diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
index 20b4140..3e3c64b 100755
--- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
+++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
@@ -50,7 +50,6 @@
import cx.ring.services.PresenceService;
import cx.ring.services.SharedPreferencesServiceImpl;
import cx.ring.utils.Log;
-import cx.ring.utils.MediaManager;
import dagger.Module;
import dagger.Provides;
@@ -192,10 +191,4 @@
ScheduledExecutorService provideScheduledExecutorService() {
return Executors.newSingleThreadScheduledExecutor();
}
-
- @Provides
- @Singleton
- MediaManager provideMediaManager(Context context) {
- return new MediaManager(context);
- }
}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
index d647376..2b4dd45 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
@@ -124,7 +124,6 @@
private MenuItem dialPadBtn = null;
private MenuItem changeScreenOrientationBtn = null;
- // Screen wake lock for incoming call
private PowerManager.WakeLock mScreenWakeLock;
private DisplayManager.DisplayListener displayListener;
diff --git a/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java
index 4e4fd57..ecffda9 100644
--- a/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java
+++ b/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java
@@ -43,11 +43,13 @@
import cx.ring.daemon.StringVect;
import cx.ring.service.OpenSlParams;
import cx.ring.utils.Log;
-import cx.ring.utils.MediaManager;
import cx.ring.utils.NetworkUtils;
import cx.ring.utils.StringUtils;
-public class DeviceRuntimeServiceImpl extends DeviceRuntimeService {
+import cx.ring.utils.Ringer;
+import cx.ring.utils.BluetoothWrapper;
+
+public class DeviceRuntimeServiceImpl extends DeviceRuntimeService implements AudioManager.OnAudioFocusChangeListener, BluetoothWrapper.BluetoothChangeListener {
private static final String TAG = DeviceRuntimeServiceImpl.class.getName();
private static final String[] PROFILE_PROJECTION = new String[]{ContactsContract.Profile._ID,
@@ -61,13 +63,17 @@
@Inject
protected Context mContext;
- @Inject
- protected MediaManager mediaManager;
-
private long mDaemonThreadId = -1;
+ private Ringer mRinger;
+ private AudioManager mAudioManager;
+ private BluetoothWrapper mBluetoothWrapper;
+
@Override
public void loadNativeLibrary() {
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mRinger = new Ringer(mContext);
+
Future<Boolean> result = mExecutor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
@@ -97,13 +103,20 @@
mainHandler.post(new Runnable() {
@Override
public void run() {
- mediaManager.obtainAudioFocus(isRinging);
+ if (mBluetoothWrapper == null) {
+ mBluetoothWrapper = new BluetoothWrapper(mContext);
+ mBluetoothWrapper.registerScoUpdate();
+ mBluetoothWrapper.registerBtConnection();
+ mBluetoothWrapper.setBluetoothChangeListener(DeviceRuntimeServiceImpl.this);
+ }
+
+ obtainAudioFocus(isRinging);
if (isRinging) {
- mediaManager.audioManager.setMode(AudioManager.MODE_RINGTONE);
- mediaManager.startRing();
+ mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+ startRinging();
} else {
- mediaManager.stopRing();
- mediaManager.audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
+ stopRinging();
+ mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
}
});
@@ -111,8 +124,8 @@
@Override
public void closeAudioState() {
- mediaManager.stopRing();
- mediaManager.abandonAudioFocus();
+ stopRinging();
+ abandonAudioFocus();
}
@Override
@@ -185,7 +198,6 @@
return ContextCompat.checkSelfPermission(mContext, permission) == PackageManager.PERMISSION_GRANTED;
}
-
@Override
public void getHardwareAudioFormat(IntVect ret) {
OpenSlParams audioParams = OpenSlParams.createInstance(mContext);
@@ -223,4 +235,111 @@
ret.add(StringUtils.capitalize(manufacturer) + " " + model);
}
}
+
+ @Override
+ public void startRinging() {
+ mRinger.ring();
+ }
+
+ @Override
+ public boolean isSpeakerOn() {
+ return mAudioManager.isSpeakerphoneOn();
+ }
+
+ @Override
+ public void stopRinging() {
+ mRinger.stopRing();
+ }
+
+ @Override
+ public void onAudioFocusChange(int arg0) {
+ Log.i(TAG, "onAudioFocusChange " + arg0);
+ }
+
+ @Override
+ public void abandonAudioFocus() {
+ mAudioManager.abandonAudioFocus(this);
+ if (mAudioManager.isSpeakerphoneOn()) {
+ mAudioManager.setSpeakerphoneOn(false);
+ }
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+
+ if (mBluetoothWrapper != null) {
+ mBluetoothWrapper.unregister();
+ mBluetoothWrapper.setBluetoothOn(false);
+ mBluetoothWrapper = null;
+ }
+ }
+
+ @Override
+ public void obtainAudioFocus(boolean requestSpeakerOn) {
+
+ mAudioManager.requestAudioFocus(this, getInCallStream(mAudioManager.isBluetoothA2dpOn()), AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+
+ if (mBluetoothWrapper != null && mBluetoothWrapper.canBluetooth()) {
+ Log.d(TAG, "Try to enable bluetooth");
+ mBluetoothWrapper.setBluetoothOn(true);
+ } else if (!mAudioManager.isWiredHeadsetOn()) {
+ mAudioManager.setSpeakerphoneOn(requestSpeakerOn);
+ }
+ }
+
+ @Override
+ public void switchAudioToCurrentMode() {
+ mRinger.stopRing();
+ if (mBluetoothWrapper != null && mBluetoothWrapper.canBluetooth()) {
+ routeToBTHeadset();
+ } else {
+ mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
+ }
+ }
+
+ private void routeToBTHeadset() {
+ Log.d(TAG, "Try to enable bluetooth");
+ mAudioManager.setSpeakerphoneOn(false);
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ mBluetoothWrapper.setBluetoothOn(true);
+ mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
+ }
+
+ @Override
+ public void toggleSpeakerphone() {
+ if (mAudioManager.isSpeakerphoneOn()) {
+ mAudioManager.setSpeakerphoneOn(!mAudioManager.isSpeakerphoneOn());
+ if (mBluetoothWrapper != null && mBluetoothWrapper.canBluetooth()) {
+ routeToBTHeadset();
+ }
+ } else {
+ mAudioManager.setSpeakerphoneOn(true);
+ }
+ }
+
+ @Override
+ public void onBluetoothStateChanged(int status) {
+ Log.d(TAG, "bluetoothStateChanged to: " + status);
+ if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
+ routeToBTHeadset();
+ }
+ }
+
+ /**
+ * Get the stream id for in call track. Can differ on some devices. Current device for which it's different :
+ *
+ * @return
+ */
+ public static int getInCallStream(boolean requestBluetooth) {
+ /* Archos 5IT */
+ if (android.os.Build.BRAND.equalsIgnoreCase("archos") && android.os.Build.DEVICE.equalsIgnoreCase("g7a")) {
+ // Since archos has no voice call capabilities, voice call stream is
+ // not implemented
+ // So we have to choose the good stream tag, which is by default
+ // falled back to music
+ return AudioManager.STREAM_MUSIC;
+ }
+ if (requestBluetooth) {
+ return 6; /* STREAM_BLUETOOTH_SCO -- Thx @Stefan for the contrib */
+ }
+
+ return AudioManager.STREAM_VOICE_CALL;
+ }
}
diff --git a/ring-android/app/src/main/java/cx/ring/utils/BluetoothWrapper.java b/ring-android/app/src/main/java/cx/ring/utils/BluetoothWrapper.java
new file mode 100644
index 0000000..728c2fb
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/utils/BluetoothWrapper.java
@@ -0,0 +1,196 @@
+/**
+ * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
+ * This file is part of CSipSimple.
+ * <p>
+ * CSipSimple is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * If you own a pjsip commercial license you can also redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public License
+ * as an android library.
+ * <p>
+ * CSipSimple is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * <p>
+ * You should have received a copy of the GNU General Public License
+ * along with CSipSimple. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package cx.ring.utils;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.util.Log;
+
+import java.util.Set;
+
+
+public class BluetoothWrapper {
+
+ private static String TAG = BluetoothWrapper.class.getSimpleName();
+
+ protected Context mContext;
+ private AudioManager audioManager;
+ private boolean isBluetoothConnected = false;
+ private BluetoothAdapter bluetoothAdapter;
+ private boolean targetBt = false;
+
+ public interface BluetoothChangeListener {
+ void onBluetoothStateChanged(int status);
+ }
+
+ private BluetoothChangeListener btChangesListener;
+
+ public BluetoothWrapper(Context context) {
+ mContext = context;
+ audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ if (bluetoothAdapter == null) {
+ try {
+ bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Cant get default bluetooth adapter ", e);
+ }
+ }
+ }
+
+ public void setBluetoothChangeListener(BluetoothChangeListener listener) {
+ btChangesListener = listener;
+ }
+
+ public boolean isBTHeadsetConnected() {
+ return bluetoothAdapter != null && (bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET) == BluetoothAdapter.STATE_CONNECTED);
+ }
+
+ private BroadcastReceiver mediaStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, ">>> BT SCO state changed !!! ");
+ if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) {
+ int status = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_ERROR);
+ Log.d(TAG, "BT SCO state changed : " + status + " target is " + targetBt);
+ audioManager.setBluetoothScoOn(targetBt);
+
+ if (status == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
+ Log.d(TAG, "BT SCO state changed : CONNECTED");
+ isBluetoothConnected = true;
+ } else if (status == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
+ Log.d(TAG, "BT SCO state changed : DISCONNECTED");
+ isBluetoothConnected = false;
+ } else {
+ Log.d(TAG, "BT SCO state changed : " + status);
+ }
+ }
+ }
+ };
+
+ // Create a BroadcastReceiver for ACTION_FOUND.
+ private final BroadcastReceiver mBtReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "BT state changed");
+ String action = intent.getAction();
+ if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
+ int status = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0);
+ if (status == 2) {
+ Log.d(TAG, "BT device found");
+ // Discovery has found a device. Get the BluetoothDevice
+ // object and its info from the Intent.
+ if (btChangesListener != null) {
+ btChangesListener.onBluetoothStateChanged(status);
+ }
+ }
+ }
+ }
+ };
+
+
+ public boolean canBluetooth() {
+ // Detect if any bluetooth a device is available for call
+ if (bluetoothAdapter == null) {
+ // Device does not support Bluetooth
+ return false;
+ }
+ boolean hasConnectedDevice = false;
+ //If bluetooth is on
+ if (bluetoothAdapter.isEnabled()) {
+
+ //We get all bounded bluetooth devices
+ // bounded is not enough, should search for connected devices....
+ Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
+ for (BluetoothDevice device : pairedDevices) {
+ BluetoothClass bluetoothClass = device.getBluetoothClass();
+ if (bluetoothClass != null) {
+ int deviceClass = bluetoothClass.getDeviceClass();
+ if (bluetoothClass.hasService(BluetoothClass.Service.RENDER) ||
+ deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET ||
+ deviceClass == BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO ||
+ deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE) {
+ //And if any can be used as a audio handset
+ hasConnectedDevice = true;
+ break;
+ }
+ }
+ }
+ }
+ boolean retVal = hasConnectedDevice && audioManager.isBluetoothScoAvailableOffCall();
+ Log.d(TAG, "Can I do BT ? " + retVal);
+ return retVal;
+ }
+
+ public void setBluetoothOn(boolean on) {
+ Log.d(TAG, "Try to turn BT " + on);
+ cx.ring.utils.Log.i(TAG, "mAudioManager.isBluetoothA2dpOn():" + audioManager.isBluetoothA2dpOn());
+ cx.ring.utils.Log.i(TAG, "mAudioManager.isBluetoothscoOn():" + audioManager.isBluetoothScoOn());
+
+ targetBt = on;
+ if (on != isBluetoothConnected) {
+ // BT SCO connection state is different from required activation
+ if (on) {
+ // First we try to connect
+ Log.d(TAG, "BT SCO on >>>");
+ audioManager.startBluetoothSco();
+ } else {
+ Log.d(TAG, "BT SCO off >>>");
+ // We stop to use BT SCO
+ audioManager.setBluetoothScoOn(false);
+ // And we stop BT SCO connection
+ audioManager.stopBluetoothSco();
+ }
+ } else if (on != audioManager.isBluetoothScoOn()) {
+ // BT SCO is already in desired connection state
+ // we only have to use it
+ audioManager.setBluetoothScoOn(on);
+ }
+ }
+
+ public void registerScoUpdate() {
+ Log.d(TAG, "Register BT media receiver");
+ mContext.registerReceiver(mediaStateReceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
+ }
+
+ public void registerBtConnection() {
+ Log.d(TAG, "Register BT connection");
+ mContext.registerReceiver(mBtReceiver, new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED));
+ }
+
+ public void unregister() {
+ try {
+ Log.d(TAG, "Unregister BT media receiver");
+ mContext.unregisterReceiver(mediaStateReceiver);
+ mContext.unregisterReceiver(mBtReceiver);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to unregister media state receiver", e);
+ }
+ }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/utils/Compatibility.java b/ring-android/app/src/main/java/cx/ring/utils/Compatibility.java
deleted file mode 100644
index e3fa24b..0000000
--- a/ring-android/app/src/main/java/cx/ring/utils/Compatibility.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
- * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
- *
- * Author: Regis Montoya <r3gis.3R@gmail.com>
- * Alexandre Lision <alexandre.lision@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Additional permission under GNU GPL version 3 section 7:
- *
- * If you modify this program, or any covered work, by linking or
- * combining it with the OpenSSL project's OpenSSL library (or a
- * modified version of that library), containing parts covered by the
- * terms of the OpenSSL or SSLeay licenses, Savoir-faire Linux Inc.
- * grants you additional permission to convey the resulting work.
- * Corresponding Source for a non-source form of such a combination
- * shall include the source code for the parts of OpenSSL used as well
- * as that of the covered work.
- */
-
-package cx.ring.utils;
-
-import android.media.AudioManager;
-
-@SuppressWarnings("deprecation")
-public final class Compatibility {
-
- private Compatibility() {
- }
-
- /**
- * Get the stream id for in call track. Can differ on some devices. Current device for which it's different :
- *
- * @return
- */
- public static int getInCallStream(boolean requestBluetooth) {
- /* Archos 5IT */
- if (android.os.Build.BRAND.equalsIgnoreCase("archos") && android.os.Build.DEVICE.equalsIgnoreCase("g7a")) {
- // Since archos has no voice call capabilities, voice call stream is
- // not implemented
- // So we have to choose the good stream tag, which is by default
- // falled back to music
- return AudioManager.STREAM_MUSIC;
- }
- if (requestBluetooth) {
- return 6; /* STREAM_BLUETOOTH_SCO -- Thx @Stefan for the contrib */
- }
-
- // return AudioManager.STREAM_MUSIC;
- return AudioManager.STREAM_VOICE_CALL;
- }
-
-// --Commented out by Inspection START (17-05-08 17:51):
-// private static boolean needToneWorkaround() {
-// return android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i5800") || android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i5801")
-// || android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i9003");
-// }
-// --Commented out by Inspection STOP (17-05-08 17:51)
-
-}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java b/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
deleted file mode 100644
index 5408792..0000000
--- a/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
- *
- * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
- * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package cx.ring.utils;
-
-import android.content.Context;
-import android.media.AudioManager;
-import android.media.AudioManager.OnAudioFocusChangeListener;
-import android.os.Handler;
-import android.util.Log;
-import cx.ring.utils.bluetooth.BluetoothWrapper;
-
-public class MediaManager implements OnAudioFocusChangeListener, BluetoothWrapper.BluetoothChangeListener {
-
- private static final String TAG = MediaManager.class.getSimpleName();
- public final AudioManager audioManager;
- private final Ringer ringer;
-
- public MediaManager(Context c) {
- audioManager = (AudioManager) c.getSystemService(Context.AUDIO_SERVICE);
-
- ringer = new Ringer(c);
- }
-
- public void obtainAudioFocus(boolean requestSpeakerOn) {
- audioManager.requestAudioFocus(this, Compatibility.getInCallStream(false), AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- if (!audioManager.isWiredHeadsetOn()){
- audioManager.setSpeakerphoneOn(requestSpeakerOn);
- }
- }
-
- @Override
- public void onAudioFocusChange(int arg0) {
- Log.i(TAG, "onAudioFocusChange " + arg0);
- }
-
- public void abandonAudioFocus() {
- audioManager.abandonAudioFocus(this);
- if (audioManager.isSpeakerphoneOn()) {
- audioManager.setSpeakerphoneOn(false);
- }
- audioManager.setMode(AudioManager.MODE_NORMAL);
- }
-
- /**5
- * Start ringing announce for a given contact.
- * It will also focus audio for us.
- */
- synchronized public void startRing() {
- ringer.ring();
- }
-
- /**
- * Stop all ringing. <br/>
- * Warning, this will not unfocus audio.
- */
- synchronized public void stopRing() {
- ringer.stopRing();
- }
-
- @Override
- public void onBluetoothStateChanged(int status) {
- }
-
-}
diff --git a/ring-android/app/src/main/java/cx/ring/utils/Ringer.java b/ring-android/app/src/main/java/cx/ring/utils/Ringer.java
index ef3ef9f..2b01491 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/Ringer.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/Ringer.java
@@ -63,15 +63,13 @@
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
//No ring no vibrate
Log.d(TAG, "skipping ring and vibrate because profile is Silent");
- }
- else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE || ringerMode == AudioManager.RINGER_MODE_NORMAL) {
+ } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE || ringerMode == AudioManager.RINGER_MODE_NORMAL) {
// Vibrate
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
vibrator.vibrate(VIBRATE_PATTERN, 0, VIBRATE_ATTRIBUTES);
} else {
vibrator.vibrate(VIBRATE_PATTERN, 0);
}
- audioManager.setMode(AudioManager.MODE_RINGTONE);
}
}
diff --git a/ring-android/app/src/main/java/cx/ring/utils/bluetooth/BluetoothUtils14.java b/ring-android/app/src/main/java/cx/ring/utils/bluetooth/BluetoothUtils14.java
deleted file mode 100644
index c378347..0000000
--- a/ring-android/app/src/main/java/cx/ring/utils/bluetooth/BluetoothUtils14.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
- * This file is part of CSipSimple.
- *
- * CSipSimple is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * If you own a pjsip commercial license you can also redistribute it
- * and/or modify it under the terms of the GNU Lesser General Public License
- * as an android library.
- *
- * CSipSimple is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with CSipSimple. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package cx.ring.utils.bluetooth;
-
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.util.Log;
-
-import java.util.Set;
-
-public class BluetoothUtils14 extends BluetoothWrapper {
-
- private static String TAG = BluetoothUtils14.class.getSimpleName();
- private AudioManager audioManager;
- private boolean isBluetoothConnected = false;
-
-
- @Override
- public boolean isBTHeadsetConnected() {
- return bluetoothAdapter != null && (bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET) == BluetoothAdapter.STATE_CONNECTED);
- }
-
-
-
- private BroadcastReceiver mediaStateReceiver = new BroadcastReceiver() {
-
- @SuppressWarnings("deprecation")
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- Log.d(TAG, ">>> BT SCO state changed !!! ");
- if(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(action)) {
- int status = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_ERROR );
- Log.d(TAG, "BT SCO state changed : " + status + " target is " + targetBt);
- audioManager.setBluetoothScoOn(targetBt);
-
- if(status == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
- isBluetoothConnected = true;
- }else if(status == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
- isBluetoothConnected = false;
- }
-
- if(btChangesListener != null) {
- btChangesListener.onBluetoothStateChanged(status);
- }
- }
- }
- };
-
- protected BluetoothAdapter bluetoothAdapter;
-
- @Override
- public void setContext(Context aContext){
- super.setContext(aContext);
- audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- if(bluetoothAdapter == null) {
- try {
- bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- }catch(RuntimeException e) {
- Log.w(TAG, "Cant get default bluetooth adapter ", e);
- }
- }
- }
-
- public boolean canBluetooth() {
- // Detect if any bluetooth a device is available for call
- if (bluetoothAdapter == null) {
- // Device does not support Bluetooth
- return false;
- }
- boolean hasConnectedDevice = false;
- //If bluetooth is on
- if(bluetoothAdapter.isEnabled()) {
-
- //We get all bounded bluetooth devices
- // bounded is not enough, should search for connected devices....
- Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
- for(BluetoothDevice device : pairedDevices) {
- BluetoothClass bluetoothClass = device.getBluetoothClass();
- if (bluetoothClass != null) {
- int deviceClass = bluetoothClass.getDeviceClass();
- if(bluetoothClass.hasService(BluetoothClass.Service.RENDER) ||
- deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET ||
- deviceClass == BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO ||
- deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE ) {
- //And if any can be used as a audio handset
- hasConnectedDevice = true;
- break;
- }
- }
- }
- }
- boolean retVal = hasConnectedDevice && audioManager.isBluetoothScoAvailableOffCall();
- Log.d(TAG, "Can I do BT ? "+retVal);
- return retVal;
- }
-
- private boolean targetBt = false;
- public void setBluetoothOn(boolean on) {
- Log.d(TAG, "Ask for "+on+" vs "+audioManager.isBluetoothScoOn());
- targetBt = on;
- if(on != isBluetoothConnected) {
- // BT SCO connection state is different from required activation
- if(on) {
- // First we try to connect
- Log.d(TAG, "BT SCO on >>>");
- audioManager.startBluetoothSco();
- }else {
- Log.d(TAG, "BT SCO off >>>");
- // We stop to use BT SCO
- audioManager.setBluetoothScoOn(false);
- // And we stop BT SCO connection
- audioManager.stopBluetoothSco();
- }
- }else if(on != audioManager.isBluetoothScoOn()) {
- // BT SCO is already in desired connection state
- // we only have to use it
- audioManager.setBluetoothScoOn(on);
- }
- }
-
- public boolean isBluetoothOn() {
- return isBluetoothConnected;
- }
-
- @SuppressWarnings("deprecation")
- public void register() {
- Log.d(TAG, "Register BT media receiver");
- context.registerReceiver(mediaStateReceiver , new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
- }
-
- public void unregister() {
- try {
- Log.d(TAG, "Unregister BT media receiver");
- context.unregisterReceiver(mediaStateReceiver);
- }catch(Exception e) {
- Log.w(TAG, "Failed to unregister media state receiver",e);
- }
- }
-}
diff --git a/ring-android/app/src/main/java/cx/ring/utils/bluetooth/BluetoothWrapper.java b/ring-android/app/src/main/java/cx/ring/utils/bluetooth/BluetoothWrapper.java
deleted file mode 100644
index 053db85..0000000
--- a/ring-android/app/src/main/java/cx/ring/utils/bluetooth/BluetoothWrapper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
- * This file is part of CSipSimple.
- *
- * CSipSimple is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * If you own a pjsip commercial license you can also redistribute it
- * and/or modify it under the terms of the GNU Lesser General Public License
- * as an android library.
- *
- * CSipSimple is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with CSipSimple. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package cx.ring.utils.bluetooth;
-
-import android.content.Context;
-
-
-public abstract class BluetoothWrapper {
-
- public interface BluetoothChangeListener {
- void onBluetoothStateChanged(int status);
- }
-
-
- private static BluetoothWrapper instance;
- protected Context context;
-
- protected BluetoothChangeListener btChangesListener;
-
- public static BluetoothWrapper getInstance(Context context) {
- if (instance == null) {
- instance = new BluetoothUtils14();
- instance.setContext(context);
- }
-
- return instance;
- }
-
- protected BluetoothWrapper() {
- }
-
- protected void setContext(Context ctxt) {
- context = ctxt;
- }
-
- public void setBluetoothChangeListener(BluetoothChangeListener l) {
- btChangesListener = l;
- }
-
- public abstract boolean canBluetooth();
-
- public abstract void setBluetoothOn(boolean on);
-
- public abstract boolean isBluetoothOn();
-
- public abstract void register();
-
- public abstract void unregister();
-
- public abstract boolean isBTHeadsetConnected();
-}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
index e2630f2..98d4bea 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
@@ -214,6 +214,9 @@
}
public void videoSurfaceCreated(Object holder) {
+ if (mSipCall == null) {
+ return;
+ }
mHardwareService.addVideoSurface(mSipCall.getCallId(), holder);
getView().displayContactBubble(false);
}
@@ -249,6 +252,7 @@
private void finish() {
if (mSipCall != null) {
+ mCallService.hangUp(mSipCall.getCallId());
mNotificationService.cancelCallNotification(mSipCall.getCallId().hashCode());
}
if (executor != null && !executor.isShutdown()) {
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/DeviceRuntimeService.java b/ring-android/libringclient/src/main/java/cx/ring/services/DeviceRuntimeService.java
index c13dfcf..405b928 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/DeviceRuntimeService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/DeviceRuntimeService.java
@@ -55,4 +55,17 @@
public abstract String getProfileName();
+ public abstract void startRinging();
+
+ public abstract boolean isSpeakerOn();
+
+ public abstract void stopRinging();
+
+ public abstract void abandonAudioFocus();
+
+ public abstract void obtainAudioFocus(boolean requesSpeakerOn);
+
+ public abstract void switchAudioToCurrentMode();
+
+ public abstract void toggleSpeakerphone();
}