2016-12-01 12 views
2

mp3ファイル (see this question)を再生するために、Android MediaPlayerフレームワークを使用しようとしました。ボリュームを設定できません。音量コントロールがシステムに転送されていません。

私はそれを動作させた後、音量アップ/ダウンイベントがクラスjavafxports.android.KeyEventProcessorによってキャッチされ、決して転送されないことをすぐに認識しました。私はそれを回避しようとしましたが、無駄にしました。

でないイベントをディスパッチする手段はありますかがキャッチされますか?私は常に自分の質問に答えることを嫌いますが

おかげに関して、 ダニエル

+0

http://stackoverflow.com/questions/40562263/how-to-play-a-sound-on-android-using-gluon-javafx-project、https://でビットバケット.org/javafxports/android/issues/73/hardware-button-key-events-report – jns

+0

うわー!どのような素晴らしい応答! 2つのリンクを提供するだけで、それは解決されておらず、解決できないことを示唆しているようです。いい加減にして!これは私たちが話しているアンドロイドであり、それは解決可能です! - 私の答えを見て、私はこのトピックを提供します。 – dzim

+0

私は参照してください。とにかくあなた自身の質問に常に答えているので、トピックに関する情報を提供するリンクには興味がありません。 – jns

答えて

2

は、私は上のいくつかのドキュメンテーションとを掘り、AndroidのAPIで遊んで数時間後に解決策を見つけました。

私の解決策は、部分的には、@ホセペレダがトピック"javafxports how to call android native Media Player"で与えた答えに基づいています。

私は "volumeDown" と "ミュート"、タスク "volumeUp" のためのインタフェースを作成しました:

public interface NativeVolumeService { 
    void volumeUp(); 
    void volumeDown(); 
    void mute(); 
} 

その後、system volume on Androidを設定する方法については、以下の回答に基づいて、 Androidで次の実装を考えました:

import java.util.ArrayList; 
import java.util.logging.Logger; 

import android.content.Context; 
import android.media.AudioManager; 
import android.view.KeyEvent; 
import android.view.View; 
import android.view.ViewGroup; 
import my.package.platform.NativeVolumeService; 
import javafxports.android.FXActivity; 

public class NativeVolumeServiceAndroid implements NativeVolumeService { 

    private static final Logger LOG = Logger.getLogger(NativeVolumeServiceAndroid.class.getName()); 

    private final AudioManager audioManager; 

    private final int maxVolume; 
    private int preMuteVolume = 0; 
    private int currentVolume = 0; 

    public NativeVolumeServiceAndroid() { 
     audioManager = (AudioManager) FXActivity.getInstance().getSystemService(Context.AUDIO_SERVICE); 
     maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 
    } 

    @Override 
    public void volumeUp() { 
     LOG.info("dispatch volume up event"); 
     KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP); 
     dispatchEvent(event, true, false); 
    } 

    @Override 
    public void volumeDown() { 
     LOG.info("dispatch volume down event"); 
     KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_DOWN); 
     dispatchEvent(event, false, false); 
    } 

    @Override 
    public void mute() { 
     LOG.info("dispatch volume mute event"); 
     KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_MUTE); 
     dispatchEvent(event, false, true); 
    } 

    private void dispatchEvent(KeyEvent event, boolean up, boolean mute) { 

     // hardware key events (amongst others) get caught by the JavaFXPorts engine (or better: the Dalvik impl from Oracle) 
     // to circumvent this, we need to do the volume adjustment the hard way: via the AudioManager 

     // see: https://developer.android.com/reference/android/media/AudioManager.html 
     // see: https://stackoverflow.com/questions/9164347/setting-the-android-system-volume?rq=1 

     // reason: 
     // FXActivity registers a FXDalvikEntity, which etends the surface view and passing a key processor 
     // called KeyEventProcessor - this one catches all key events and matches them to JavaFX representations. 
     // Unfortunately, we cannot bypass this, so we need the AudioManager 

     currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
     if (mute) { 
      if (currentVolume > 0) { 
       preMuteVolume = currentVolume; 
       audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_SAME, 
         AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE | AudioManager.FLAG_SHOW_UI); 
      } else { 
       preMuteVolume = 0; 
       audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, preMuteVolume, AudioManager.FLAG_SHOW_UI); 
      } 
     } else if (up) { 
      audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, 
        (currentVolume + 1) <= maxVolume ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI); 
     } else if (!up) { 
      audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, 
        (currentVolume - 1) >= 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI); 
     } 
    } 
} 

これを統合するには、私はappropを作成しました私のメインクラスのインスタンスriate(私は世界的にこれを必要とする - あなたが表示されます、なぜ)

private void instantiateNativeVolumeService() { 
    String serviceName = NativeVolumeService.class.getName(); 
    if (Platform.isDesktop()) { 
     serviceName += "Desktop"; 
    } else if (Platform.isAndroid()) { 
     serviceName += "Android"; 
    } 
    try { 
     volumeService = (NativeVolumeService) Class.forName(serviceName).newInstance(); 
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { 
     LOG.log(Level.SEVERE, "Could not get an instance of NativeAudioService for platform " + Platform.getCurrent(), e); 
    } 
} 

volumeServiceはクラス変数です。

それから私は私のStageSceneのイベントハンドラ登録:

@Override 
public void start(Stage stage) throws Exception { 
    // initiate everything 
    scene.addEventFilter(KeyEvent.ANY, this::handleGlobalKeyEvents); 
    // do more stuff, if needed 
} 

をそして最後に、このようになりますhandleGlobalKeyEvents方法:最後に

private void handleGlobalKeyEvents(KeyEvent event) { 
    // use a more specific key event type like 
    // --> KeyEvent.KEY_RELEASED == event.getEventType() 
    // --> KeyEvent.KEY_PRESSED == event.getEventType() 
    // without it, we would react on both events, thus doing one operation too much 
    if (event.getCode().equals(KeyCode.VOLUME_UP) && KeyEvent.KEY_PRESSED == event.getEventType()) { 
     if (volumeService != null) { 
      volumeService.volumeUp(); 
      event.consume(); 
     } 
    } 
    if (event.getCode().equals(KeyCode.VOLUME_DOWN) && KeyEvent.KEY_PRESSED == event.getEventType()) { 
     if (volumeService != null) { 
      volumeService.volumeDown(); 
      event.consume(); 
     } 
    } 
} 

は、解決策は同じくらいきれいですそれはあまりにも複雑ではありません。それが働くまでの道のりはちょっと厄介でした。

@JoséPereda:このソリューションをチャームダウンプラグインなどとして統合したい場合は、気軽にお気軽にご連絡ください。

よろしく、 ダニエル

+0

これは素晴らしい作品です。より低いレベルで修正する必要のある問題に対する適切な回避策。 –

関連する問題