2016-07-19 3 views
0

Я разрабатываю приложение, в котором нам нужно использовать гнездо для наушников только как кнопку.Как подключить наушники по умолчанию для наушников?

Требования: Воспроизведение аудио по умолчанию (вызов) через динамик, когда наушники не подключены (нет необходимости аудио через наушники)

Есть много примеров маршрутизации аудио через динамик и наушник а также Bluetooth гарнитуры, но ничего о маршрутизации звук через наушники для наушников, если гарнитуры подключены. Я попробовал много, и некоторые ссылки

Android : Force audio routing (не работает в моем сценарии)

Я проверил SoundAbout (https://play.google.com/store/apps/details?id=com.woodslink.android.wiredheadphoneroutingfix&hl=en) приложение и его маршрутизации аудио в различных порта, как гарнитуры, громкоговорители и наушники ,

Я получил аудио колонки, если подключены наушники: Вот мой код

if (Build.VERSION.SDK_INT >= 21) { 
      ForegroundService.audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); 
      ForegroundService.audioManager.setSpeakerphoneOn(true); 
      SplashScreen.preferences.edit().putBoolean("isKey", true).commit(); 
     } else { 
      Class audioSystemClass = null; 
      try { 
       audioSystemClass = Class.forName("android.media.AudioSystem"); 
       Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class); 
       setForceUse.invoke(null, FOR_MEDIA, FORCE_SPEAKER); 
      } catch (ClassNotFoundException e) { 
       e.printStackTrace(); 
      } catch (NoSuchMethodException e) { 
       e.printStackTrace(); 
      } catch (IllegalAccessException e) { 
       e.printStackTrace(); 
      } catch (InvocationTargetException e) { 
       e.printStackTrace(); 
      } 


      SplashScreen.preferences.edit().putBoolean("isKey", true).commit(); 
      ForegroundService.audioManager.setSpeakerphoneOn(true); 
     } 

ответ

0

После многозначительного исследования я обнаружил, что нет никакой возможности достичь этой функциональности без использования отражения. Сначала вам нужно установить гнездо для гарнитуры, а затем вызвать метод setWiredDeviceConnectionState() с подходящими параметрами, тогда он будет вести себя так, как будто наушники отключены, но щелкните по-прежнему. Так что это взломать, но согласно моему требованию, это не надежное решение, а работающее сейчас. Вот мой код, чтобы сделать это,

private void sendIntent(Intent i) { 
     Method m; 
     Log.i(TAG, "Device sdk = " + Build.VERSION.SDK_INT); 
     try { 
      if (Build.VERSION.SDK_INT < 16) { 
       Class<?> clazz = Class.forName("android.app.ActivityManagerNative"); 
       m = clazz.getMethod("broadcastStickyIntent", Intent.class, String.class); 
       m.setAccessible(true); 
       m.invoke(clazz, i, null); 
       return; 
      } else if (Build.VERSION.SDK_INT < 23) { 
       //int type, int state, String address, String name 
       m = am.getClass().getMethod("setWiredDeviceConnectionState", Integer.TYPE, Integer.TYPE, String.class); 
       m.setAccessible(true); 
       Object[] objArr = new Object[3]; 
       objArr[0] = (i.getIntExtra("microphone", 0) == 0) ? 8 : 4; 
       objArr[1] = i.getIntExtra("state", 0); 
       objArr[2] = i.getStringExtra("name"); 
       m.invoke(am, objArr); 
      } else { 
       //int type, int state, String address, String name 
       m = am.getClass().getMethod("setWiredDeviceConnectionState", Integer.TYPE, Integer.TYPE, String.class, String.class); 
       m.setAccessible(true); 
       Object[] objArr = new Object[4]; 
       objArr[0] = (i.getIntExtra("microphone", 0) == 0) ? 8 : 4; 
       objArr[1] = i.getIntExtra("state", 0); 
       objArr[2] = i.getStringExtra("address"); 
       objArr[3] = i.getStringExtra("name"); 
       m.invoke(am, objArr); 
      } 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

намерение отправить:

@TargetApi(Build.VERSION_CODES.M) 
public class HeadSetJackReciever extends AudioDeviceCallback { 
    public static boolean isAudioChecked; 

    public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { 
     if (addedDevices.length != 0) { 
      for (int i = 0; i < addedDevices.length; i++) { 
       if (addedDevices[i].getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) { 
        AudioDeviceInfo audioDeviceInfo = addedDevices[i]; 
        int microphone = audioDeviceInfo.getType(); 
        String headsetName = "DCS"; 
        String headsetAddress = ""; 
        try { 
         Method method = audioDeviceInfo.getClass().getMethod("getAddress"); 
         method.setAccessible(true); 
         headsetAddress = (String) method.invoke(audioDeviceInfo); 
        } catch (NoSuchMethodException e) { 
         e.printStackTrace(); 
        } catch (InvocationTargetException e) { 
         e.printStackTrace(); 
        } catch (IllegalAccessException e) { 
         e.printStackTrace(); 
        } 
        Log.e("TEST", "microphone:"+microphone); 
        Log.e("TEST", "headsetName:"+headsetName); 
        Log.e("TEST", "headsetAddress:"+headsetAddress); 
        Intent intent = new Intent(ForegroundService.context, SelectAudioOutput.class); 
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
        intent.putExtra("microphone",microphone); 
        intent.putExtra("headsetName",headsetName); 
        intent.putExtra("headsetAddress",headsetAddress); 
        ForegroundService.context.startActivity(intent); 
       } 
      } 
     } 
    } 

    public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { 
     if (removedDevices.length != 0) { 
      Log.e("TEST", "Audio deinserted"); 
      if (SplashScreen.preferences.getBoolean("isKey", false)) { 
       Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class); 
       startIntent.setAction(Constants.ACTION.STARTNOTIFICATION_ACTION); 
       ForegroundService.context.startService(startIntent); 
      } else { 
       Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class); 
       startIntent.setAction(Constants.ACTION.STOPNOTIFICATION_ACTION); 
       ForegroundService.context.startService(startIntent); 
      } 
      ForegroundService.audioManager.setMode(AudioManager.MODE_IN_CALL); 
      ForegroundService.audioManager.setSpeakerphoneOn(false); 
     } 
    } 
} 

