diff --git a/app/src/main/java/org/jellyfin/android/WebappActivity.kt b/app/src/main/java/org/jellyfin/android/WebappActivity.kt index ff667cc8..15d87dc0 100644 --- a/app/src/main/java/org/jellyfin/android/WebappActivity.kt +++ b/app/src/main/java/org/jellyfin/android/WebappActivity.kt @@ -14,6 +14,7 @@ import android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS import android.webkit.WebChromeClient import android.webkit.WebView import androidx.appcompat.app.AppCompatActivity +import org.jellyfin.android.bridge.NativeInterface import org.jellyfin.android.cast.Chromecast import org.jellyfin.android.utils.lazyView diff --git a/app/src/main/java/org/jellyfin/android/bridge/JavascriptCallback.kt b/app/src/main/java/org/jellyfin/android/bridge/JavascriptCallback.kt new file mode 100644 index 00000000..16a5673a --- /dev/null +++ b/app/src/main/java/org/jellyfin/android/bridge/JavascriptCallback.kt @@ -0,0 +1,23 @@ +package org.jellyfin.android.bridge + +import org.json.JSONArray +import org.json.JSONObject + +abstract class JavascriptCallback { + protected abstract fun callback(keep: Boolean, err: String?, result: String?) + + @JvmOverloads + fun success(keep: Boolean = false, result: String? = null) = callback(keep, null, result?.let { """"$it"""" }) + + @JvmOverloads + fun success(keep: Boolean = false, result: JSONObject?) = callback(keep, null, result.toString()) + + @JvmOverloads + fun success(keep: Boolean = false, result: JSONArray?) = callback(keep, null, result.toString()) + + @JvmOverloads + fun error(keep: Boolean = false, message: String) = callback(keep, """"$message"""", null) + + @JvmOverloads + fun error(keep: Boolean = false, error: JSONObject) = callback(keep, error.toString(), null) +} \ No newline at end of file diff --git a/app/src/main/java/org/jellyfin/android/NativeInterface.kt b/app/src/main/java/org/jellyfin/android/bridge/NativeInterface.kt similarity index 96% rename from app/src/main/java/org/jellyfin/android/NativeInterface.kt rename to app/src/main/java/org/jellyfin/android/bridge/NativeInterface.kt index 1af915ab..cb459e27 100644 --- a/app/src/main/java/org/jellyfin/android/NativeInterface.kt +++ b/app/src/main/java/org/jellyfin/android/bridge/NativeInterface.kt @@ -1,4 +1,4 @@ -package org.jellyfin.android +package org.jellyfin.android.bridge import android.annotation.SuppressLint import android.app.AlertDialog @@ -11,7 +11,10 @@ import android.provider.Settings.Secure import android.view.View import android.view.WindowManager import android.webkit.JavascriptInterface -import org.jellyfin.android.cast.CallbackContext +import org.jellyfin.android.BuildConfig +import org.jellyfin.android.R +import org.jellyfin.android.RemotePlayerService +import org.jellyfin.android.WebappActivity import org.jellyfin.android.utils.Constants import org.json.JSONArray import org.json.JSONObject @@ -166,7 +169,7 @@ class NativeInterface(private val activity: WebappActivity) { @JavascriptInterface fun execCast(action: String, args: String) { - activity.chromecast.execute(action, JSONArray(args), object : CallbackContext { + activity.chromecast.execute(action, JSONArray(args), object : JavascriptCallback() { override fun callback(keep: Boolean, err: String?, result: String?) { activity.runOnUiThread { activity.loadUrl("""javascript:window.NativeShell.castCallback("$action", $keep, $err, $result);""") diff --git a/app/src/main/java/org/jellyfin/android/cast/CallbackContext.kt b/app/src/main/java/org/jellyfin/android/cast/CallbackContext.kt deleted file mode 100644 index cade13e7..00000000 --- a/app/src/main/java/org/jellyfin/android/cast/CallbackContext.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.jellyfin.android.cast - -import org.json.JSONObject - -interface CallbackContext { - fun callback(keep: Boolean = false, err: String? = null, result: String? = null) - - fun success() = callback() - fun success(result: JSONObject) = callback(result = result.toString()) - fun errorString(message: String) = callback(err = """"$message"""") - fun error(error: JSONObject) = callback(err = error.toString()) -} \ No newline at end of file diff --git a/app/src/main/java/org/jellyfin/android/cast/Chromecast.java b/app/src/main/java/org/jellyfin/android/cast/Chromecast.java index b801ad3c..f3ede796 100644 --- a/app/src/main/java/org/jellyfin/android/cast/Chromecast.java +++ b/app/src/main/java/org/jellyfin/android/cast/Chromecast.java @@ -6,6 +6,7 @@ import androidx.mediarouter.media.MediaRouter.RouteInfo; import com.google.android.gms.cast.CastDevice; +import org.jellyfin.android.bridge.JavascriptCallback; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -39,11 +40,11 @@ public final class Chromecast { /** * Holds the reference to the current client initiated scan callback. */ - private CallbackContext scanCallback; + private JavascriptCallback scanCallback; /** * Client's event listener callback. */ - private CallbackContext eventCallback; + private JavascriptCallback eventCallback; /** * In the case that chromecast can't be used. **/ @@ -98,7 +99,7 @@ public final class Chromecast { } } - public boolean execute(String action, JSONArray args, CallbackContext cbContext) throws JSONException { + public boolean execute(String action, JSONArray args, JavascriptCallback cbContext) throws JSONException { if (noChromecastError != null) { cbContext.error(ChromecastUtilities.createError("api_not_initialized", noChromecastError)); return true; @@ -167,11 +168,11 @@ public final class Chromecast { * Do everything you need to for "setup" - calling back sets the isAvailable and lets every function on the * javascript side actually do stuff. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean setup(CallbackContext callbackContext) { - this.eventCallback = callbackContext; + public boolean setup(JavascriptCallback javascriptCallback) { + this.eventCallback = javascriptCallback; // Ensure any existing scan is stopped connection.stopRouteScan(clientScan, () -> { if (scanCallback != null) { @@ -190,11 +191,11 @@ public final class Chromecast { * @param appId The appId we're going to use for ALL session requests * @param autoJoinPolicy tab_and_origin_scoped | origin_scoped | page_scoped * @param defaultActionPolicy create_session | cast_this_tab - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean initialize(final String appId, String autoJoinPolicy, String defaultActionPolicy, final CallbackContext callbackContext) { - connection.initialize(appId, callbackContext); + public boolean initialize(final String appId, String autoJoinPolicy, String defaultActionPolicy, final JavascriptCallback javascriptCallback) { + connection.initialize(appId, javascriptCallback); return true; } @@ -204,25 +205,25 @@ public final class Chromecast { * or, if we already have a session launch the connection options * dialog which will have the option to stop casting at minimum. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean requestSession(final CallbackContext callbackContext) { + public boolean requestSession(final JavascriptCallback javascriptCallback) { connection.requestSession(new ChromecastConnection.RequestSessionCallback() { @Override public void onJoin(JSONObject jsonSession) { - callbackContext.success(jsonSession); + javascriptCallback.success(jsonSession); } @Override public void onError(int errorCode) { // TODO maybe handle some of the error codes better - callbackContext.errorString("session_error"); + javascriptCallback.error("session_error"); } @Override public void onCancel() { - callbackContext.errorString("cancel"); + javascriptCallback.error("cancel"); } }); return true; @@ -231,20 +232,20 @@ public final class Chromecast { /** * Selects a route by its id. * - * @param routeId the id of the route to join - * @param callbackContext called with .success or .error depending on the result + * @param routeId the id of the route to join + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean selectRoute(final String routeId, final CallbackContext callbackContext) { + public boolean selectRoute(final String routeId, final JavascriptCallback javascriptCallback) { connection.selectRoute(routeId, new ChromecastConnection.SelectRouteCallback() { @Override public void onJoin(JSONObject jsonSession) { - callbackContext.success(jsonSession); + javascriptCallback.success(jsonSession); } @Override public void onError(JSONObject message) { - callbackContext.error(message); + javascriptCallback.error(message); } }); return true; @@ -253,120 +254,120 @@ public final class Chromecast { /** * Set the volume level on the receiver - this is a Chromecast volume, not a Media volume. * - * @param newLevel the level to set the volume to - * @param callbackContext called with .success or .error depending on the result + * @param newLevel the level to set the volume to + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean setReceiverVolumeLevel(Integer newLevel, CallbackContext callbackContext) { - return this.setReceiverVolumeLevel(newLevel.doubleValue(), callbackContext); + public boolean setReceiverVolumeLevel(Integer newLevel, JavascriptCallback javascriptCallback) { + return this.setReceiverVolumeLevel(newLevel.doubleValue(), javascriptCallback); } /** * Set the volume level on the receiver - this is a Chromecast volume, not a Media volume. * - * @param newLevel the level to set the volume to - * @param callbackContext called with .success or .error depending on the result + * @param newLevel the level to set the volume to + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean setReceiverVolumeLevel(Double newLevel, CallbackContext callbackContext) { - this.media.setVolume(newLevel, callbackContext); + public boolean setReceiverVolumeLevel(Double newLevel, JavascriptCallback javascriptCallback) { + this.media.setVolume(newLevel, javascriptCallback); return true; } /** * Sets the muted boolean on the receiver - this is a Chromecast mute, not a Media mute. * - * @param muted if true set the media to muted, else, unmute - * @param callbackContext called with .success or .error depending on the result + * @param muted if true set the media to muted, else, unmute + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean setReceiverMuted(Boolean muted, CallbackContext callbackContext) { - this.media.setMute(muted, callbackContext); + public boolean setReceiverMuted(Boolean muted, JavascriptCallback javascriptCallback) { + this.media.setMute(muted, javascriptCallback); return true; } /** * Send a custom message to the receiver - we don't need this just yet... it was just simple to implement on the js side. * - * @param namespace namespace - * @param message the message to send - * @param callbackContext called with .success or .error depending on the result + * @param namespace namespace + * @param message the message to send + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean sendMessage(String namespace, String message, final CallbackContext callbackContext) { - this.media.sendMessage(namespace, message, callbackContext); + public boolean sendMessage(String namespace, String message, final JavascriptCallback javascriptCallback) { + this.media.sendMessage(namespace, message, javascriptCallback); return true; } /** * Adds a listener to a specific namespace. * - * @param namespace namespace - * @param callbackContext called with .success or .error depending on the result + * @param namespace namespace + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean addMessageListener(String namespace, CallbackContext callbackContext) { + public boolean addMessageListener(String namespace, JavascriptCallback javascriptCallback) { this.media.addMessageListener(namespace); - callbackContext.success(); + javascriptCallback.success(); return true; } /** * Loads some media on the Chromecast using the media APIs. * - * @param contentId The URL of the media item - * @param customData CustomData - * @param contentType MIME type of the content - * @param duration Duration of the content - * @param streamType buffered | live | other - * @param autoPlay Whether or not to automatically start playing the media - * @param currentTime Where to begin playing from - * @param metadata Metadata - * @param textTrackStyle The text track style - * @param callbackContext called with .success or .error depending on the result + * @param contentId The URL of the media item + * @param customData CustomData + * @param contentType MIME type of the content + * @param duration Duration of the content + * @param streamType buffered | live | other + * @param autoPlay Whether or not to automatically start playing the media + * @param currentTime Where to begin playing from + * @param metadata Metadata + * @param textTrackStyle The text track style + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean loadMedia(String contentId, JSONObject customData, String contentType, Integer duration, String streamType, Boolean autoPlay, Integer currentTime, JSONObject metadata, JSONObject textTrackStyle, final CallbackContext callbackContext) { - return this.loadMedia(contentId, customData, contentType, duration, streamType, autoPlay, new Double(currentTime.doubleValue()), metadata, textTrackStyle, callbackContext); + public boolean loadMedia(String contentId, JSONObject customData, String contentType, Integer duration, String streamType, Boolean autoPlay, Integer currentTime, JSONObject metadata, JSONObject textTrackStyle, final JavascriptCallback javascriptCallback) { + return this.loadMedia(contentId, customData, contentType, duration, streamType, autoPlay, new Double(currentTime.doubleValue()), metadata, textTrackStyle, javascriptCallback); } - private boolean loadMedia(String contentId, JSONObject customData, String contentType, Integer duration, String streamType, Boolean autoPlay, Double currentTime, JSONObject metadata, JSONObject textTrackStyle, final CallbackContext callbackContext) { - this.media.loadMedia(contentId, customData, contentType, duration, streamType, autoPlay, currentTime, metadata, textTrackStyle, callbackContext); + private boolean loadMedia(String contentId, JSONObject customData, String contentType, Integer duration, String streamType, Boolean autoPlay, Double currentTime, JSONObject metadata, JSONObject textTrackStyle, final JavascriptCallback javascriptCallback) { + this.media.loadMedia(contentId, customData, contentType, duration, streamType, autoPlay, currentTime, metadata, textTrackStyle, javascriptCallback); return true; } /** * Play on the current media in the current session. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean mediaPlay(CallbackContext callbackContext) { - media.mediaPlay(callbackContext); + public boolean mediaPlay(JavascriptCallback javascriptCallback) { + media.mediaPlay(javascriptCallback); return true; } /** * Pause on the current media in the current session. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean mediaPause(CallbackContext callbackContext) { - media.mediaPause(callbackContext); + public boolean mediaPause(JavascriptCallback javascriptCallback) { + media.mediaPause(javascriptCallback); return true; } /** * Seeks the current media in the current session. * - * @param seekTime - Seconds to seek to - * @param resumeState - Resume state once seeking is complete: PLAYBACK_PAUSE or PLAYBACK_START - * @param callbackContext called with .success or .error depending on the result + * @param seekTime - Seconds to seek to + * @param resumeState - Resume state once seeking is complete: PLAYBACK_PAUSE or PLAYBACK_START + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean mediaSeek(Integer seekTime, String resumeState, CallbackContext callbackContext) { - media.mediaSeek(seekTime.longValue() * 1000, resumeState, callbackContext); + public boolean mediaSeek(Integer seekTime, String resumeState, JavascriptCallback javascriptCallback) { + media.mediaSeek(seekTime.longValue() * 1000, resumeState, javascriptCallback); return true; } @@ -374,48 +375,48 @@ public final class Chromecast { /** * Set the volume level and mute state on the media. * - * @param level the level to set the volume to - * @param muted if true set the media to muted, else, unmute - * @param callbackContext called with .success or .error depending on the result + * @param level the level to set the volume to + * @param muted if true set the media to muted, else, unmute + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean setMediaVolume(Integer level, Boolean muted, CallbackContext callbackContext) { - return this.setMediaVolume(level.doubleValue(), muted, callbackContext); + public boolean setMediaVolume(Integer level, Boolean muted, JavascriptCallback javascriptCallback) { + return this.setMediaVolume(level.doubleValue(), muted, javascriptCallback); } /** * Set the volume level and mute state on the media. * - * @param level the level to set the volume to - * @param muted if true set the media to muted, else, unmute - * @param callbackContext called with .success or .error depending on the result + * @param level the level to set the volume to + * @param muted if true set the media to muted, else, unmute + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean setMediaVolume(Double level, Boolean muted, CallbackContext callbackContext) { - media.mediaSetVolume(level, muted, callbackContext); + public boolean setMediaVolume(Double level, Boolean muted, JavascriptCallback javascriptCallback) { + media.mediaSetVolume(level, muted, javascriptCallback); return true; } /** * Stops the current media. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean mediaStop(CallbackContext callbackContext) { - media.mediaStop(callbackContext); + public boolean mediaStop(JavascriptCallback javascriptCallback) { + media.mediaStop(javascriptCallback); return true; } /** * Handle Track changes. * - * @param activeTrackIds track Ids to set. - * @param textTrackStyle text track style to set. - * @param callbackContext called with .success or .error depending on the result + * @param activeTrackIds track Ids to set. + * @param textTrackStyle text track style to set. + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean mediaEditTracksInfo(JSONArray activeTrackIds, JSONObject textTrackStyle, final CallbackContext callbackContext) { + public boolean mediaEditTracksInfo(JSONArray activeTrackIds, JSONObject textTrackStyle, final JavascriptCallback javascriptCallback) { long[] trackIds = new long[activeTrackIds.length()]; try { @@ -426,45 +427,45 @@ public final class Chromecast { Timber.tag(TAG).e("Wrong format in activeTrackIds"); } - this.media.mediaEditTracksInfo(trackIds, textTrackStyle, callbackContext); + this.media.mediaEditTracksInfo(trackIds, textTrackStyle, javascriptCallback); return true; } /** * Loads a queue of media to the Chromecast. * - * @param queueLoadRequest chrome.cast.media.QueueLoadRequest - * @param callbackContext called with .success or .error depending on the result + * @param queueLoadRequest chrome.cast.media.QueueLoadRequest + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean queueLoad(JSONObject queueLoadRequest, final CallbackContext callbackContext) { - this.media.queueLoad(queueLoadRequest, callbackContext); + public boolean queueLoad(JSONObject queueLoadRequest, final JavascriptCallback javascriptCallback) { + this.media.queueLoad(queueLoadRequest, javascriptCallback); return true; } /** * Plays the item with itemId in the queue. * - * @param itemId The ID of the item to jump to. - * @param callbackContext called with .success or .error depending on the result + * @param itemId The ID of the item to jump to. + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean queueJumpToItem(Integer itemId, final CallbackContext callbackContext) { - this.media.queueJumpToItem(itemId, callbackContext); + public boolean queueJumpToItem(Integer itemId, final JavascriptCallback javascriptCallback) { + this.media.queueJumpToItem(itemId, javascriptCallback); return true; } /** * Plays the item with itemId in the queue. * - * @param itemId The ID of the item to jump to. - * @param callbackContext called with .success or .error depending on the result + * @param itemId The ID of the item to jump to. + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean queueJumpToItem(Double itemId, final CallbackContext callbackContext) { + public boolean queueJumpToItem(Double itemId, final JavascriptCallback javascriptCallback) { if (itemId - Double.valueOf(itemId).intValue() == 0) { // Only perform the jump if the double is a whole number - return queueJumpToItem(Double.valueOf(itemId).intValue(), callbackContext); + return queueJumpToItem(Double.valueOf(itemId).intValue(), javascriptCallback); } else { return true; } @@ -473,22 +474,22 @@ public final class Chromecast { /** * Stops the session. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean sessionStop(CallbackContext callbackContext) { - connection.endSession(true, callbackContext); + public boolean sessionStop(JavascriptCallback javascriptCallback) { + connection.endSession(true, javascriptCallback); return true; } /** * Stops the session. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean sessionLeave(CallbackContext callbackContext) { - connection.endSession(false, callbackContext); + public boolean sessionLeave(JavascriptCallback javascriptCallback) { + connection.endSession(false, javascriptCallback); return true; } @@ -497,20 +498,20 @@ public final class Chromecast { * It is super important that client calls "stopRouteScan", otherwise the * battery could drain quickly. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean startRouteScan(CallbackContext callbackContext) { + public boolean startRouteScan(JavascriptCallback javascriptCallback) { if (scanCallback != null) { scanCallback.error(ChromecastUtilities.createError("cancel", "Started a new route scan before stopping previous one.")); } - scanCallback = callbackContext; + scanCallback = javascriptCallback; Runnable startScan = () -> { clientScan = new ChromecastConnection.ScanCallback() { @Override void onRouteUpdate(List routes) { if (scanCallback != null) { - scanCallback.callback(true, null, ChromecastUtilities.createRoutesArray(routes).toString()); + scanCallback.success(true, ChromecastUtilities.createRoutesArray(routes)); } else { // Try to get the scan to stop because we already ended the scanCallback connection.stopRouteScan(clientScan, null); @@ -531,17 +532,17 @@ public final class Chromecast { /** * Stops the scan started by startRouteScan. * - * @param callbackContext called with .success or .error depending on the result + * @param javascriptCallback called with .success or .error depending on the result * @return true for cordova */ - public boolean stopRouteScan(CallbackContext callbackContext) { + public boolean stopRouteScan(JavascriptCallback javascriptCallback) { // Stop any other existing clientScan connection.stopRouteScan(clientScan, () -> { if (scanCallback != null) { scanCallback.error(ChromecastUtilities.createError("cancel", "Scan stopped.")); scanCallback = null; } - callbackContext.success(); + javascriptCallback.success(); }); return true; } @@ -556,6 +557,6 @@ public final class Chromecast { if (eventCallback == null) { return; } - eventCallback.callback(true, null, new JSONArray().put(eventName).put(args).toString()); + eventCallback.success(true, new JSONArray().put(eventName).put(args)); } } diff --git a/app/src/main/java/org/jellyfin/android/cast/ChromecastConnection.java b/app/src/main/java/org/jellyfin/android/cast/ChromecastConnection.java index 8163b481..5cfc2d13 100644 --- a/app/src/main/java/org/jellyfin/android/cast/ChromecastConnection.java +++ b/app/src/main/java/org/jellyfin/android/cast/ChromecastConnection.java @@ -22,6 +22,7 @@ import com.google.android.gms.cast.framework.SessionManager; import com.google.android.gms.cast.framework.SessionManagerListener; import org.jellyfin.android.R; +import org.jellyfin.android.bridge.JavascriptCallback; import org.json.JSONObject; import java.util.ArrayList; @@ -94,7 +95,7 @@ public class ChromecastConnection { * @param applicationId the app id to use * @param callback called when initialization is complete */ - public void initialize(String applicationId, CallbackContext callback) { + public void initialize(String applicationId, JavascriptCallback callback) { activity.runOnUiThread(new Runnable() { public void run() { // If the app Id changed @@ -463,7 +464,7 @@ public class ChromecastConnection { * @param stopCasting should the receiver application be stopped as well? * @param callback called with .success or .error depending on the initial result */ - void endSession(boolean stopCasting, CallbackContext callback) { + void endSession(boolean stopCasting, JavascriptCallback callback) { activity.runOnUiThread(new Runnable() { public void run() { getSessionManager().addSessionManagerListener(new SessionListener() { diff --git a/app/src/main/java/org/jellyfin/android/cast/ChromecastSession.java b/app/src/main/java/org/jellyfin/android/cast/ChromecastSession.java index 53821cb8..a874920e 100644 --- a/app/src/main/java/org/jellyfin/android/cast/ChromecastSession.java +++ b/app/src/main/java/org/jellyfin/android/cast/ChromecastSession.java @@ -17,6 +17,7 @@ import com.google.android.gms.cast.framework.media.RemoteMediaClient; import com.google.android.gms.cast.framework.media.RemoteMediaClient.MediaChannelResult; import com.google.android.gms.common.api.ResultCallback; +import org.jellyfin.android.bridge.JavascriptCallback; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -198,16 +199,16 @@ public class ChromecastSession { * @param message the message to send * @param callback called with success or error */ - public void sendMessage(String namespace, String message, CallbackContext callback) { + public void sendMessage(String namespace, String message, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> session.sendMessage(namespace, message).setResultCallback(result -> { if (!result.isSuccess()) { callback.success(); } else { - callback.errorString(result.toString()); + callback.error(result.toString()); } })); } @@ -228,9 +229,9 @@ public class ChromecastSession { * @param textTrackStyle - The text track style * @param callback called with success or error */ - public void loadMedia(String contentId, JSONObject customData, String contentType, long duration, String streamType, boolean autoPlay, double currentTime, JSONObject metadata, JSONObject textTrackStyle, CallbackContext callback) { + public void loadMedia(String contentId, JSONObject customData, String contentType, long duration, String streamType, boolean autoPlay, double currentTime, JSONObject metadata, JSONObject textTrackStyle, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> { @@ -246,7 +247,7 @@ public class ChromecastSession { client.load(loadRequest).setResultCallback(result -> { requestingMedia = false; if (!result.getStatus().isSuccess()) { - callback.errorString("session_error"); + callback.error("session_error"); setQueueReloadCallback(null); } }); @@ -258,9 +259,9 @@ public class ChromecastSession { * * @param callback called with success or error */ - public void mediaPlay(CallbackContext callback) { + public void mediaPlay(JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> client.play() @@ -272,9 +273,9 @@ public class ChromecastSession { * * @param callback called with success or error */ - public void mediaPause(CallbackContext callback) { + public void mediaPause(JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> client.pause() @@ -288,9 +289,9 @@ public class ChromecastSession { * @param resumeState - Resume state once seeking is complete: PLAYBACK_PAUSE or PLAYBACK_START * @param callback called with success or error */ - public void mediaSeek(long seekPosition, String resumeState, CallbackContext callback) { + public void mediaSeek(long seekPosition, String resumeState, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> { @@ -321,9 +322,9 @@ public class ChromecastSession { * @param muted if true set the media to muted, else, unmute * @param callback called with success or error */ - public void mediaSetVolume(Double level, Boolean muted, CallbackContext callback) { + public void mediaSetVolume(Double level, Boolean muted, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> { @@ -352,7 +353,7 @@ public class ChromecastSession { if (callsCompleted >= expectedCalls) { // Both the setvolume an setMute have returned if (finalErr != null) { - callback.errorString(finalErr); + callback.error(finalErr); } else { callback.success(); } @@ -390,9 +391,9 @@ public class ChromecastSession { * * @param callback called with success or error */ - public void mediaStop(CallbackContext callback) { + public void mediaStop(JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> client.stop() @@ -406,9 +407,9 @@ public class ChromecastSession { * @param textTrackStyle track style * @param callback called with success or error */ - public void mediaEditTracksInfo(long[] activeTracksIds, JSONObject textTrackStyle, CallbackContext callback) { + public void mediaEditTracksInfo(long[] activeTracksIds, JSONObject textTrackStyle, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> { @@ -580,9 +581,9 @@ public class ChromecastSession { * @param queueLoadRequest chrome.cast.media.QueueLoadRequest * @param callback called with success or error */ - public void queueLoad(JSONObject queueLoadRequest, CallbackContext callback) { + public void queueLoad(JSONObject queueLoadRequest, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> { @@ -605,7 +606,7 @@ public class ChromecastSession { setQueueReloadCallback(() -> callback.success(createMediaObject())); client.queueLoad(items, startIndex, repeatMode, playPosition, customData).setResultCallback(result -> { if (!result.getStatus().isSuccess()) { - callback.errorString("session_error"); + callback.error("session_error"); setQueueReloadCallback(null); } }); @@ -621,9 +622,9 @@ public class ChromecastSession { * @param itemId The ID of the item to jump to. * @param callback called with .success or .error depending on the result */ - public void queueJumpToItem(Integer itemId, CallbackContext callback) { + public void queueJumpToItem(Integer itemId, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } @@ -639,7 +640,7 @@ public class ChromecastSession { if (errorResult != null) { error += "\nError details: " + errorResult; } - callback.errorString(error); + callback.error(error); } }); }); @@ -653,9 +654,9 @@ public class ChromecastSession { * @param volume volume to set the receiver to * @param callback called with success or error */ - public void setVolume(double volume, CallbackContext callback) { + public void setVolume(double volume, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> { @@ -663,7 +664,7 @@ public class ChromecastSession { session.setVolume(volume); callback.success(); } catch (IOException e) { - callback.errorString("CHANNEL_ERROR"); + callback.error("CHANNEL_ERROR"); } }); } @@ -674,9 +675,9 @@ public class ChromecastSession { * @param muted if true mute, else, unmute * @param callback called with success or error */ - public void setMute(boolean muted, CallbackContext callback) { + public void setMute(boolean muted, JavascriptCallback callback) { if (client == null || session == null) { - callback.errorString("session_error"); + callback.error("session_error"); return; } activity.runOnUiThread(() -> { @@ -684,7 +685,7 @@ public class ChromecastSession { session.setMute(muted); callback.success(); } catch (IOException e) { - callback.errorString("CHANNEL_ERROR"); + callback.error("CHANNEL_ERROR"); } }); } @@ -698,7 +699,7 @@ public class ChromecastSession { * @param errorMsg error message if failure * @return a callback for use in PendingResult.setResultCallback() */ - private ResultCallback getResultCallback(CallbackContext callback, String errorMsg) { + private ResultCallback getResultCallback(JavascriptCallback callback, String errorMsg) { return result -> { if (result.getStatus().isSuccess()) { callback.success(); @@ -708,7 +709,7 @@ public class ChromecastSession { if (errorResult != null) { error += "\nError details: " + errorMsg; } - callback.errorString(error); + callback.error(error); } }; }