AbstractMethodError onClientSessionEvent and “Miss

2019-08-04 12:13发布

问题:

I have problem with this code:

@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.KITKAT)
public class NotificationRemoteControllerService extends NotificationService implements OnClientUpdateListenerExtended {
private static final String TAG = "NRemoteContollerService";
public static boolean isMusicPlaying = false;
MusicPlaybackState currenTplaybackState;
// REMOTE CONTROLLER
private int currentPlaybackState;
private SimpleMusicMetadata simpleMusicMetadata;
private RemoteController remoteController;

private static String getStringMetadata(RemoteController.MetadataEditor metadataEditor, int key) {
    return metadataEditor.getString(key, METADATA_DEFAULT_VALUE);
}

public static boolean isEnabled(Context context) {
    ComponentName cn = new ComponentName(context, NotificationRemoteControllerService.class);
    String flat = Settings.Secure.getString(context.getContentResolver(), "enabled_notification_listeners");
    return flat != null && flat.contains(cn.flattenToString());
}

@Override
public void onCreate() {
    super.onCreate();

    remoteController = new RemoteController(this, this);
}

RemoteController.OnClientUpdateListener myListener = new RemoteController.OnClientUpdateListener() {
    @Override
    public void onClientChange(boolean b) {

    }

    @Override
    public void onClientPlaybackStateUpdate(int i) {

    }

    @Override
    public void onClientPlaybackStateUpdate(int i, long l, long l1, float v) {

    }

    @Override
    public void onClientTransportControlUpdate(int i) {

    }

    @Override
    public void onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor) {

    }
}
/* ----------------------------------------------------------------------------------------

                                    REMOTE CONTROLLER

   ---------------------------------------------------------------------------------------- */

@Override
public void onDestroy() {
    disableRemoteController();
    super.onDestroy();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    int artworkWidth;
    int artworkHeight;
    if (intent != null) {
        artworkWidth = intent.getIntExtra(EXTRA_ALBUM_COVER_WIDTH,
                DEFAULT_ATTRIBUTE_ALBUM_COVER_WIDTH);
        artworkHeight = intent.getIntExtra(EXTRA_ALBUM_COVER_HEIGHT,
                DEFAULT_ATTRIBUTE_ALBUM_COVER_HEIGHT);
    } else {
        artworkWidth = DEFAULT_ATTRIBUTE_ALBUM_COVER_WIDTH;
        artworkHeight = DEFAULT_ATTRIBUTE_ALBUM_COVER_HEIGHT;
    }

    Log.e(TAG, "isMusicPlaying " + Boolean.toString(isMusicPlaying));
    if (simpleMusicMetadata == null) Log.e(TAG, "simpleMusic is Null!!");

    if (isMusicPlaying && simpleMusicMetadata != null) {
        Log.e(TAG, "onStartCommand: eventbus.get " + simpleMusicMetadata.getTitle());
        EventBus.getDefault().post(simpleMusicMetadata);
    } else {
        remoteController.setArtworkConfiguration(artworkWidth, artworkHeight);
        enableRemoteController();
    }
    if (currenTplaybackState != null) {
        Log.e(TAG, "PLAY_STATE" + currenTplaybackState.name());
        EventBus.getDefault().post(currenTplaybackState);
    }
    return START_STICKY;
}

private void postUpdateMetadata(RemoteController.MetadataEditor metadataEditor) {
    String title = getStringMetadata(metadataEditor, METADATA_KEY_TITLE);
    String artist = getStringMetadata(metadataEditor, METADATA_KEY_ARTIST);
    String album = getStringMetadata(metadataEditor, METADATA_KEY_ALBUM);

    Bitmap artwork = metadataEditor.getBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, null);

    simpleMusicMetadata = new SimpleMusicMetadata(title, artist, album, artwork);
    EventBus.getDefault().post(simpleMusicMetadata);

}

