[mobile] support cast - part 3

pull/123/head
FongMi 3 years ago
parent 70ff917977
commit 897b364daf
  1. 1
      app/build.gradle
  2. 2
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/PushActivity.java
  3. 2
      app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/ConfigDialog.java
  4. 7
      app/src/main/java/com/fongmi/android/tv/bean/Device.java
  5. 17
      app/src/main/java/com/fongmi/android/tv/db/AppDatabase.java
  6. 6
      app/src/main/java/com/fongmi/android/tv/event/RefreshEvent.java
  7. 8
      app/src/main/java/com/fongmi/android/tv/server/Server.java
  8. 7
      app/src/mobile/AndroidManifest.xml
  9. 21
      app/src/mobile/java/com/fongmi/android/tv/ui/activity/DetailActivity.java
  10. 1
      app/src/mobile/java/com/fongmi/android/tv/ui/activity/MainActivity.java
  11. 3
      app/src/mobile/java/com/fongmi/android/tv/ui/fragment/VodFragment.java
  12. 10
      app/src/mobile/res/drawable/ic_cast_refresh.xml
  13. 40
      app/src/mobile/res/drawable/ic_cast_scan.xml
  14. 13
      app/src/mobile/res/layout/activity_scan.xml
  15. 29
      app/src/mobile/res/layout/adapter_device.xml
  16. 53
      app/src/mobile/res/layout/dialog_cast.xml
  17. 25
      app/src/mobile/res/layout/view_scanner.xml
  18. 6
      app/src/mobile/res/values-zh-rCN/strings.xml
  19. 6
      app/src/mobile/res/values-zh-rTW/strings.xml
  20. 6
      app/src/mobile/res/values/strings.xml

