diff --git a/app/src/main/java/org/xbmc/kore/host/HostConnectionObserver.java b/app/src/main/java/org/xbmc/kore/host/HostConnectionObserver.java index 5823714..194de80 100644 --- a/app/src/main/java/org/xbmc/kore/host/HostConnectionObserver.java +++ b/app/src/main/java/org/xbmc/kore/host/HostConnectionObserver.java @@ -58,10 +58,10 @@ public class HostConnectionObserver public interface ApplicationEventsObserver { /** * Notifies the observer that volume has changed - * @param volume - * @param muted + * @param volume Volume level + * @param muted Is muted */ - public void applicationOnVolumeChanged(int volume, boolean muted); + void applicationOnVolumeChanged(int volume, boolean muted); } /** @@ -72,13 +72,13 @@ public class HostConnectionObserver * Constants for possible events. Useful to save the last event and compare with the * current one to check for differences */ - public static final int PLAYER_NO_RESULT = 0, + int PLAYER_NO_RESULT = 0, PLAYER_CONNECTION_ERROR = 1, PLAYER_IS_PLAYING = 2, PLAYER_IS_PAUSED = 3, PLAYER_IS_STOPPED = 4; - public void playerOnPropertyChanged(NotificationsData notificationsData); + void playerOnPropertyChanged(NotificationsData notificationsData); /** * Notifies that something is playing @@ -86,7 +86,7 @@ public class HostConnectionObserver * @param getPropertiesResult Properties obtained by a call to {@link org.xbmc.kore.jsonrpc.method.Player.GetProperties} * @param getItemResult Currently playing item, obtained by a call to {@link org.xbmc.kore.jsonrpc.method.Player.GetItem} */ - public void playerOnPlay(PlayerType.GetActivePlayersReturnType getActivePlayerResult, + void playerOnPlay(PlayerType.GetActivePlayersReturnType getActivePlayerResult, PlayerType.PropertyValue getPropertiesResult, ListType.ItemsAll getItemResult); @@ -96,41 +96,41 @@ public class HostConnectionObserver * @param getPropertiesResult Properties obtained by a call to {@link org.xbmc.kore.jsonrpc.method.Player.GetProperties} * @param getItemResult Currently paused item, obtained by a call to {@link org.xbmc.kore.jsonrpc.method.Player.GetItem} */ - public void playerOnPause(PlayerType.GetActivePlayersReturnType getActivePlayerResult, + void playerOnPause(PlayerType.GetActivePlayersReturnType getActivePlayerResult, PlayerType.PropertyValue getPropertiesResult, ListType.ItemsAll getItemResult); /** * Notifies that media is stopped/nothing is playing */ - public void playerOnStop(); + void playerOnStop(); /** * Called when we get a connection error - * @param errorCode - * @param description + * @param errorCode Code + * @param description Description */ - public void playerOnConnectionError(int errorCode, String description); + void playerOnConnectionError(int errorCode, String description); /** * Notifies that we don't have a result yet */ - public void playerNoResultsYet(); + void playerNoResultsYet(); /** * Notifies that XBMC has quit/shutdown/sleep */ - public void systemOnQuit(); + void systemOnQuit(); /** * Notifies that XBMC has requested input */ - public void inputOnInputRequested(String title, String type, String value); + void inputOnInputRequested(String title, String type, String value); /** * Notifies the observer that it this is stopping */ - public void observerOnStopObserving(); + void observerOnStopObserving(); } /** @@ -141,33 +141,26 @@ public class HostConnectionObserver /** * The list of observers */ - private List playerEventsObservers = new ArrayList(); + private List playerEventsObservers = new ArrayList<>(); private List applicationEventsObservers = new ArrayList<>(); -// /** -// * Handlers for which observer, on which to notify them -// */ -// private Map observerHandlerMap = new HashMap(); - // Associate the Handler with the UI thread private Handler checkerHandler = new Handler(Looper.getMainLooper()); private Runnable httpCheckerRunnable = new Runnable() { @Override public void run() { - final int HTTP_NOTIFICATION_CHECK_INTERVAL = 3000; - boolean keepChecking = false; - if ( ! playerEventsObservers.isEmpty() ) { - keepChecking = true; + final int HTTP_NOTIFICATION_CHECK_INTERVAL = 2000; + // If no one is listening to this, just exit + if (playerEventsObservers.isEmpty() && applicationEventsObservers.isEmpty()) + return; + + if (!playerEventsObservers.isEmpty()) checkWhatsPlaying(); - } - if ( ! applicationEventsObservers.isEmpty() ) { - keepChecking = true; + if (!applicationEventsObservers.isEmpty()) getApplicationProperties(); - } - if (keepChecking) - checkerHandler.postDelayed(this, HTTP_NOTIFICATION_CHECK_INTERVAL); + checkerHandler.postDelayed(this, HTTP_NOTIFICATION_CHECK_INTERVAL); } }; @@ -184,24 +177,16 @@ public class HostConnectionObserver ping.execute(connection, new ApiCallback() { @Override public void onSuccess(String result) { - boolean keepChecking = false; - // Ok, we've got a ping, if there are playerEventsObservers and // we were in a error or uninitialized state, update - if ((! playerEventsObservers.isEmpty()) && + if ((!playerEventsObservers.isEmpty()) && ((hostState.lastCallResult == PlayerEventsObserver.PLAYER_NO_RESULT) || (hostState.lastCallResult == PlayerEventsObserver.PLAYER_CONNECTION_ERROR))) { + LogUtils.LOGD(TAG, "Checking what's playing because we don't have info about it"); checkWhatsPlaying(); - keepChecking = true; } - if ( ! applicationEventsObservers.isEmpty() ) { - getApplicationProperties(); - keepChecking = true; - } - - if (keepChecking) - checkerHandler.postDelayed(tcpCheckerRunnable, PING_AFTER_SUCCESS_CHECK_INTERVAL); + checkerHandler.postDelayed(tcpCheckerRunnable, PING_AFTER_SUCCESS_CHECK_INTERVAL); } @Override @@ -235,8 +220,6 @@ public class HostConnectionObserver public HostState hostState; - private HostConnectionObserver() {} - public HostConnectionObserver(HostConnection connection) { this.hostState = new HostState(); this.connection = connection; @@ -250,7 +233,7 @@ public class HostConnectionObserver if (this.connection == null) return; - if ( ! playerEventsObservers.contains(observer) ) + if (!playerEventsObservers.contains(observer)) playerEventsObservers.add(observer); if (replyImmediately) replyWithLastResult(observer); @@ -263,9 +246,8 @@ public class HostConnectionObserver connection.registerSystemNotificationsObserver(this, checkerHandler); connection.registerInputNotificationsObserver(this, checkerHandler); } + startCheckerHandler(); } - - startCheckerHandler(); } /** @@ -274,7 +256,6 @@ public class HostConnectionObserver */ public void unregisterPlayerObserver(PlayerEventsObserver observer) { playerEventsObservers.remove(observer); -// observerHandlerMap.remove(observer); LogUtils.LOGD(TAG, "Unregistering player observer " + observer.getClass().getSimpleName() + ". Still got " + playerEventsObservers.size() + @@ -295,13 +276,13 @@ public class HostConnectionObserver /** * Registers a new observer that will be notified about application events * @param observer Observer - * @param replyImmediately + * @param replyImmediately Wether to immediatlely issue a reply with the current status */ public void registerApplicationObserver(ApplicationEventsObserver observer, boolean replyImmediately) { if (this.connection == null) return; - if (! applicationEventsObservers.contains(observer) ) + if (!applicationEventsObservers.contains(observer)) applicationEventsObservers.add(observer); if (replyImmediately) { @@ -318,9 +299,8 @@ public class HostConnectionObserver if (connection.getProtocol() == HostConnection.PROTOCOL_TCP) { connection.registerApplicationNotificationsObserver(this, checkerHandler); } + startCheckerHandler(); } - - startCheckerHandler(); } /** @@ -343,6 +323,19 @@ public class HostConnectionObserver } } + private void startCheckerHandler() { + // Check if checkerHandler is already running, to prevent multiple runnables to be posted + // when multiple observers are registered. + if (checkerHandler.hasMessages(0)) + return; + + if (connection.getProtocol() == HostConnection.PROTOCOL_TCP) { + checkerHandler.post(tcpCheckerRunnable); + } else { + checkerHandler.post(httpCheckerRunnable); + } + } + /** * Unregisters all observers */ @@ -372,35 +365,48 @@ public class HostConnectionObserver /** * The {@link HostConnection.PlayerNotificationsObserver} interface methods + * Start the chain calls to get whats playing */ public void onPlay(org.xbmc.kore.jsonrpc.notification.Player.OnPlay notification) { - // Just start our chain calls - chainCallGetActivePlayers(); + // Ignore this if Kodi is Leia or higher, as we'll be properly notified via OnAVStart + // See https://github.com/xbmc/Kore/issues/602 and https://github.com/xbmc/xbmc/pull/13726 + if (connection.getHostInfo().isLeiaOrLater()) { + LogUtils.LOGD(TAG, "OnPlay notification ignored. Will wait for OnAVStart."); + return; + } + checkWhatsPlaying(); } public void onResume(org.xbmc.kore.jsonrpc.notification.Player.OnResume notification) { - // Just start our chain calls - chainCallGetActivePlayers(); + checkWhatsPlaying(); } public void onPause(org.xbmc.kore.jsonrpc.notification.Player.OnPause notification) { - // Just start our chain calls - chainCallGetActivePlayers(); + checkWhatsPlaying(); } public void onSpeedChanged(org.xbmc.kore.jsonrpc.notification.Player.OnSpeedChanged notification) { - // Just start our chain calls - chainCallGetActivePlayers(); + checkWhatsPlaying(); } public void onSeek(org.xbmc.kore.jsonrpc.notification.Player.OnSeek notification) { - // Just start our chain calls - chainCallGetActivePlayers(); + checkWhatsPlaying(); } public void onStop(org.xbmc.kore.jsonrpc.notification.Player.OnStop notification) { - // Just start our chain calls - notifyNothingIsPlaying(playerEventsObservers); + // We could directly notify that nothing is playing here, but in Kodi Leia everytime + // there's a playlist change, onStop is triggered, which caused the UI to display + // that nothing was being played. Checking what's playing prevents this. + checkWhatsPlaying(); + } + + public void onAVStart(org.xbmc.kore.jsonrpc.notification.Player.OnAVStart notification) { + checkWhatsPlaying(); + } + + public void onAVChange(org.xbmc.kore.jsonrpc.notification.Player.OnAVChange notification) { + // Just ignore this, as it is fired by Kodi very often, and we're only + // interested in play/resume/stop changes } /** @@ -448,18 +454,6 @@ public class HostConnectionObserver } } - private void startCheckerHandler() { - // Check if checkerHandler is already running, to prevent multiple runnables to be posted - // when multiple observers are registered. - if ( checkerHandler.hasMessages(0) ) - return; - - if (connection.getProtocol() == HostConnection.PROTOCOL_TCP) { - checkerHandler.post(tcpCheckerRunnable); - } else { - checkerHandler.post(httpCheckerRunnable); - } - } private void getApplicationProperties() { org.xbmc.kore.jsonrpc.method.Application.GetProperties getProperties = new org.xbmc.kore.jsonrpc.method.Application.GetProperties(org.xbmc.kore.jsonrpc.method.Application.GetProperties.VOLUME, @@ -483,10 +477,23 @@ public class HostConnectionObserver }, checkerHandler); } + /** + * Indicator set when we are calling Kodi to check what's playing, so that we don't call it + * while there are still pending calls + */ + private boolean checkingWhatsPlaying = false; + /** * Checks whats playing and notifies observers */ private void checkWhatsPlaying() { + // We don't properly protect this against race conditions because it's + // not worth the trouble - we can safely call Kodi multiple times. + if (checkingWhatsPlaying) { + LogUtils.LOGD(TAG, "Already checking whats playing, returning"); + return; + } + checkingWhatsPlaying = true; LogUtils.LOGD(TAG, "Checking whats playing"); // Start the calls: Player.GetActivePlayers -> Player.GetProperties -> Player.GetItem @@ -627,6 +634,7 @@ public class HostConnectionObserver * @param observers List of observers */ private void notifyConnectionError(final int errorCode, final String description, List observers) { + checkingWhatsPlaying = false; // Reply if different from last result if (forceReply || (hostState.lastCallResult != PlayerEventsObserver.PLAYER_CONNECTION_ERROR) || @@ -652,22 +660,15 @@ public class HostConnectionObserver */ private void notifyConnectionError(final int errorCode, final String description, PlayerEventsObserver observer) { observer.playerOnConnectionError(errorCode, description); -// Handler observerHandler = observerHandlerMap.get(observer); -// observerHandler.post(new Runnable() { -// @Override -// public void run() { -// observer.playerOnConnectionError(errorCode, description); -// } -// }); } - /** * Nothing is playing, notify observers calling playerOnStop * Only notifies them if the result is different from the last one * @param observers List of observers */ private void notifyNothingIsPlaying(List observers) { + checkingWhatsPlaying = false; // Reply if forced or different from last result if (forceReply || (hostState.lastCallResult != PlayerEventsObserver.PLAYER_IS_STOPPED)) { @@ -706,15 +707,16 @@ public class HostConnectionObserver /** * Something is playing or paused, notify observers * Only notifies them if the result is different from the last one - * @param getActivePlayersResult - * @param getPropertiesResult - * @param getItemResult + * @param getActivePlayersResult Previous call result + * @param getPropertiesResult Previous call result + * @param getItemResult Previous call result * @param observers List of observers */ private void notifySomethingIsPlaying(final PlayerType.GetActivePlayersReturnType getActivePlayersResult, final PlayerType.PropertyValue getPropertiesResult, final ListType.ItemsAll getItemResult, List observers) { + checkingWhatsPlaying = false; int currentCallResult = (getPropertiesResult.speed == 0) ? PlayerEventsObserver.PLAYER_IS_PAUSED : PlayerEventsObserver.PLAYER_IS_PLAYING; if (forceReply || @@ -740,7 +742,7 @@ public class HostConnectionObserver if ((currentCallResult == PlayerEventsObserver.PLAYER_IS_PLAYING) && (connection.getProtocol() == HostConnection.PROTOCOL_TCP) && (getPropertiesResult.time.ToSeconds() == 0)) { - LogUtils.LOGD(TAG, "Scheduling new call to check what's playing."); + LogUtils.LOGD(TAG, "Scheduling new call to check what's playing because time is 0."); final int RECHECK_INTERVAL = 3000; checkerHandler.postDelayed(new Runnable() { @Override @@ -750,15 +752,14 @@ public class HostConnectionObserver } }, RECHECK_INTERVAL); } - } /** * Something is playing or paused, notify a specific observer * Always notifies the observer, and doesn't save results in last call - * @param getActivePlayersResult - * @param getPropertiesResult - * @param getItemResult + * @param getActivePlayersResult Previous call result + * @param getPropertiesResult Previous call result + * @param getItemResult Previous call result * @param observer Specific observer */ private void notifySomethingIsPlaying(final PlayerType.GetActivePlayersReturnType getActivePlayersResult, @@ -801,8 +802,9 @@ public class HostConnectionObserver * Forces a refresh of the current cached results */ public void forceRefreshResults() { + LogUtils.LOGD(TAG, "Forcing a refresh"); forceReply = true; - chainCallGetActivePlayers(); + checkWhatsPlaying(); } public HostState getHostState() { diff --git a/app/src/main/java/org/xbmc/kore/host/HostInfo.java b/app/src/main/java/org/xbmc/kore/host/HostInfo.java index bf58d18..2a7e2db 100644 --- a/app/src/main/java/org/xbmc/kore/host/HostInfo.java +++ b/app/src/main/java/org/xbmc/kore/host/HostInfo.java @@ -307,7 +307,11 @@ public class HostInfo { return kodiVersionMajor >= KODI_V17_KRYPTON; } - /** + public boolean isLeiaOrLater() { + return kodiVersionMajor >= KODI_V18_LEIA; + } + + /** * Returns the URL of the host * @return HTTP URL eg. http://192.168.1.1:8080 */ diff --git a/app/src/main/java/org/xbmc/kore/jsonrpc/HostConnection.java b/app/src/main/java/org/xbmc/kore/jsonrpc/HostConnection.java index f10e210..44afb1f 100644 --- a/app/src/main/java/org/xbmc/kore/jsonrpc/HostConnection.java +++ b/app/src/main/java/org/xbmc/kore/jsonrpc/HostConnection.java @@ -77,6 +77,8 @@ public class HostConnection { void onSpeedChanged(Player.OnSpeedChanged notification); void onSeek(Player.OnSeek notification); void onStop(Player.OnStop notification); + void onAVStart(Player.OnAVStart notification); + void onAVChange(Player.OnAVChange notification); } /** @@ -126,25 +128,25 @@ public class HostConnection { * {@link java.util.HashMap} that will hold the {@link MethodCallInfo} with the information * necessary to respond to clients (TCP only) */ - private final HashMap> clientCallbacks = new HashMap>(); + private final HashMap> clientCallbacks = new HashMap<>(); /** * The observers that will be notified of player notifications */ private final HashMap playerNotificationsObservers = - new HashMap(); + new HashMap<>(); /** * The observers that will be notified of system notifications */ private final HashMap systemNotificationsObservers = - new HashMap(); + new HashMap<>(); /** * The observers that will be notified of input notifications */ private final HashMap inputNotificationsObservers = - new HashMap(); + new HashMap<>(); /** * The observers that will be notified of application notifications @@ -317,10 +319,9 @@ public class HostConnection { " on host: " + hostInfo.getJsonRpcHttpEndpoint()); if (protocol == PROTOCOL_TCP) { - /** - * Do not call this from the runnable below as it may cause a race condition - * with {@link #updateClientCallback(int, ApiCallback, Handler)} - */ + // Do not call this from the runnable below as it may cause a race condition + // with {@link #updateClientCallback(int, ApiCallback, Handler)} + // // Save this method/callback for any later response addClientCallback(method, callback, handler); } @@ -411,10 +412,10 @@ public class HostConnection { /** * Stores the method and callback to handle asynchronous responses. * Note this is only needed for requests over TCP. - * @param method - * @param callback - * @param handler - * @param + * @param method Method + * @param callback Callback + * @param handler Handler + * @param Method/Callback type */ private void addClientCallback(final ApiMethod method, final ApiCallback callback, final Handler handler) { @@ -437,7 +438,7 @@ public class HostConnection { } return; } - clientCallbacks.put(methodId, new MethodCallInfo(method, callback, handler)); + clientCallbacks.put(methodId, new MethodCallInfo<>(method, callback, handler)); } } @@ -489,7 +490,7 @@ public class HostConnection { httpClient.setAuthenticator(new Authenticator() { @Override - public Request authenticate(Proxy proxy, Response response) throws IOException { + public Request authenticate(Proxy proxy, Response response) { if (TextUtils.isEmpty(hostInfo.getUsername())) return null; @@ -498,7 +499,7 @@ public class HostConnection { } @Override - public Request authenticateProxy(Proxy proxy, Response response) throws IOException { + public Request authenticateProxy(Proxy proxy, Response response) { return null; } }); @@ -517,7 +518,7 @@ public class HostConnection { /** * Send an OkHttp POST request * @param request Request to send - * @throws ApiException + * @throws ApiException {@link ApiException} if request can't be sent */ private Response sendOkHttpRequest(final OkHttpClient client, final Request request) throws ApiException { try { @@ -543,7 +544,7 @@ public class HostConnection { * Reads the response from the server * @param response Response from OkHttp * @return Response body string - * @throws ApiException + * @throws ApiException {@link ApiException} if response can't be read/processed */ private String handleOkHttpResponse(Response response) throws ApiException { try { @@ -582,7 +583,7 @@ public class HostConnection { * If it is an error (contains the error tag), returns an {@link ApiException} with the info. * @param response JSON response * @return {@link com.fasterxml.jackson.databind.node.ObjectNode} constructed - * @throws ApiException + * @throws ApiException Exception trown if we can't parse the response */ private ObjectNode parseJsonResponse(String response) throws ApiException { // LogUtils.LOGD(TAG, "Parsing JSON response"); @@ -661,7 +662,7 @@ public class HostConnection { * Send a TCP request * @param socket Socket to write to * @param request Request to send - * @throws ApiException + * @throws ApiException Exception if can't send */ private void sendTcpRequest(Socket socket, String request) throws ApiException { try { @@ -713,7 +714,7 @@ public class HostConnection { ignoreTcpResponse = false; ignore = true; } - LogUtils.LOGD(TAG, "ignore tcp response - " + ignore); + //LogUtils.LOGD(TAG, "ignore tcp response - " + ignore); return ignore; } @@ -726,10 +727,10 @@ public class HostConnection { String notificationName = jsonResponse.get(ApiNotification.METHOD_NODE).asText(); ObjectNode params = (ObjectNode)jsonResponse.get(ApiNotification.PARAMS_NODE); - if (notificationName.equals(Player.OnPause.NOTIFICATION_NAME)) { + switch (notificationName) { + case Player.OnPause.NOTIFICATION_NAME: { final Player.OnPause apiNotification = new Player.OnPause(params); - for (final PlayerNotificationsObserver observer : - playerNotificationsObservers.keySet()) { + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { Handler handler = playerNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -738,10 +739,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Player.OnPlay.NOTIFICATION_NAME)) { + break; + } + case Player.OnPlay.NOTIFICATION_NAME: { final Player.OnPlay apiNotification = new Player.OnPlay(params); - for (final PlayerNotificationsObserver observer : - playerNotificationsObservers.keySet()) { + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { Handler handler = playerNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -750,10 +752,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Player.OnResume.NOTIFICATION_NAME)) { + break; + } + case Player.OnResume.NOTIFICATION_NAME: { final Player.OnResume apiNotification = new Player.OnResume(params); - for (final PlayerNotificationsObserver observer : - playerNotificationsObservers.keySet()) { + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { Handler handler = playerNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -762,10 +765,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Player.OnSeek.NOTIFICATION_NAME)) { + break; + } + case Player.OnSeek.NOTIFICATION_NAME: { final Player.OnSeek apiNotification = new Player.OnSeek(params); - for (final PlayerNotificationsObserver observer : - playerNotificationsObservers.keySet()) { + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { Handler handler = playerNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -774,10 +778,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Player.OnSpeedChanged.NOTIFICATION_NAME)) { + break; + } + case Player.OnSpeedChanged.NOTIFICATION_NAME: { final Player.OnSpeedChanged apiNotification = new Player.OnSpeedChanged(params); - for (final PlayerNotificationsObserver observer : - playerNotificationsObservers.keySet()) { + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { Handler handler = playerNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -786,10 +791,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Player.OnStop.NOTIFICATION_NAME)) { + break; + } + case Player.OnStop.NOTIFICATION_NAME: { final Player.OnStop apiNotification = new Player.OnStop(params); - for (final PlayerNotificationsObserver observer : - playerNotificationsObservers.keySet()) { + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { Handler handler = playerNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -798,10 +804,37 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Player.OnPropertyChanged.NOTIFICATION_NAME)) { + break; + } + case Player.OnAVStart.NOTIFICATION_NAME: { + final Player.OnAVStart apiNotification = new Player.OnAVStart(params); + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { + Handler handler = playerNotificationsObservers.get(observer); + postOrRunNow(handler, new Runnable() { + @Override + public void run() { + observer.onAVStart(apiNotification); + } + }); + } + break; + } + case Player.OnAVChange.NOTIFICATION_NAME: { + final Player.OnAVChange apiNotification = new Player.OnAVChange(params); + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { + Handler handler = playerNotificationsObservers.get(observer); + postOrRunNow(handler, new Runnable() { + @Override + public void run() { + observer.onAVChange(apiNotification); + } + }); + } + break; + } + case Player.OnPropertyChanged.NOTIFICATION_NAME: { final Player.OnPropertyChanged apiNotification = new Player.OnPropertyChanged(params); - for (final PlayerNotificationsObserver observer : - playerNotificationsObservers.keySet()) { + for (final PlayerNotificationsObserver observer : playerNotificationsObservers.keySet()) { Handler handler = playerNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -810,10 +843,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(System.OnQuit.NOTIFICATION_NAME)) { + break; + } + case System.OnQuit.NOTIFICATION_NAME: { final System.OnQuit apiNotification = new System.OnQuit(params); - for (final SystemNotificationsObserver observer : - systemNotificationsObservers.keySet()) { + for (final SystemNotificationsObserver observer : systemNotificationsObservers.keySet()) { Handler handler = systemNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -822,10 +856,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(System.OnRestart.NOTIFICATION_NAME)) { + break; + } + case System.OnRestart.NOTIFICATION_NAME: { final System.OnRestart apiNotification = new System.OnRestart(params); - for (final SystemNotificationsObserver observer : - systemNotificationsObservers.keySet()) { + for (final SystemNotificationsObserver observer : systemNotificationsObservers.keySet()) { Handler handler = systemNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -834,10 +869,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(System.OnSleep.NOTIFICATION_NAME)) { + break; + } + case System.OnSleep.NOTIFICATION_NAME: { final System.OnSleep apiNotification = new System.OnSleep(params); - for (final SystemNotificationsObserver observer : - systemNotificationsObservers.keySet()) { + for (final SystemNotificationsObserver observer : systemNotificationsObservers.keySet()) { Handler handler = systemNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -846,10 +882,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Input.OnInputRequested.NOTIFICATION_NAME)) { + break; + } + case Input.OnInputRequested.NOTIFICATION_NAME: { final Input.OnInputRequested apiNotification = new Input.OnInputRequested(params); - for (final InputNotificationsObserver observer : - inputNotificationsObservers.keySet()) { + for (final InputNotificationsObserver observer : inputNotificationsObservers.keySet()) { Handler handler = inputNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -858,11 +895,11 @@ public class HostConnection { } }); } - } else if (notificationName.equals(Application.OnVolumeChanged.NOTIFICATION_NAME)) { - final Application.OnVolumeChanged apiNotification = - new Application.OnVolumeChanged(params); - for (final ApplicationNotificationsObserver observer : - applicationNotificationsObservers.keySet()) { + break; + } + case Application.OnVolumeChanged.NOTIFICATION_NAME: { + final Application.OnVolumeChanged apiNotification = new Application.OnVolumeChanged(params); + for (final ApplicationNotificationsObserver observer : applicationNotificationsObservers.keySet()) { Handler handler = applicationNotificationsObservers.get(observer); postOrRunNow(handler, new Runnable() { @Override @@ -871,8 +908,8 @@ public class HostConnection { } }); } - } - + break; + }} LogUtils.LOGD(TAG, "Got a notification: " + jsonResponse.get("method").textValue()); } else { String methodId = jsonResponse.get(ApiMethod.ID_NODE).asText(); diff --git a/app/src/main/java/org/xbmc/kore/jsonrpc/notification/Player.java b/app/src/main/java/org/xbmc/kore/jsonrpc/notification/Player.java index 85e9ea4..05b523e 100644 --- a/app/src/main/java/org/xbmc/kore/jsonrpc/notification/Player.java +++ b/app/src/main/java/org/xbmc/kore/jsonrpc/notification/Player.java @@ -158,6 +158,42 @@ public class Player { public String getNotificationName() { return NOTIFICATION_NAME; } } + /** + * Player.OnAVStart notification + * Will be triggered on playback start if the first frame was drawn. + * If there is no ID available extra information will be provided + */ + public static class OnAVStart extends ApiNotification { + public static final String NOTIFICATION_NAME = "Player.OnAVStart"; + + public final NotificationsData data; + + public OnAVStart(ObjectNode node) { + super(node); + data = new NotificationsData(node.get(NotificationsData.DATA_NODE)); + } + + public String getNotificationName() { return NOTIFICATION_NAME; } + } + + /** + * Player.OnAVChange notification + * Audio- or videostream has changed. + * If there is no ID available extra information will be provided + */ + public static class OnAVChange extends ApiNotification { + public static final String NOTIFICATION_NAME = "Player.OnAVChange"; + + public final NotificationsData data; + + public OnAVChange(ObjectNode node) { + super(node); + data = new NotificationsData(node.get(NotificationsData.DATA_NODE)); + } + + public String getNotificationName() { return NOTIFICATION_NAME; } + } + /** * Notification data for Player */