我正在开发一个包含语音通话的项目,但存在一些问题,即我无法在通话时更改音频级别。
项目正在React Native 0.64.2上运行
我尝试用 AudioManager 听硬件按钮来更改音频。但这里的问题是,当用户尝试按住音量按钮时, onKeyDown 永远不会被调用,它仅在未通话时被调用。有谁知道问题是什么。
因为其他人很难测试,当我执行代码并按下音量按钮时,短时间和长时间会发生什么:
为了接管音频,我创建了自己的包,这样我就可以设置当时需要的音频通道。 (我将其链接到项目的 MainActivity,因此通常会执行硬件按下(根据我的说法))
模块:
package be.idealsystems.audioTakeover;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
import android.media.AudioManager;
import java.util.Arrays;
import java.lang.Integer;
import android.util.Log;
public class RNAudioTakeoverModule extends ReactContextBaseJavaModule {
private static Integer channel = AudioManager.STREAM_MUSIC;
public RNAudioTakeoverModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "RNAudioTakeover";
}
public static Integer get() {
return channel;
}
@ReactMethod
public static void set(Integer value) {
Integer[] existingStreams = {
AudioManager.STREAM_ACCESSIBILITY,
AudioManager.STREAM_ALARM,
AudioManager.STREAM_DTMF,
AudioManager.STREAM_MUSIC,
AudioManager.STREAM_NOTIFICATION,
AudioManager.STREAM_RING,
AudioManager.STREAM_SYSTEM,
AudioManager.STREAM_VOICE_CALL,
AudioManager.USE_DEFAULT_STREAM_TYPE
};
try {
if (value == (Integer)value && Arrays.asList(existingStreams).contains(value)) {
channel = value;
} else {
channel = AudioManager.STREAM_MUSIC;
}
} catch (Exception e) {
channel = AudioManager.STREAM_MUSIC;
}
}
}
包装:
package be.idealsystems.audioTakeover;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class RNAudioTakeoverPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new RNAudioTakeoverModule(reactContext));
}
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
主要活动:
package be.idealsystems.mc.purecloud;
import android.os.SystemClock;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import android.view.KeyEvent;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.graphics.Color;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import com.facebook.react.ReactActivity;
import android.content.res.Configuration;
import android.view.WindowManager.LayoutParams;
import java.lang.Integer;
//DSL
import android.view.WindowManager;
import io.wazo.callkeep.RNCallKeepModule;
import com.overlaypermission.OverlayPermissionPackage;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import android.content.res.Configuration;
import android.content.Intent;
import android.util.Log;
import android.net.Uri;
import be.idealsystems.hideScreenshot.HideScreenshotModule;
import be.idealsystems.audioTakeover.RNAudioTakeoverModule;
import android.media.AudioManager;
public class MainActivity extends ReactActivity {
private static final String DEFAULT_CHANNEL = "DEFAULT";
private static final String SILENT_CHANNEL = "SILENT";
private static final String TEL = "tel";
public Bundle mInitialProps = null;
private AudioManager audio;
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "Testing";
}
@Override
public void invokeDefaultOnBackPressed() {
moveTaskToBack(true);
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected Bundle getLaunchOptions() {
return mInitialProps;
}
};
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case RNCallKeepModule.REQUEST_READ_PHONE_STATE:
RNCallKeepModule.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
}
private void sendEvent(ReactContext reactContext, String eventName, WritableMap params) {
try{
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
catch(Exception e){
Log.d("TEST","ERROR "+ e.getMessage());
}
}
@Override
protected void onPause() {
super.onPause();
if (HideScreenshotModule.get()) {
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
}
}
@Override
protected void onResume() {
super.onResume();
if (HideScreenshotModule.get()) {
getWindow().clearFlags(LayoutParams.FLAG_SECURE);
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (HideScreenshotModule.get()) {
if (hasFocus) {
getWindow().clearFlags(LayoutParams.FLAG_SECURE);
} else {
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
}
}
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String action = intent.getAction();
Uri data = intent.getData();
String stringUri="";
if (data!=null){
stringUri = data.toString();
if (stringUri.contains(TEL)) {
WritableMap idData = Arguments.createMap();
idData.putString("tel", stringUri);
sendEvent(getReactInstanceManager().getCurrentReactContext(), "INCOMINGTELFROMOUTSIDEMC", idData);
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getReactInstanceManager().onConfigurationChanged(this, newConfig);
}
// needed for react-native-screens
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
//DSL
mInitialProps = new Bundle();
Uri test = getIntent().getData();
String stringUri="";
if (test!=null)
stringUri = test.toString();
if (stringUri.contains(TEL)) {
mInitialProps.putString(TEL, stringUri);
}
audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//END DSL
if (Build.VERSION.SDK_INT >= 26) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
createDefaultNotificationChannel(mNotificationManager);
// createSilentNotificationChannel(mNotificationManager);
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
@Override
public boolean onKeyShortcut(int keyCode, KeyEvent event) {
Log.e("@YANNICK", "KEY SHORTCUT " + keyCode);
return true;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.e("@YANNICK", "KEY UP " + keyCode);
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.e("@YANNICK", "KEY DOWN " + keyCode);
return true;
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
Log.e("@YANNICK", "KEY MULTIPLE " + keyCode + " " + ((Integer)repeatCount).toString());
return true;
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
Log.e("@YANNICK", "KEY LONG " + keyCode);
return true;
}
// This works, but executes like keyUp (only once every press)
/*@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
Log.e("@YANNICK", "KEY EVENT " + keyCode);
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
audio.adjustStreamVolume(RNAudioTakeoverModule.get(), AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
audio.adjustStreamVolume(RNAudioTakeoverModule.get(), AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
return true;
default:
return super.dispatchKeyEvent(event);
}
}*/
private void createDefaultNotificationChannel(NotificationManager mNotificationManager) {
NotificationChannel defaultChannel = new NotificationChannel(
DEFAULT_CHANNEL,
"Default channel",
NotificationManager.IMPORTANCE_HIGH
);
defaultChannel.setLightColor(Color.GREEN);
defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotificationManager.createNotificationChannel(defaultChannel);
}
private void createSilentNotificationChannel(NotificationManager mNotificationManager) {
NotificationChannel silentChannel = new NotificationChannel(
SILENT_CHANNEL,
"Silent channel",
NotificationManager.IMPORTANCE_HIGH
);
silentChannel.setSound(null, null);
silentChannel.enableLights(false);
silentChannel.setVibrationPattern(null);
silentChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotificationManager.createNotificationChannel(silentChannel);
}
}
来自简短的文档。
当释放按键且未由活动内的任何视图处理时调用。
可能压力由另一个活动元素处理,或者 我怀疑您在通话期间使用蓝牙连接(例如,使用耳机),那么按下将由蓝牙连接处理。