private void enableRemoteController() {
    if (!EventBus.getDefault().isRegistered(this))
        EventBus.getDefault().register(this);
    if (remoteController != null) {
        try {
            AudioManager manager = ((AudioManager) getApplicationContext().getSystemService(AUDIO_SERVICE));

            if (!manager.registerRemoteController(remoteController)) {
                Log.e(TAG, "Failed to register remoteController.");
            }

        } catch (Exception e) {
            Log.e(TAG, "enableRemoteController EXCEPTION");
            Log.e(TAG, e.getLocalizedMessage());
            Log.e(TAG, e.getMessage());

        }
    }

    setSynchronizationMode(RemoteController.POSITION_SYNCHRONIZATION_NONE);
    currentPlaybackState = PLAYBACK_INVALID_STATE;
}

private void setSynchronizationMode(int sync) {
    if ((sync != RemoteController.POSITION_SYNCHRONIZATION_NONE) && (sync != RemoteController.POSITION_SYNCHRONIZATION_CHECK)) {
        throw new IllegalArgumentException("Unknown synchronization mode " + sync);
    }

    Class<?> iRemoteControlDisplayClass;

    try {
        iRemoteControlDisplayClass = Class.forName("android.media.IRemoteControlDisplay");
    } catch (ClassNotFoundException e1) {
        throw new RuntimeException("Class IRemoteControlDisplay doesn't exist, can't access it with reflection");
    }

    Method remoteControlDisplayWantsPlaybackPositionSyncMethod;
    try {
        remoteControlDisplayWantsPlaybackPositionSyncMethod = AudioManager.class.getDeclaredMethod("remoteControlDisplayWantsPlaybackPositionSync", iRemoteControlDisplayClass, boolean.class);
        remoteControlDisplayWantsPlaybackPositionSyncMethod.setAccessible(true);
    } catch (NoSuchMethodException e) {
        throw new RuntimeException("Method remoteControlDisplayWantsPlaybackPositionSync() doesn't exist, can't access it with reflection");
    }

    Object rcDisplay;
    Field rcDisplayField;
    try {
        rcDisplayField = RemoteController.class.getDeclaredField("mRcd");
        rcDisplayField.setAccessible(true);
        rcDisplay = rcDisplayField.get(remoteController);
    } catch (NoSuchFieldException e) {
        throw new RuntimeException("Field mRcd doesn't exist, can't access it with reflection");
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Field mRcd can't be accessed - access denied");
    } catch (IllegalArgumentException e) {
        throw new RuntimeException("Field mRcd can't be accessed - invalid argument");
    }

    AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    try {
        remoteControlDisplayWantsPlaybackPositionSyncMethod.invoke(am, iRemoteControlDisplayClass.cast(rcDisplay), true);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Method remoteControlDisplayWantsPlaybackPositionSync() invocation failure - access denied");
    } catch (IllegalArgumentException e) {
        throw new RuntimeException("Method remoteControlDisplayWantsPlaybackPositionSync() invocation failure - invalid arguments");
    } catch (InvocationTargetException e) {
        throw new RuntimeException("Method remoteControlDisplayWantsPlaybackPositionSync() invocation failure - invalid invocation target");
    }
}


private void disableRemoteController() {
    EventBus.getDefault().unregister(this);
    if (remoteController != null) {
        ((AudioManager) getApplicationContext().getSystemService(AUDIO_SERVICE))
                .unregisterRemoteController(remoteController);
    }
}

private boolean sendMediaKeyEvent(int key) {
    try {
        KeyEvent downKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, key);
        KeyEvent upKeyEvent = new KeyEvent(KeyEvent.ACTION_UP, key);
        boolean downResult = remoteController.sendMediaKeyEvent(downKeyEvent);
        boolean upResult = remoteController.sendMediaKeyEvent(upKeyEvent);
        return downResult && upResult;
    } catch (NullPointerException e) {
        Log.e(TAG, "remoteController == null");
        return false;
    }
}