для Lollipop и более низких версий:

if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) { 
      headsetName = intent.getStringExtra("name"); 
      microphone = intent.getIntExtra("microphone", 0); 

      int state = intent.getIntExtra("state", -1); 
      switch (state) { 
       case 0: 
        Log.d("onReceive", "Headset unplugged"); 
        Log.e("TEST", "Audio deinserted"); 
        if (SplashScreen.preferences.getBoolean("isKey", false)) { 
         Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class); 
         startIntent.setAction(Constants.ACTION.STARTNOTIFICATION_ACTION); 
         context.startService(startIntent); 
        } else { 
         Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class); 
         startIntent.setAction(Constants.ACTION.STOPNOTIFICATION_ACTION); 
         context.startService(startIntent); 
        } 
        ForegroundService.audioManager.setMode(AudioManager.MODE_IN_CALL); 
        ForegroundService.audioManager.setSpeakerphoneOn(false); 
        break; 
       case 1: 

        Log.d("onReceive", "Headset plugged"); 
        Log.e("TEST", "microphone:"+microphone); 
        Log.e("TEST", "headsetName:"+headsetName); 
        Log.e("TEST", "headsetAddress:"+headsetAddress); 
        Intent intentone = new Intent(ForegroundService.context, SelectAudioOutput.class); 
        intentone.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
        intentone.putExtra("microphone",microphone); 
        intentone.putExtra("headsetName",headsetName); 
        intentone.putExtra("headsetAddress",headsetAddress); 
        context.startActivity(intentone); 
        break; 
      } 
     } 

Позвольте мне знать, если я что-то пропустил. Спасибо.

+0

в HeadsetJackReceiver addedDevices [] массив, я получаю 2 гарнитуры и 1 наушники. Таким образом, код отправляет два намерения, а аудио не маршрутизируется. Я использую Android M (23). Вы можете помочь? –

1

Наушник никогда не используется для средств массовой информации в Android, и он может быть использован только в случае, если телефон находится в «вызов "или" связь "(VoIP).

Я думаю, вы заметили, что константа «FORCE_EARPIECE» отсутствует, поэтому она не может быть указана при вызове setForceUse.

Кроме того, динамик имеет самый низкий приоритет при выборе выходного устройства для звонков, так что, если телефон имеет ничего подключенного к нему (и в вашем случае есть поддельные гарнитуры), что устройство будет выбраны (см https://android.googlesource.com/platform/frameworks/av/+/322b4d2/services/audiopolicy/enginedefault/src/Engine.cpp#381).

Извините, не представляется возможным достичь того, что вы намерены.

UPDATE

После изучения media.audio_policy состояния в то время как SoundAbout является принуждая использование наушника для средств массовой информации, я обнаружил следующие приемы, которые используют это приложение:

  1. Он призывает AudioSystem.setPhoneState(MODE_IN_COMMUNICATION) за исполнение " (обычно используется для VoIP-вызовов).

  2. Если подключена минигарнитура (или наушники), чтобы предотвратить перенаправление звука из-за более высокого приоритета, приложение вызывает AudioSystem.setDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET, DEVICE_STATE_UNAVAILABLE, ...), чтобы обмануть Audio Manager, чтобы полагать, что гарнитуры нет.

Все эти взломы и требуют приложения для непосредственного наблюдения за состоянием телефона. Он также не работает все время.

Другим недостатком является то, что использование наушника отключает встроенную аудиоразделение на кристалле и, следовательно, имеет более высокий уровень использования батареи.

В общем, я бы не рекомендовал использовать эти методы.

+0

Thanks @Mikhail за то, что поделился своими мыслями. Я знаю, что это невозможно. Похоже, Google не хочет предоставлять какой-либо метод для прямой кнопки для разработчиков. Я много исследовал об этом и обнаружил, что все методы, которые могут получить к нему доступ, были удалены или скрыты или лишены. Но некоторые приложения все еще делают это как mSwitch, Keycut, iKey на playstore, так что это возможно, но я не знаю, как, но мне нужна эта функциональность в моем приложении. Я думаю, что они отключают наушники программно, используя отражение, а затем звук направляется на наушники, как обычно, используя приоритет, который вы знаете. – DCS

+0

Как минимум mSwitch (KeyCut) требует укоренения вашего телефона. При использовании root вы определенно можете изменить конфигурацию аудио-политики, чтобы делать все, что вам нужно. –

+0

Мне не нужен root-доступ, и устройства, на которых я тестировал, не были внедрены. Пожалуйста, проверьте SoundAbout и приложение Kclick на playstore. Выберите, чтобы направить динамик, и вы получите звук в наушнике, а не в наушниках. – DCS

Смежные вопросы