@ -110,6 +110,7 @@ dependencies {
leanbackImplementation 'androidx.leanback:leanback:1.2.0-alpha02'
leanbackImplementation 'me.jessyan:autosize:1.2.1'
mobileImplementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
mobileImplementation('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false }
annotationProcessor 'androidx.room:room-compiler:2.5.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
}

@ -29,7 +29,7 @@ public class PushActivity extends BaseActivity {
@Override
protected void initView() {
String address = Server.get().getAddress(false);
String address = Server.get().getAddress();
mBinding.code.setImageBitmap(QRCode.getBitmap(address, 250, 1));
mBinding.info.setText(ResUtil.getString(R.string.push_info, address));
mBinding.clip.setOnClickListener(this::onClip);

@ -70,7 +70,7 @@ public class ConfigDialog implements DialogInterface.OnDismissListener {
}
private void initView() {
String address = Server.get().getAddress(false);
String address = Server.get().getAddress();
binding.text.setText(url = getUrl());
binding.text.setSelection(url.length());
binding.code.setImageBitmap(QRCode.getBitmap(address, 200, 0));

@ -1,5 +1,6 @@
package com.fongmi.android.tv.bean;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@ -32,7 +33,7 @@ public class Device {
Device device = new Device();
device.setUuid(Utils.getDeviceId());
device.setName(Utils.getDeviceName());
device.setIp(Server.get().getAddress(false));
device.setIp(Server.get().getAddress());
return device;
}
@ -72,6 +73,10 @@ public class Device {
this.ip = ip;
}
public String getHost() {
return Uri.parse(getIp()).getHost();
}
public Device save() {
AppDatabase.get().getDeviceDao().insertOrUpdate(this);
return this;

@ -11,20 +11,22 @@ import androidx.sqlite.db.SupportSQLiteDatabase;
import com.fongmi.android.tv.App;
import com.fongmi.android.tv.bean.Config;
import com.fongmi.android.tv.bean.Device;
import com.fongmi.android.tv.bean.History;
import com.fongmi.android.tv.bean.Keep;
import com.fongmi.android.tv.bean.Site;
import com.fongmi.android.tv.bean.Track;
import com.fongmi.android.tv.db.dao.ConfigDao;
import com.fongmi.android.tv.db.dao.DeviceDao;
import com.fongmi.android.tv.db.dao.HistoryDao;
import com.fongmi.android.tv.db.dao.KeepDao;
import com.fongmi.android.tv.db.dao.SiteDao;
import com.fongmi.android.tv.db.dao.TrackDao;
@Database(entities = {Keep.class, Site.class, Track.class, Config.class, History.class}, version = AppDatabase.VERSION)
@Database(entities = {Keep.class, Site.class, Track.class, Config.class, Device.class, History.class}, version = AppDatabase.VERSION)
public abstract class AppDatabase extends RoomDatabase {
public static final int VERSION = 20;
public static final int VERSION = 21;
public static final String SYMBOL = "@@@";
private static volatile AppDatabase instance;
@ -45,6 +47,7 @@ public abstract class AppDatabase extends RoomDatabase {
.addMigrations(MIGRATION_17_18)
.addMigrations(MIGRATION_18_19)
.addMigrations(MIGRATION_19_20)
.addMigrations(MIGRATION_20_21)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();
@ -58,6 +61,8 @@ public abstract class AppDatabase extends RoomDatabase {
public abstract ConfigDao getConfigDao();
public abstract DeviceDao getDeviceDao();
public abstract HistoryDao getHistoryDao();
static final Migration MIGRATION_11_12 = new Migration(11, 12) {
@ -126,4 +131,12 @@ public abstract class AppDatabase extends RoomDatabase {
database.execSQL("ALTER TABLE Config ADD COLUMN name TEXT DEFAULT NULL");
}
};
static final Migration MIGRATION_20_21 = new Migration(20, 21) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Device` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `uuid` TEXT, `name` TEXT, `ip` TEXT)");
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_Device_uuid_name` ON `Device` (`uuid`, `name`)");
}
};
}

@ -6,6 +6,10 @@ public class RefreshEvent {
private final Type type;
public static void empty() {
EventBus.getDefault().post(new RefreshEvent(Type.EMPTY));
}
public static void image() {
EventBus.getDefault().post(new RefreshEvent(Type.IMAGE));
}
@ -39,6 +43,6 @@ public class RefreshEvent {
}
public enum Type {
IMAGE, VIDEO, HISTORY, KEEP, SIZE, WALL
EMPTY, IMAGE, VIDEO, HISTORY, KEEP, SIZE, WALL
}
}

@ -31,14 +31,18 @@ public class Server implements Nano.Listener {
this.port = 9978;
}
public String getAddress(boolean local) {
return "http://" + (local ? "127.0.0.1" : getIP()) + ":" + port;
public String getAddress() {
return getAddress(false);
}
public String getAddress(String path) {
return getAddress(true) + "/" + path;
}
public String getAddress(boolean local) {
return "http://" + (local ? "127.0.0.1" : getIP()) + ":" + port;
}
public void start() {
if (nano != null) return;
do {

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fongmi.android.tv">
<uses-permission android:name="android.permission.CAMERA" />
<application>
<meta-data
@ -62,5 +64,10 @@
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="userPortrait" />
<activity
android:name=".ui.activity.ScanActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="userPortrait" />
</application>
</manifest>

@ -37,16 +37,16 @@ import com.fongmi.android.tv.bean.Parse;
import com.fongmi.android.tv.bean.Site;
import com.fongmi.android.tv.bean.Track;
import com.fongmi.android.tv.bean.Vod;
import com.fongmi.android.tv.cast.Cast;
import com.fongmi.android.tv.databinding.ActivityDetailBinding;
import com.fongmi.android.tv.db.AppDatabase;
import com.fongmi.android.tv.event.ErrorEvent;
import com.fongmi.android.tv.event.PlayerEvent;
import com.fongmi.android.tv.event.RefreshEvent;
import com.fongmi.android.tv.model.SiteViewModel;
import com.fongmi.android.tv.pip.PiP;
import com.fongmi.android.tv.pip.Receiver;
import com.fongmi.android.tv.player.ExoUtil;
import com.fongmi.android.tv.player.Players;
import com.fongmi.android.tv.pip.Receiver;
import com.fongmi.android.tv.ui.adapter.EpisodeAdapter;
import com.fongmi.android.tv.ui.adapter.FlagAdapter;
import com.fongmi.android.tv.ui.adapter.ParseAdapter;
@ -55,12 +55,12 @@ import com.fongmi.android.tv.ui.base.BaseActivity;
import com.fongmi.android.tv.ui.custom.CustomKeyDownVod;
import com.fongmi.android.tv.ui.custom.SpaceItemDecoration;
import com.fongmi.android.tv.ui.custom.ViewType;
import com.fongmi.android.tv.ui.custom.dialog.CastDialog;
import com.fongmi.android.tv.ui.custom.dialog.ControlDialog;
import com.fongmi.android.tv.ui.custom.dialog.EpisodeDialog;
import com.fongmi.android.tv.ui.custom.dialog.TrackDialog;
import com.fongmi.android.tv.utils.Clock;
import com.fongmi.android.tv.utils.Notify;
import com.fongmi.android.tv.pip.PiP;
import com.fongmi.android.tv.utils.Prefers;
import com.fongmi.android.tv.utils.ResUtil;
import com.fongmi.android.tv.utils.Traffic;
@ -79,7 +79,7 @@ import java.util.concurrent.Executors;
import tv.danmaku.ijk.media.player.ui.IjkVideoView;
public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Listener, Cast.Listener, TrackDialog.Listener, ControlDialog.Listener, Clock.Callback, FlagAdapter.OnClickListener, EpisodeAdapter.OnClickListener, ParseAdapter.OnClickListener {
public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Listener, CastDialog.Listener, TrackDialog.Listener, ControlDialog.Listener, Clock.Callback, FlagAdapter.OnClickListener, EpisodeAdapter.OnClickListener, ParseAdapter.OnClickListener {
private ViewGroup.LayoutParams mFrameParams;
private ActivityDetailBinding mBinding;
@ -450,8 +450,8 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis
}
private void onCast() {
mBinding.control.cast.setEnabled(false);
Cast.create(this).url(ApiConfig.getUrl()).history(mHistory).start();
for (Fragment fragment : getSupportFragmentManager().getFragments()) if (fragment instanceof BottomSheetDialogFragment) return;
CastDialog.create(this).url(ApiConfig.getUrl()).history(mHistory).show(getSupportFragmentManager(), null);
}
private void onKeep() {
@ -672,6 +672,7 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis
private void showControl() {
mBinding.control.cast.setVisibility(mHistory == null || isFullscreen() ? View.GONE : View.VISIBLE);
mBinding.control.keep.setVisibility(mHistory == null || isFullscreen() ? View.GONE : View.VISIBLE);
mBinding.control.parse.setVisibility(isFullscreen() && isUseParse() ? View.VISIBLE : View.GONE);
mBinding.control.rotate.setVisibility(isFullscreen() && !isLock() ? View.VISIBLE : View.GONE);
mBinding.control.back.setVisibility(isFullscreen() && !isLock() ? View.VISIBLE : View.GONE);
@ -679,7 +680,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis
mBinding.control.setting.setVisibility(isFullscreen() ? View.GONE : View.VISIBLE);
mBinding.control.title.setVisibility(isFullscreen() ? View.VISIBLE : View.GONE);
mBinding.control.share.setVisibility(isFullscreen() ? View.GONE : View.VISIBLE);
mBinding.control.keep.setVisibility(isFullscreen() ? View.GONE : View.VISIBLE);
mBinding.control.lock.setVisibility(isFullscreen() ? View.VISIBLE : View.GONE);
mBinding.control.size.setVisibility(isFullscreen() ? View.VISIBLE : View.GONE);
mBinding.control.center.setVisibility(isLock() ? View.GONE : View.VISIBLE);
@ -1033,16 +1033,13 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis
@Override
public void onCastTo(Device device) {
Notify.show(getString(R.string.cast_device, device.getName()));
mBinding.control.cast.setEnabled(true);
Notify.show(getString(R.string.cast_to, device.getName()));
checkPlayImg(false);
mPlayers.pause();
}
@Override
public void onCastError(int resId) {
mBinding.control.cast.setEnabled(true);
Notify.show(resId);
public void onCastError() {
}
@Override

@ -91,6 +91,7 @@ public class MainActivity extends BaseActivity implements NavigationBarView.OnIt
@Override
public void error(int resId) {
RefreshEvent.empty();
Notify.show(resId);
}
};

@ -208,6 +208,9 @@ public class VodFragment extends BaseFragment implements SiteCallback, FilterCal
@Subscribe(threadMode = ThreadMode.MAIN)
public void onRefreshEvent(RefreshEvent event) {
switch (event.getType()) {
case EMPTY:
hideProgress();
break;
case VIDEO:
case SIZE:
homeContent();

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/grey_500"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z" />
</vector>

@ -0,0 +1,40 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/grey_500"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M3,11h8V3H3V11zM5,5h4v4H5V5z" />
<path
android:fillColor="@android:color/white"
android:pathData="M3,21h8v-8H3V21zM5,15h4v4H5V15z" />
<path
android:fillColor="@android:color/white"
android:pathData="M13,3v8h8V3H13zM19,9h-4V5h4V9z" />
<path
android:fillColor="@android:color/white"
android:pathData="M19,19h2v2h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M13,13h2v2h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M15,15h2v2h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M13,17h2v2h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M15,19h2v2h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M17,17h2v2h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M17,13h2v2h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M19,15h2v2h-2z" />
</vector>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:id="@+id/scanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:zxing_scanner_layout="@layout/view_scanner" />
</FrameLayout>

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@drawable/shape_text"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="Google Chrome Cast" />
<TextView
android:id="@+id/host"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="127.0.0.1" />
</LinearLayout>

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/cast_select"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" />
<ImageView
android:id="@+id/scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_cast_scan" />
<ImageView
android:id="@+id/refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_cast_refresh" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:padding="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/adapter_device" />
</LinearLayout>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.journeyapps.barcodescanner.BarcodeView
android:id="@+id/zxing_barcode_surface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.journeyapps.barcodescanner.ViewfinderView
android:id="@+id/zxing_viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/zxing_status_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="16dp"
android:background="@color/zxing_transparent"
android:text="@string/cast_scan"
android:textColor="@color/zxing_status_text"
android:textSize="16sp" />
</merge>

@ -21,8 +21,10 @@
<string name="detail_search">快搜“<xliff:g name="name">%s</xliff:g></string>
<!-- Cast -->
<string name="cast_device_empty">找不到装置</string>
<string name="cast_device">已投放至“<xliff:g name="name">%s</xliff:g></string>
<string name="cast_error">找不到装置</string>
<string name="cast_select">选择装置</string>
<string name="cast_scan">请扫描影视 QRCode 进行绑定</string>
<string name="cast_to">已投放至“<xliff:g name="name">%s</xliff:g></string>
<!-- Control -->
<string name="control_speed">倍速</string>

@ -21,8 +21,10 @@
<string name="detail_search">快搜「<xliff:g name="name">%s</xliff:g></string>
<!-- Cast -->
<string name="cast_device_empty">找不到裝置</string>
<string name="cast_device">已投放至「<xliff:g name="name">%s</xliff:g></string>
<string name="cast_error">找不到裝置</string>
<string name="cast_select">選擇裝置</string>
<string name="cast_scan">請掃描影視 QRCode 進行綁定</string>
<string name="cast_to">已投放至「<xliff:g name="name">%s</xliff:g></string>
<!-- Control -->
<string name="control_speed">倍速</string>

@ -21,8 +21,10 @@
<string name="detail_search">Searching <xliff:g name="name">%s</xliff:g></string>
<!-- Cast -->
<string name="cast_device_empty">Could\'t find a device to cast</string>
<string name="cast_device">Cast to <xliff:g name="name">%s</xliff:g></string>
<string name="cast_error">Could\'t find a device to cast</string>
<string name="cast_select">Select devices</string>
<string name="cast_scan">Please scan QR Code to bind</string>
<string name="cast_to">Cast to <xliff:g name="name">%s</xliff:g></string>
<!-- Control -->
<string name="control_speed">Speed</string>

Loading…
Cancel
Save