private boolean sendNextKeyEvent() {
    return sendMediaKeyEvent(MUSIC_KEY_NEXT);
}

private boolean sendPreviousKeyEvent() {
    return sendMediaKeyEvent(MUSIC_KEY_PREVIOUS);
}

private boolean sendPlayKeyEvent() {
    return sendMediaKeyEvent(MUSIC_KEY_PLAY);
}

private boolean sendPauseKeyEvent() {
    return sendMediaKeyEvent(MUSIC_KEY_PAUSE);
}

@SuppressWarnings("unused")
public void onEvent(MusicAction action) {
    switch (action) {
        case PREVIOUS:
            sendPreviousKeyEvent();
            break;
        case NEXT:
            sendNextKeyEvent();
            break;
        case PLAY_PAUSE:
            if (isMusicPlaying) {
                sendPauseKeyEvent();
            } else {
                sendPlayKeyEvent();
            }
            break;
    }
}

public static int state;

private void updatePlaybackState(int state) {
    MusicPlaybackState playbackState;

    if (state == STATE_PLAYING
            || state == STATE_BUFFERING
            || state == STATE_FAST_FORWARDING
            || state == STATE_REWINDING
            || state == STATE_SKIPPING_TO_NEXT) {
        isMusicPlaying = true;
        playbackState = MusicPlaybackState.PLAYING;

    } else if (state == STATE_PAUSED) {
        isMusicPlaying = false;
        playbackState = MusicPlaybackState.PAUSED;

    } else {
        isMusicPlaying = false;
        playbackState = MusicPlaybackState.STOPPED;
    }
    Log.e(TAG, "playing state: " + playbackState.name());
    EventBus.getDefault().post(playbackState);
    currenTplaybackState = playbackState;
    currentPlaybackState = state;
}

@Override
public void onClientSessionEvent(String s, Bundle bundle) {

}


@Override
public void onClientChange(boolean noClient) {
    Log.e(TAG, "onClientChange: " + Boolean.toString(noClient) + ", " + Boolean.toString(isMusicPlaying));
    if (!noClient && isMusicPlaying) {
        EventBus.getDefault().post(VisibilityBus.VISIBLE);
    } else {
        EventBus.getDefault().post(VisibilityBus.GONE);
    }
}

@Override
public void onClientPlaybackStateUpdate(int i) {
    Log.e(TAG, "onClientPlaybackStateUpdate: " + i);
    updatePlaybackState(i);
}

@Override
public void onClientPlaybackStateUpdate(int i, long l, long l1, float v) {
    Log.e(TAG, "onClientPlaybackStateUpdate: " + i);
    updatePlaybackState(i);
}

@Override
public void onClientTransportControlUpdate(int i) {
}

@Override
public void onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor) {
    postUpdateMetadata(metadataEditor);
}


}

problem:

AbstractMethodError: abstract method "void android.media.RemoteController$OnClientUpdateListener.onClientSessionEvent 

It occures on some Samsung phones with Android 5.x. I was trying to change to

        remoteController = new RemoteController(this, new RemoteController.OnClientUpdateListener() {

        public void onClientSessionEvent(String string, Bundle bundle) { }

        @Override
        public void onClientChange(boolean b) {

        }

        @Override
        public void onClientPlaybackStateUpdate(int i) {

        }

        @Override
        public void onClientPlaybackStateUpdate(int i, long l, long l1, float v) {

        }

        @Override
        public void onClientTransportControlUpdate(int i) {

        }

        @Override
        public void onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor) {

        }
    });
}

but then I have "Missing permission to control media". How I have to add this method to make it work?

回答1:

Add this permission to your AndroidManifest.xml

<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>

According to the documentation:

public static final String MEDIA_CONTENT_CONTROL
Added in API level 19
Allows an application to know what content is playing and control its playback.
Not for use by third-party applications due to privacy of media consumption
Constant Value: "android.permission.MEDIA_CONTENT_CONTROL"