Add cast support #123
This commit is contained in:
parent
680bdf7bd2
commit
5757a8b1d8
|
@ -126,7 +126,7 @@ dependencies {
|
|||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.browser:browser:1.2.0'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
|
||||
|
@ -155,5 +155,7 @@ dependencies {
|
|||
implementation "androidx.work:work-runtime:2.4.0"
|
||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
||||
implementation 'su.litvak.chromecast:api-v2:0.11.3'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-core:2.12.0'
|
||||
|
||||
}
|
|
@ -17,7 +17,8 @@
|
|||
<string name="set_video_sensitive_choice" translatable="false">set_video_sensitive_choice</string>
|
||||
<string name="set_video_in_list">Vidéos dans une liste</string>
|
||||
<string name="set_video_in_list_description">Change la mise en page pour afficher les vidéos dans une liste</string>
|
||||
|
||||
<string name="cast">ChromeCast</string>
|
||||
<string name="chromecast_choice">Choix de la ChromeCast</string>
|
||||
<string name="_retry">Réessayer</string>
|
||||
<string name="refresh_token_failed">Échec de rafraîchissement du jeton d\'accès</string>
|
||||
<string name="refresh_token_failed_message">Vous pouvez réessayer de le rafraîchir ou simplement déconnecter le compte</string>
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
<string name="no_instances">No instances !</string>
|
||||
<string name="show_more">Show more</string>
|
||||
<string name="show_less">Show less</string>
|
||||
|
||||
<string name="cast">ChromeCast</string>
|
||||
<string name="chromecast_choice">ChromeCast choice</string>
|
||||
<string name="set_play_screen_lock">Screen lock</string>
|
||||
<string name="set_play_screen_lock_description">Keep playing videos when the screen is locked</string>
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
<string name="no_instances">No instances !</string>
|
||||
<string name="show_more">Show more</string>
|
||||
<string name="show_less">Show less</string>
|
||||
<string name="cast">ChromeCast</string>
|
||||
<string name="chromecast_choice">ChromeCast choice</string>
|
||||
|
||||
<string name="set_play_screen_lock">Screen lock</string>
|
||||
<string name="set_play_screen_lock_description">Keep playing videos when the screen is locked</string>
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -47,6 +48,11 @@ import com.kobakei.ratethisapp.RateThisApp;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -77,6 +83,7 @@ import app.fedilab.fedilabtube.sqlite.Sqlite;
|
|||
import app.fedilab.fedilabtube.sqlite.StoredInstanceDAO;
|
||||
import app.fedilab.fedilabtube.viewmodel.TimelineVM;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
import su.litvak.chromecast.api.v2.ChromeCasts;
|
||||
|
||||
import static app.fedilab.fedilabtube.MainActivity.TypeOfConnection.NORMAL;
|
||||
import static app.fedilab.fedilabtube.MainActivity.TypeOfConnection.SURFING;
|
||||
|
@ -198,6 +205,36 @@ public class MainActivity extends AppCompatActivity {
|
|||
View view = binding.getRoot();
|
||||
setContentView(view);
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<NetworkInterface> interfaces;
|
||||
interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||
for (NetworkInterface ni : interfaces) {
|
||||
if ((!ni.isLoopback()) && ni.isUp() && (ni.getName().equals("wlan0"))) {
|
||||
Enumeration<InetAddress> inetAddressEnumeration = ni.getInetAddresses();
|
||||
while (inetAddressEnumeration.hasMoreElements()) {
|
||||
InetAddress inetAddress = inetAddressEnumeration.nextElement();
|
||||
ChromeCasts.restartDiscovery(inetAddress);
|
||||
PeertubeActivity.chromeCasts = ChromeCasts.get();
|
||||
int tryFind = 0;
|
||||
while (PeertubeActivity.chromeCasts.isEmpty() && tryFind < 5) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
PeertubeActivity.chromeCasts = ChromeCasts.get();
|
||||
tryFind++;
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = this::invalidateOptionsMenu;
|
||||
mainHandler.post(myRunnable);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
|
@ -722,7 +759,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
return locaFragment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return overviewFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,6 +44,7 @@ import android.text.method.LinkMovementMethod;
|
|||
import android.text.style.ClickableSpan;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
@ -103,6 +104,8 @@ import com.google.android.exoplayer2.video.VideoListener;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -133,6 +136,7 @@ import app.fedilab.fedilabtube.drawer.CommentListAdapter;
|
|||
import app.fedilab.fedilabtube.drawer.MenuAdapter;
|
||||
import app.fedilab.fedilabtube.drawer.MenuItemAdapter;
|
||||
import app.fedilab.fedilabtube.helper.CacheDataSourceFactory;
|
||||
import app.fedilab.fedilabtube.helper.DashCastRequest;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.helper.HelperInstance;
|
||||
import app.fedilab.fedilabtube.sqlite.AccountDAO;
|
||||
|
@ -147,6 +151,11 @@ import app.fedilab.fedilabtube.webview.CustomWebview;
|
|||
import app.fedilab.fedilabtube.webview.MastalabWebChromeClient;
|
||||
import app.fedilab.fedilabtube.webview.MastalabWebViewClient;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
import su.litvak.chromecast.api.v2.Application;
|
||||
import su.litvak.chromecast.api.v2.ChromeCast;
|
||||
import su.litvak.chromecast.api.v2.ChromeCasts;
|
||||
import su.litvak.chromecast.api.v2.ChromeCastsListener;
|
||||
import su.litvak.chromecast.api.v2.Status;
|
||||
|
||||
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.ADD_COMMENT;
|
||||
import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.RATEVIDEO;
|
||||
|
@ -160,7 +169,7 @@ import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation;
|
|||
import static com.google.android.exoplayer2.Player.MEDIA_ITEM_TRANSITION_REASON_AUTO;
|
||||
|
||||
|
||||
public class PeertubeActivity extends AppCompatActivity implements CommentListAdapter.AllCommentRemoved, Player.EventListener, VideoListener, TorrentListener, MenuAdapter.ItemClicked, MenuItemAdapter.ItemAction {
|
||||
public class PeertubeActivity extends AppCompatActivity implements CommentListAdapter.AllCommentRemoved, Player.EventListener, VideoListener, TorrentListener, MenuAdapter.ItemClicked, MenuItemAdapter.ItemAction, ChromeCastsListener {
|
||||
|
||||
public static String video_id;
|
||||
public static List<String> playedVideos = new ArrayList<>();
|
||||
|
@ -194,6 +203,9 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
private String currentCaption;
|
||||
private boolean isRemote;
|
||||
private boolean willPlayFromIntent;
|
||||
public static List<ChromeCast> chromeCasts;
|
||||
private ChromeCast chromeCast;
|
||||
private String chromeCastVideoURL;
|
||||
|
||||
public static void hideKeyboard(Activity activity) {
|
||||
if (activity != null && activity.getWindow() != null) {
|
||||
|
@ -240,6 +252,14 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
public void onStreamStopped() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newChromeCastDiscovered(ChromeCast chromeCast) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chromeCastRemoved(ChromeCast chromeCast) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -263,6 +283,9 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
.removeFilesAfterStop(true)
|
||||
.build();
|
||||
|
||||
|
||||
ChromeCastsListener chromeCastsListener = this;
|
||||
ChromeCasts.registerListener(chromeCastsListener);
|
||||
fullScreenMode = false;
|
||||
torrentStream = TorrentStream.init(torrentOptions);
|
||||
torrentStream.addListener(PeertubeActivity.this);
|
||||
|
@ -661,6 +684,20 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.video_menu, menu);
|
||||
MenuItem castItem = menu.findItem(R.id.action_cast);
|
||||
if (chromeCasts != null && chromeCasts.size() > 0) {
|
||||
castItem.setVisible(true);
|
||||
if (chromeCast != null && chromeCast.isConnected()) {
|
||||
castItem.setIcon(R.drawable.ic_baseline_cast_connected_24);
|
||||
} else {
|
||||
castItem.setIcon(R.drawable.ic_baseline_cast_24);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
@ -670,6 +707,69 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
}
|
||||
finish();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_cast) {
|
||||
if (chromeCasts != null && chromeCasts.size() > 0) {
|
||||
String[] chromecast_choice = new String[chromeCasts.size()];
|
||||
AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
|
||||
alt_bld.setTitle(R.string.chromecast_choice);
|
||||
int i = 0;
|
||||
for (ChromeCast cc : chromeCasts) {
|
||||
chromecast_choice[i] = cc.getTitle();
|
||||
i++;
|
||||
}
|
||||
alt_bld.setSingleChoiceItems(chromecast_choice, i, (dialog, position) -> {
|
||||
chromeCast = chromeCasts.get(position);
|
||||
new Thread(() -> {
|
||||
if (chromeCast != null) {
|
||||
if (chromeCast.isConnected()) {
|
||||
try {
|
||||
chromeCast.disconnect();
|
||||
chromeCast = null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
chromeCast.connect();
|
||||
|
||||
|
||||
Status status = chromeCast.getStatus();
|
||||
|
||||
String app_id = status.getRunningApp().id;
|
||||
if (chromeCast.isAppAvailable(app_id) && !status.isAppRunning(app_id)) {
|
||||
Application app = chromeCast.launchApp(app_id);
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
invalidateOptionsMenu();
|
||||
dialog.dismiss();
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
if (chromeCastVideoURL != null) {
|
||||
chromeCast.load(peertube.getTitle(), "https://" + HelperInstance.getLiveInstance(PeertubeActivity.this) + peertube.getThumbnailPath(), chromeCastVideoURL, null);
|
||||
// chromeCast.send("urn:x-cast:es.offd.dashcast", new DashCastRequest(chromeCastVideoURL, true, false, 0));
|
||||
}
|
||||
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
invalidateOptionsMenu();
|
||||
dialog.dismiss();
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
});
|
||||
alt_bld.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss());
|
||||
AlertDialog alert = alt_bld.create();
|
||||
alert.show();
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
@ -1182,6 +1282,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
|
||||
private void startStream(String videoURL, String streamingPlaylistsURLS, boolean autoPlay, long position, Uri subtitles, String lang, boolean promptNSFW) {
|
||||
|
||||
chromeCastVideoURL = videoURL;
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
|
||||
String nsfwAction = sharedpreferences.getString(getString(R.string.set_video_sensitive_choice), Helper.BLUR);
|
||||
if (promptNSFW && peertube != null && peertube.isNsfw() && (nsfwAction.compareTo(Helper.BLUR) == 0 || nsfwAction.compareTo(Helper.DO_NOT_LIST) == 0)) {
|
||||
|
@ -1205,6 +1306,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
stream(videoURL, streamingPlaylistsURLS, autoPlay, position, subtitles, lang);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1247,6 +1349,14 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd
|
|||
if (torrentStream != null && torrentStream.isStreaming()) {
|
||||
torrentStream.stopStream();
|
||||
}
|
||||
ChromeCasts.unregisterListener(this);
|
||||
if (chromeCast != null) {
|
||||
try {
|
||||
chromeCast.disconnect();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
unregisterReceiver();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package app.fedilab.fedilabtube.helper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import su.litvak.chromecast.api.v2.Request;
|
||||
|
||||
public class DashCastRequest implements Request {
|
||||
@JsonProperty
|
||||
final String url;
|
||||
@JsonProperty
|
||||
final boolean force;
|
||||
@JsonProperty
|
||||
final boolean reload;
|
||||
@JsonProperty("reload_time")
|
||||
final int reloadTime;
|
||||
|
||||
private Long requestId;
|
||||
|
||||
public DashCastRequest(String url,
|
||||
boolean force,
|
||||
boolean reload,
|
||||
int reloadTime) {
|
||||
this.url = url;
|
||||
this.force = force;
|
||||
this.reload = reload;
|
||||
this.reloadTime = reloadTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestId(Long requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM19,7L5,7v1.63c3.96,1.28 7.09,4.41 8.37,8.37L19,17L19,7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_cast"
|
||||
android:icon="@drawable/ic_baseline_cast_24"
|
||||
android:title="@string/cast"
|
||||
android:visible="false"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
Loading…
Reference in New Issue