From 508a7af02b202bd3eaccd50429cb319f3f10004f Mon Sep 17 00:00:00 2001 From: FongMi Date: Mon, 17 Apr 2023 22:53:51 +0800 Subject: [PATCH] Upload missing files --- .../fongmi/android/tv/cast/CastDevice.java | 57 +++++++++++ .../com/fongmi/android/tv/cast/CastVideo.java | 43 ++++++++ .../com/fongmi/android/tv/cast/ScanEvent.java | 20 ++++ .../com/fongmi/android/tv/cast/ScanTask.java | 80 +++++++++++++++ .../android/tv/ui/activity/ScanActivity.java | 97 +++++++++++++++++++ .../android/tv/ui/adapter/DeviceAdapter.java | 85 ++++++++++++++++ 6 files changed, 382 insertions(+) create mode 100644 app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java create mode 100644 app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java create mode 100644 app/src/mobile/java/com/fongmi/android/tv/cast/ScanEvent.java create mode 100644 app/src/mobile/java/com/fongmi/android/tv/cast/ScanTask.java create mode 100644 app/src/mobile/java/com/fongmi/android/tv/ui/activity/ScanActivity.java create mode 100644 app/src/mobile/java/com/fongmi/android/tv/ui/adapter/DeviceAdapter.java diff --git a/app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java b/app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java new file mode 100644 index 000000000..19f2849fe --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java @@ -0,0 +1,57 @@ +package com.fongmi.android.tv.cast; + +import org.fourthline.cling.model.meta.Device; + +import java.util.ArrayList; +import java.util.List; + +public class CastDevice { + + private final List> devices; + + private static class Loader { + static volatile CastDevice INSTANCE = new CastDevice(); + } + + public static CastDevice get() { + return Loader.INSTANCE; + } + + public CastDevice() { + this.devices = new ArrayList<>(); + } + + public boolean isEmpty() { + return devices.isEmpty(); + } + + private com.fongmi.android.tv.bean.Device create(Device item) { + com.fongmi.android.tv.bean.Device device = new com.fongmi.android.tv.bean.Device(); + device.setUuid(item.getIdentity().getUdn().getIdentifierString()); + device.setName(item.getDetails().getFriendlyName()); + device.setType(2); + return device; + } + + public List getAll() { + List items = new ArrayList<>(); + for (Device device : devices) items.add(create(device)); + return items; + } + + public List add(Device device) { + devices.remove(device); + devices.add(device); + return getAll(); + } + + public com.fongmi.android.tv.bean.Device remove(Device device) { + devices.remove(device); + return create(device); + } + + public Device find(com.fongmi.android.tv.bean.Device item) { + for (Device device : devices) if (device.getIdentity().getUdn().getIdentifierString().equals(item.getUuid())) return device; + return null; + } +} diff --git a/app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java b/app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java new file mode 100644 index 000000000..626a937ad --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java @@ -0,0 +1,43 @@ +package com.fongmi.android.tv.cast; + +import androidx.annotation.NonNull; + +import com.android.cast.dlna.core.ICast; +import com.fongmi.android.tv.server.Server; +import com.fongmi.android.tv.utils.FileUtil; + +import java.util.UUID; + +public class CastVideo implements ICast { + + private final String name; + private final String url; + + public static CastVideo get(String name, String url) { + return new CastVideo(name, url); + } + + private CastVideo(String name, String url) { + if (url.startsWith("file")) url = Server.get().getAddress() + "/" + url.replace(FileUtil.getRootPath(), ""); + this.name = name; + this.url = url; + } + + @NonNull + @Override + public String getId() { + return UUID.randomUUID().toString(); + } + + @NonNull + @Override + public String getUri() { + return url; + } + + @NonNull + @Override + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/app/src/mobile/java/com/fongmi/android/tv/cast/ScanEvent.java b/app/src/mobile/java/com/fongmi/android/tv/cast/ScanEvent.java new file mode 100644 index 000000000..3a16ead01 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/cast/ScanEvent.java @@ -0,0 +1,20 @@ +package com.fongmi.android.tv.cast; + +import org.greenrobot.eventbus.EventBus; + +public class ScanEvent { + + private final String address; + + public static void post(String address) { + EventBus.getDefault().post(new ScanEvent(address)); + } + + public ScanEvent(String address) { + this.address = address; + } + + public String getAddress() { + return address; + } +} diff --git a/app/src/mobile/java/com/fongmi/android/tv/cast/ScanTask.java b/app/src/mobile/java/com/fongmi/android/tv/cast/ScanTask.java new file mode 100644 index 000000000..b91361328 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/cast/ScanTask.java @@ -0,0 +1,80 @@ +package com.fongmi.android.tv.cast; + +import com.fongmi.android.tv.App; +import com.fongmi.android.tv.bean.Device; +import com.fongmi.android.tv.net.OkHttp; +import com.fongmi.android.tv.server.Server; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import okhttp3.OkHttpClient; + +public class ScanTask { + + private final Listener listener; + private final OkHttpClient client; + private final List devices; + + public static ScanTask create(Listener listener) { + return new ScanTask(listener); + } + + public ScanTask(Listener listener) { + this.listener = listener; + this.client = OkHttp.client(1000); + this.devices = new ArrayList<>(); + } + + public void start(List ips) { + App.execute(() -> run(getUrl(ips))); + } + + public void start(String url) { + App.execute(() -> run(List.of(url))); + } + + private void run(List items) { + try { + getDevice(items); + } catch (Exception e) { + e.printStackTrace(); + } finally { + App.post(() -> listener.onFind(devices)); + } + } + + private void getDevice(List urls) throws Exception { + CountDownLatch cd = new CountDownLatch(urls.size()); + for (String url : urls) new Thread(() -> findDevice(cd, url)).start(); + cd.await(); + } + + private List getUrl(List ips) { + LinkedHashSet urls = new LinkedHashSet<>(ips); + String local = Server.get().getAddress(); + String base = local.substring(0, local.lastIndexOf(".") + 1); + for (int i = 1; i < 256; i++) urls.add(base + i + ":9978"); + return new ArrayList<>(urls); + } + + private void findDevice(CountDownLatch cd, String url) { + try { + if (url.contains(Server.get().getAddress())) return; + String result = OkHttp.newCall(client, url.concat("/device")).execute().body().string(); + Device device = Device.objectFrom(result); + if (device == null) return; + devices.add(device.save()); + } catch (Exception ignored) { + } finally { + cd.countDown(); + } + } + + public interface Listener { + + void onFind(List devices); + } +} diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/ScanActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/ScanActivity.java new file mode 100644 index 000000000..af30916dd --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/ScanActivity.java @@ -0,0 +1,97 @@ +package com.fongmi.android.tv.ui.activity; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.viewbinding.ViewBinding; + +import com.fongmi.android.tv.cast.ScanEvent; +import com.fongmi.android.tv.databinding.ActivityScanBinding; +import com.fongmi.android.tv.ui.base.BaseActivity; +import com.fongmi.android.tv.utils.Utils; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.ResultPoint; +import com.journeyapps.barcodescanner.BarcodeCallback; +import com.journeyapps.barcodescanner.BarcodeResult; +import com.journeyapps.barcodescanner.CaptureManager; +import com.journeyapps.barcodescanner.DefaultDecoderFactory; + +import java.util.List; + +public class ScanActivity extends BaseActivity implements BarcodeCallback { + + private ActivityScanBinding mBinding; + private CaptureManager mCapture; + + public static void start(Activity activity) { + activity.startActivity(new Intent(activity, ScanActivity.class)); + } + + @Override + protected ViewBinding getBinding() { + return mBinding = ActivityScanBinding.inflate(getLayoutInflater()); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Utils.hideSystemUI(this); + } + + @Override + protected void initView(Bundle savedInstanceState) { + mCapture = new CaptureManager(this, mBinding.scanner); + mBinding.scanner.getBarcodeView().setDecoderFactory(new DefaultDecoderFactory(List.of(BarcodeFormat.QR_CODE))); + } + + @Override + public void possibleResultPoints(List resultPoints) { + } + + @Override + public void barcodeResult(BarcodeResult result) { + if (!result.getText().startsWith("http")) return; + ScanEvent.post(result.getText()); + finish(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + mCapture.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Utils.hideSystemUI(this); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus) Utils.hideSystemUI(this); + } + + @Override + protected void onResume() { + super.onResume(); + mCapture.onResume(); + mBinding.scanner.decodeSingle(this); + } + + @Override + protected void onPause() { + super.onPause(); + mCapture.onPause(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mCapture.onDestroy(); + } +} diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/adapter/DeviceAdapter.java b/app/src/mobile/java/com/fongmi/android/tv/ui/adapter/DeviceAdapter.java new file mode 100644 index 000000000..63d00e742 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/adapter/DeviceAdapter.java @@ -0,0 +1,85 @@ +package com.fongmi.android.tv.ui.adapter; + +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.fongmi.android.tv.R; +import com.fongmi.android.tv.bean.Device; +import com.fongmi.android.tv.databinding.AdapterDeviceBinding; + +import java.util.ArrayList; +import java.util.List; + +public class DeviceAdapter extends RecyclerView.Adapter { + + private final OnClickListener mListener; + private final List mItems; + + public DeviceAdapter(OnClickListener listener) { + this.mItems = new ArrayList<>(); + this.mListener = listener; + } + + public interface OnClickListener { + + void onItemClick(Device item); + } + + public void addAll(List items) { + if (items == null) return; + mItems.removeAll(items); + mItems.addAll(items); + notifyDataSetChanged(); + } + + public void remove(Device item) { + if (item == null) return; + mItems.remove(item); + notifyDataSetChanged(); + } + + public void clear() { + mItems.clear(); + Device.delete(); + notifyDataSetChanged(); + } + + public List getIps() { + List ips = new ArrayList<>(); + for (Device item : mItems) if (!item.isDLNA()) ips.add(item.getIp()); + return ips; + } + + @Override + public int getItemCount() { + return mItems.size(); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(AdapterDeviceBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + Device item = mItems.get(position); + holder.binding.name.setText(item.getName()); + holder.binding.host.setText(item.getHost()); + holder.binding.getRoot().setOnClickListener(v -> mListener.onItemClick(item)); + holder.binding.type.setImageResource(item.isMobile() ? R.drawable.ic_cast_mobile : R.drawable.ic_cast_tv); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private final AdapterDeviceBinding binding; + + ViewHolder(@NonNull AdapterDeviceBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } +}