diff --git a/android/app/src/main/java/org/jitsi/meet/MainActivity.java b/android/app/src/main/java/org/jitsi/meet/MainActivity.java index 4ffefa3054..77abadcbca 100644 --- a/android/app/src/main/java/org/jitsi/meet/MainActivity.java +++ b/android/app/src/main/java/org/jitsi/meet/MainActivity.java @@ -23,7 +23,6 @@ import android.content.IntentFilter; import android.content.RestrictionEntry; import android.content.RestrictionsManager; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.util.Log; @@ -96,7 +95,7 @@ public class MainActivity extends JitsiMeetActivity { // In Debug builds React needs permission to write over other apps in // order to display the warning and error overlays. if (BuildConfig.DEBUG) { - if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) { + if (!Settings.canDrawOverlays(this)) { Intent intent = new Intent( Settings.ACTION_MANAGE_OVERLAY_PERMISSION, @@ -186,8 +185,7 @@ public class MainActivity extends JitsiMeetActivity { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE - && canRequestOverlayPermission()) { + if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE) { if (Settings.canDrawOverlays(this)) { initialize(); return; @@ -232,10 +230,4 @@ public class MainActivity extends JitsiMeetActivity { return null; } } - - private boolean canRequestOverlayPermission() { - return - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M; - } } diff --git a/android/build.gradle b/android/build.gradle index 37a917a89c..755d996123 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -144,7 +144,7 @@ allprojects { ext { buildToolsVersion = "29.0.3" compileSdkVersion = 29 - minSdkVersion = 21 + minSdkVersion = 23 targetSdkVersion = 29 supportLibVersion = "28.0.0" diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioDeviceHandlerGeneric.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioDeviceHandlerGeneric.java index b6e57342cd..1b8ab1622e 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioDeviceHandlerGeneric.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioDeviceHandlerGeneric.java @@ -16,11 +16,8 @@ package org.jitsi.meet.sdk; -import android.content.Context; import android.media.AudioDeviceInfo; import android.media.AudioManager; -import android.os.Build; -import androidx.annotation.RequiresApi; import java.util.HashSet; import java.util.Set; @@ -34,7 +31,6 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger; * default it's only used on versions < O, since versions >= O use ConnectionService, but it * can be disabled. */ -@RequiresApi(Build.VERSION_CODES.M) class AudioDeviceHandlerGeneric implements AudioModeModule.AudioDeviceHandlerInterface, AudioManager.OnAudioFocusChangeListener { diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioDeviceHandlerLegacy.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioDeviceHandlerLegacy.java deleted file mode 100644 index db43bed778..0000000000 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioDeviceHandlerLegacy.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright @ 2017-present 8x8, Inc. - * - * 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 org.jitsi.meet.sdk; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.media.AudioManager; - -import org.jitsi.meet.sdk.log.JitsiMeetLogger; - - -/** - * {@link AudioModeModule.AudioDeviceHandlerInterface} module implementing device handling for - * legacy (pre-M) Android versions. - */ -class AudioDeviceHandlerLegacy implements - AudioModeModule.AudioDeviceHandlerInterface, - AudioManager.OnAudioFocusChangeListener, - BluetoothHeadsetMonitor.Listener { - - private final static String TAG = AudioDeviceHandlerLegacy.class.getSimpleName(); - - /** - * Reference to the main {@code AudioModeModule}. - */ - private AudioModeModule module; - - /** - * Indicator that we have lost audio focus. - */ - private boolean audioFocusLost = false; - - /** - * {@link AudioManager} instance used to interact with the Android audio - * subsystem. - */ - private AudioManager audioManager; - - /** - * {@link BluetoothHeadsetMonitor} for detecting Bluetooth device changes in - * old (< M) Android versions. - */ - private BluetoothHeadsetMonitor bluetoothHeadsetMonitor; - - public AudioDeviceHandlerLegacy(AudioManager audioManager) { - this.audioManager = audioManager; - } - - /** - * Helper method to trigger an audio route update when Bluetooth devices are - * connected / disconnected. - */ - @Override - public void onBluetoothDeviceChange(final boolean deviceAvailable) { - module.runInAudioThread(new Runnable() { - @Override - public void run() { - if (deviceAvailable) { - module.addDevice(AudioModeModule.DEVICE_BLUETOOTH); - } else { - module.removeDevice(AudioModeModule.DEVICE_BLUETOOTH); - } - - module.updateAudioRoute(); - } - }); - } - - /** - * Helper method to trigger an audio route update when a headset is plugged - * or unplugged. - */ - private void onHeadsetDeviceChange() { - module.runInAudioThread(new Runnable() { - @Override - public void run() { - // XXX: isWiredHeadsetOn is not deprecated when used just for - // knowing if there is a wired headset connected, regardless of - // audio being routed to it. - //noinspection deprecation - if (audioManager.isWiredHeadsetOn()) { - module.addDevice(AudioModeModule.DEVICE_HEADPHONES); - } else { - module.removeDevice(AudioModeModule.DEVICE_HEADPHONES); - } - - module.updateAudioRoute(); - } - }); - } - - /** - * {@link AudioManager.OnAudioFocusChangeListener} interface method. Called - * when the audio focus of the system is updated. - * - * @param focusChange - The type of focus change. - */ - @Override - public void onAudioFocusChange(final int focusChange) { - module.runInAudioThread(new Runnable() { - @Override - public void run() { - switch (focusChange) { - case AudioManager.AUDIOFOCUS_GAIN: { - JitsiMeetLogger.d(TAG + " Audio focus gained"); - // Some other application potentially stole our audio focus - // temporarily. Restore our mode. - if (audioFocusLost) { - module.updateAudioRoute(); - } - audioFocusLost = false; - break; - } - case AudioManager.AUDIOFOCUS_LOSS: - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: { - JitsiMeetLogger.d(TAG + " Audio focus lost"); - audioFocusLost = true; - break; - } - } - } - }); - } - - /** - * Helper method to set the output route to a Bluetooth device. - * - * @param enabled true if Bluetooth should use used, false otherwise. - */ - private void setBluetoothAudioRoute(boolean enabled) { - if (enabled) { - audioManager.startBluetoothSco(); - audioManager.setBluetoothScoOn(true); - } else { - audioManager.setBluetoothScoOn(false); - audioManager.stopBluetoothSco(); - } - } - - @Override - public void start(AudioModeModule audioModeModule) { - JitsiMeetLogger.i("Using " + TAG + " as the audio device handler"); - - module = audioModeModule; - Context context = module.getContext(); - - // Setup runtime device change detection. - // - - // Detect changes in wired headset connections. - IntentFilter wiredHeadSetFilter = new IntentFilter(AudioManager.ACTION_HEADSET_PLUG); - BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - JitsiMeetLogger.d(TAG + " Wired headset added / removed"); - onHeadsetDeviceChange(); - } - }; - context.registerReceiver(wiredHeadsetReceiver, wiredHeadSetFilter); - - // Detect Bluetooth device changes. - bluetoothHeadsetMonitor = new BluetoothHeadsetMonitor(context, this); - - // On Android < M, detect if we have an earpiece. - PackageManager pm = context.getPackageManager(); - if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { - module.addDevice(AudioModeModule.DEVICE_EARPIECE); - } - - // Always assume there is a speaker. - module.addDevice(AudioModeModule.DEVICE_SPEAKER); - } - - @Override - public void stop() { - bluetoothHeadsetMonitor.stop(); - bluetoothHeadsetMonitor = null; - } - - @Override - public void setAudioRoute(String device) { - // Turn speaker on / off - audioManager.setSpeakerphoneOn(device.equals(AudioModeModule.DEVICE_SPEAKER)); - - // Turn bluetooth on / off - setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH)); - } - - @Override - public boolean setMode(int mode) { - if (mode == AudioModeModule.DEFAULT) { - audioFocusLost = false; - audioManager.setMode(AudioManager.MODE_NORMAL); - audioManager.abandonAudioFocus(this); - audioManager.setSpeakerphoneOn(false); - setBluetoothAudioRoute(false); - - return true; - } - - audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); - audioManager.setMicrophoneMute(false); - - if (audioManager.requestAudioFocus(this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN) - == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { - JitsiMeetLogger.w(TAG + " Audio focus request failed"); - return false; - } - - return true; - } -} diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java index 4be0f985c0..8cbecd71d6 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java @@ -222,10 +222,8 @@ class AudioModeModule extends ReactContextBaseJavaModule { if (useConnectionService()) { audioDeviceHandler = new AudioDeviceHandlerConnectionService(audioManager); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - audioDeviceHandler = new AudioDeviceHandlerGeneric(audioManager); } else { - audioDeviceHandler = new AudioDeviceHandlerLegacy(audioManager); + audioDeviceHandler = new AudioDeviceHandlerGeneric(audioManager); } audioDeviceHandler.start(this); @@ -427,15 +425,6 @@ class AudioModeModule extends ReactContextBaseJavaModule { } } - /** - * Needed on the legacy handler... - * - * @return Context for the application. - */ - Context getContext() { - return getReactApplicationContext(); - } - /** * Interface for the modules implementing the actual audio device management. */ diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/BluetoothHeadsetMonitor.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/BluetoothHeadsetMonitor.java deleted file mode 100644 index 7d713883df..0000000000 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/BluetoothHeadsetMonitor.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright @ 2017-present 8x8, Inc. - * - * 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 org.jitsi.meet.sdk; - -import android.bluetooth.BluetoothAdapter; -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 org.jitsi.meet.sdk.log.JitsiMeetLogger; - -/** - * Helper class to detect and handle Bluetooth device changes. It monitors - * Bluetooth headsets being connected / disconnected and notifies the module - * about device changes when this occurs. - */ -class BluetoothHeadsetMonitor { - private final static String TAG = BluetoothHeadsetMonitor.class.getSimpleName(); - - /** - * The {@link Context} in which this module executes. - */ - private final Context context; - - /** - * Reference to the {@link BluetoothAdapter} object, used to access Bluetooth functionality. - */ - private BluetoothAdapter adapter; - - /** - * Reference to a proxy object which allows us to query connected devices. - */ - private BluetoothHeadset headset; - - /** - * receiver registered for receiving Bluetooth connection state changes. - */ - private BroadcastReceiver receiver; - - /** - * Listener for receiving Bluetooth device change events. - */ - private Listener listener; - - public BluetoothHeadsetMonitor(Context context, Listener listener) { - this.context = context; - this.listener = listener; - } - - private boolean getBluetoothHeadsetProfileProxy() { - adapter = BluetoothAdapter.getDefaultAdapter(); - - if (adapter == null) { - JitsiMeetLogger.w(TAG + " Device doesn't support Bluetooth"); - return false; - } - - // XXX: The profile listener listens for system services of the given - // type being available to the application. That is, if our Bluetooth - // adapter has the "headset" profile. - BluetoothProfile.ServiceListener listener - = new BluetoothProfile.ServiceListener() { - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (profile == BluetoothProfile.HEADSET) { - headset = (BluetoothHeadset) proxy; - updateDevices(); - } - } - - @Override - public void onServiceDisconnected(int profile) { - // The logic is the same as the logic of onServiceConnected. - onServiceConnected(profile, /* proxy */ null); - } - }; - - return adapter.getProfileProxy(context, listener, BluetoothProfile.HEADSET); - } - - private void onBluetoothReceiverReceive(Context context, Intent intent) { - final String action = intent.getAction(); - - if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { - // XXX: This action will be fired when a Bluetooth headset is - // connected or disconnected to the system. This is not related to - // audio routing. - int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -99); - - switch (state) { - case BluetoothHeadset.STATE_CONNECTED: - case BluetoothHeadset.STATE_DISCONNECTED: - JitsiMeetLogger.d(TAG + " BT headset connection state changed: " + state); - updateDevices(); - break; - } - } else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) { - // XXX: This action will be fired when the connection established - // with a Bluetooth headset (called a SCO connection) changes state. - // When the SCO connection is active we route audio to it. - int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99); - - switch (state) { - case AudioManager.SCO_AUDIO_STATE_CONNECTED: - case AudioManager.SCO_AUDIO_STATE_DISCONNECTED: - JitsiMeetLogger.d(TAG + " BT SCO connection state changed: " + state); - updateDevices(); - break; - } - } - } - - private void registerBluetoothReceiver() { - receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - onBluetoothReceiverReceive(context, intent); - } - }; - - IntentFilter filter = new IntentFilter(); - filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); - filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); - - context.registerReceiver(receiver, filter); - } - - /** - * Detects if there are new devices connected / disconnected and fires the - * {@link Listener} registered event. - */ - private void updateDevices() { - boolean headsetAvailable = (headset != null) && !headset.getConnectedDevices().isEmpty(); - listener.onBluetoothDeviceChange(headsetAvailable); - } - - public void start() { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - - if (!audioManager.isBluetoothScoAvailableOffCall()) { - JitsiMeetLogger.w(TAG + " Bluetooth SCO is not available"); - return; - } - - if (!getBluetoothHeadsetProfileProxy()) { - JitsiMeetLogger.w(TAG + " Couldn't get BT profile proxy"); - return; - } - - registerBluetoothReceiver(); - - // Initial detection. - updateDevices(); - } - - public void stop() { - if (receiver != null) { - context.unregisterReceiver(receiver); - } - - if (adapter != null && headset != null) { - adapter.closeProfileProxy(BluetoothProfile.HEADSET, headset); - } - - receiver = null; - headset = null; - adapter = null; - } - - interface Listener { - void onBluetoothDeviceChange(boolean deviceAvailable); - } -} diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivityDelegate.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivityDelegate.java index 7b214320ab..1a1147f394 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivityDelegate.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivityDelegate.java @@ -1,6 +1,5 @@ /* - * Copyright @ 2019-present 8x8, Inc. - * Copyright @ 2018 Atlassian Pty Ltd + * Copyright @ 2018-present 8x8, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +16,8 @@ package org.jitsi.meet.sdk; -import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; -import android.os.Build; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.Callback; @@ -178,7 +175,6 @@ public class JitsiMeetActivityDelegate { }; } - @TargetApi(Build.VERSION_CODES.M) public static void requestPermissions(Activity activity, String[] permissions, int requestCode, PermissionListener listener) { permissionListener = listener; activity.requestPermissions(permissions, requestCode); diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ProximityModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ProximityModule.java index 34669cf26b..68e4354b02 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ProximityModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ProximityModule.java @@ -1,5 +1,5 @@ /* - * Copyright @ 2017-present Atlassian Pty Ltd + * Copyright @ 2017-present 8x8, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,21 +33,10 @@ import com.facebook.react.module.annotations.ReactModule; * is used with the conference audio-only mode. */ @ReactModule(name = ProximityModule.NAME) -class ProximityModule - extends ReactContextBaseJavaModule { +class ProximityModule extends ReactContextBaseJavaModule { public static final String NAME = "Proximity"; - /** - * This type of wake lock (the one activated by the proximity sensor) has - * been available for a while, but the constant was only exported in API - * level 21 (Android Marshmallow) so make no assumptions and use its value - * directly. - * - * TODO: Remove when we bump the API level to 21. - */ - private static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; - /** * {@link WakeLock} instance. */ @@ -71,7 +60,7 @@ class ProximityModule try { wakeLock = powerManager.newWakeLock( - PROXIMITY_SCREEN_OFF_WAKE_LOCK, + PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "jitsi:"+NAME); } catch (Throwable ignored) { wakeLock = null;