From 2e480465bd2feaa052703a5ced25a4aec7989402 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Sun, 13 Feb 2022 17:43:37 +0100 Subject: [PATCH 01/13] Add initial implementation for Network Scanner --- .../wakeonlan/ui/MainActivity.java | 2 +- .../ui/home/scan/NetworkScanAdapter.java | 86 +++++++++++++++++++ .../ui/home/scan/NetworkScanDiffCallback.java | 22 +++++ .../ui/home/scan/NetworkScanFragment.java | 43 ++++++++++ .../ui/home/scan/model/NetworkScanDevice.java | 23 +++++ .../home/scan/viewholder/EmptyViewHolder.java | 11 +++ .../ui/home/scan/viewholder/ListViewType.java | 5 ++ .../scan/viewholder/ScanResultViewHolder.java | 44 ++++++++++ .../main/res/drawable/ic_search_network.xml | 10 +++ .../main/res/layout/fragment_network_scan.xml | 7 ++ .../main/res/layout/network_list_empty.xml | 34 ++++++++ app/src/main/res/layout/network_list_item.xml | 44 ++++++++++ .../main/res/menu/activity_main_drawer.xml | 4 + app/src/main/res/navigation/nav_graph.xml | 6 ++ app/src/main/res/values/strings.xml | 7 ++ 15 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/EmptyViewHolder.java create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ListViewType.java create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java create mode 100644 app/src/main/res/drawable/ic_search_network.xml create mode 100644 app/src/main/res/layout/fragment_network_scan.xml create mode 100644 app/src/main/res/layout/network_list_empty.xml create mode 100644 app/src/main/res/layout/network_list_item.xml diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/MainActivity.java b/app/src/main/java/de/florianisme/wakeonlan/ui/MainActivity.java index 0498a8a..e77b558 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/MainActivity.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/MainActivity.java @@ -54,7 +54,7 @@ private void initializeNavController() { } private Set getMenuIds() { - return Sets.newHashSet(R.id.deviceListFragment, R.id.backupFragment); + return Sets.newHashSet(R.id.deviceListFragment, R.id.backupFragment, R.id.networkScanFragment); } @Override diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java new file mode 100644 index 0000000..fb21c14 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java @@ -0,0 +1,86 @@ +package de.florianisme.wakeonlan.ui.home.scan; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.AsyncListDiffer; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +import de.florianisme.wakeonlan.R; +import de.florianisme.wakeonlan.ui.home.scan.model.NetworkScanDevice; +import de.florianisme.wakeonlan.ui.home.scan.viewholder.EmptyViewHolder; +import de.florianisme.wakeonlan.ui.home.scan.viewholder.ListViewType; +import de.florianisme.wakeonlan.ui.home.scan.viewholder.ScanResultViewHolder; + +public class NetworkScanAdapter extends RecyclerView.Adapter { + + private final AsyncListDiffer listDiffer = new AsyncListDiffer<>(this, new NetworkScanDiffCallback()); + + public NetworkScanAdapter(List initialDataset) { + updateDataset(initialDataset); + } + + public void updateDataset(List updatedDevices) { + listDiffer.submitList(updatedDevices); + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + RecyclerView.ViewHolder viewHolder; + + if (ListViewType.EMPTY.ordinal() == viewType) { + view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.network_list_empty, parent, false); + viewHolder = new EmptyViewHolder(view); + } else { + view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.network_list_item, parent, false); + viewHolder = new ScanResultViewHolder(view); + } + + return viewHolder; + } + + @Override + public int getItemViewType(int position) { + if (listDiffer.getCurrentList().isEmpty()) { + return ListViewType.EMPTY.ordinal(); + } else { + return ListViewType.SCAN_DEVICE.ordinal(); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + if (getItemViewType(position) == ListViewType.SCAN_DEVICE.ordinal()) { + ScanResultViewHolder scanResultViewHolder = (ScanResultViewHolder) viewHolder; + + NetworkScanDevice networkScanDevice = listDiffer.getCurrentList().get(position); + + scanResultViewHolder.setIpAddress(networkScanDevice.getIpAddress()); + scanResultViewHolder.setMacAddress(networkScanDevice.getMacAddress()); + } + } + + @Override + public long getItemId(int position) { + if (listDiffer.getCurrentList().isEmpty()) { + return RecyclerView.NO_ID; + } + return listDiffer.getCurrentList().get(position).getMacAddress().hashCode(); + } + + @Override + public int getItemCount() { + if (listDiffer.getCurrentList().isEmpty()) { + return 1; // "Empty" item + } + return listDiffer.getCurrentList().size(); + } +} diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java new file mode 100644 index 0000000..dc08529 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java @@ -0,0 +1,22 @@ +package de.florianisme.wakeonlan.ui.home.scan; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DiffUtil; + +import com.google.common.base.Strings; + +import de.florianisme.wakeonlan.ui.home.scan.model.NetworkScanDevice; + +public class NetworkScanDiffCallback extends DiffUtil.ItemCallback { + + @Override + public boolean areItemsTheSame(@NonNull NetworkScanDevice oldItem, @NonNull NetworkScanDevice newItem) { + return Strings.nullToEmpty(oldItem.getMacAddress()).equals(newItem.getMacAddress()); + } + + @Override + public boolean areContentsTheSame(@NonNull NetworkScanDevice oldItem, @NonNull NetworkScanDevice newItem) { + return Strings.nullToEmpty(oldItem.getMacAddress()).equals(newItem.getMacAddress()) && + Strings.nullToEmpty(oldItem.getIpAddress()).equals(newItem.getIpAddress()); + } +} diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java new file mode 100644 index 0000000..8c130c1 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java @@ -0,0 +1,43 @@ +package de.florianisme.wakeonlan.ui.home.scan; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +import de.florianisme.wakeonlan.databinding.FragmentNetworkScanBinding; +import de.florianisme.wakeonlan.ui.home.list.LinearLayoutManagerWrapper; + +public class NetworkScanFragment extends Fragment { + + private FragmentNetworkScanBinding binding; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + binding = FragmentNetworkScanBinding.inflate(inflater, container, false); + + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + setupRecyclerView(); + } + + private void setupRecyclerView() { + RecyclerView recyclerView = binding.networkList; + + recyclerView.setAdapter(new NetworkScanAdapter(new ArrayList<>())); + recyclerView.setLayoutManager(new LinearLayoutManagerWrapper(getContext())); + } +} diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java new file mode 100644 index 0000000..cbad198 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java @@ -0,0 +1,23 @@ +package de.florianisme.wakeonlan.ui.home.scan.model; + +public class NetworkScanDevice { + + private String ipAddress; + private String macAddress; + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getMacAddress() { + return macAddress; + } + + public void setMacAddress(String macAddress) { + this.macAddress = macAddress; + } +} diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/EmptyViewHolder.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/EmptyViewHolder.java new file mode 100644 index 0000000..ebfe1c7 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/EmptyViewHolder.java @@ -0,0 +1,11 @@ +package de.florianisme.wakeonlan.ui.home.scan.viewholder; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +public class EmptyViewHolder extends RecyclerView.ViewHolder { + public EmptyViewHolder(View view) { + super(view); + } +} diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ListViewType.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ListViewType.java new file mode 100644 index 0000000..acb2798 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ListViewType.java @@ -0,0 +1,5 @@ +package de.florianisme.wakeonlan.ui.home.scan.viewholder; + +public enum ListViewType { + EMPTY, SCAN_DEVICE +} diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java new file mode 100644 index 0000000..d637b88 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java @@ -0,0 +1,44 @@ +package de.florianisme.wakeonlan.ui.home.scan.viewholder; + +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import de.florianisme.wakeonlan.R; +import de.florianisme.wakeonlan.ui.home.scan.model.NetworkScanDevice; + +public class ScanResultViewHolder extends RecyclerView.ViewHolder { + + private final TextView deviceIp; + private final TextView deviceMac; + + private final Button addDevice; + + public ScanResultViewHolder(@NonNull View itemView) { + super(itemView); + + deviceIp = itemView.findViewById(R.id.scan_device_ip); + deviceMac = itemView.findViewById(R.id.scan_device_mac); + addDevice = itemView.findViewById(R.id.scan_device_add); + } + + public void setIpAddress(String ipAddress) { + deviceIp.setText(ipAddress); + } + + public void setMacAddress(String macAddress) { + deviceMac.setText(macAddress); + } + + public void setOnAddClickListener(NetworkScanDevice scanDevice) { + addDevice.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // TODO start AddDevice Activity + } + }); + } +} diff --git a/app/src/main/res/drawable/ic_search_network.xml b/app/src/main/res/drawable/ic_search_network.xml new file mode 100644 index 0000000..bffed68 --- /dev/null +++ b/app/src/main/res/drawable/ic_search_network.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_network_scan.xml b/app/src/main/res/layout/fragment_network_scan.xml new file mode 100644 index 0000000..e8f6121 --- /dev/null +++ b/app/src/main/res/layout/fragment_network_scan.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/network_list_empty.xml b/app/src/main/res/layout/network_list_empty.xml new file mode 100644 index 0000000..93352da --- /dev/null +++ b/app/src/main/res/layout/network_list_empty.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/network_list_item.xml b/app/src/main/res/layout/network_list_item.xml new file mode 100644 index 0000000..739a3f8 --- /dev/null +++ b/app/src/main/res/layout/network_list_item.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index b0436f6..c0d8053 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -5,6 +5,10 @@ android:id="@+id/deviceListFragment" android:icon="@drawable/ic_device_list" android:title="@string/drawer_menu_item_device_list" /> + + + Add Device Edit Device Devices + Network Scan Export/Import Data @@ -64,7 +65,13 @@ Successfully exported %1$d devices Error while exporting devices + + Add Device + No devices found + Are you connected to a WiFI Network? + @string/title_fragment_device_list + @string/title_fragment_network_scan @string/title_fragment_backup \ No newline at end of file From b9afb94997fb2718b2feb132afa36c0460c0fc55 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Sun, 13 Feb 2022 21:19:52 +0100 Subject: [PATCH 02/13] Add basic implementation for searching network devices --- app/src/main/AndroidManifest.xml | 1 + .../ui/home/scan/NetworkScanAdapter.java | 15 +++-- .../ui/home/scan/NetworkScanDiffCallback.java | 5 +- .../ui/home/scan/NetworkScanFragment.java | 32 +++++++++- .../ui/home/scan/NetworkSniffTask.java | 64 +++++++++++++++++++ .../wakeonlan/ui/home/scan/ScanCallback.java | 9 +++ .../ui/home/scan/model/NetworkScanDevice.java | 8 --- .../scan/viewholder/ScanResultViewHolder.java | 6 -- app/src/main/res/layout/network_list_item.xml | 17 ++--- app/src/main/res/values/strings.xml | 2 + 10 files changed, 119 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkSniffTask.java create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/ScanCallback.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a85f0de..dedcafc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java index fb21c14..1ae1b70 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java @@ -8,7 +8,7 @@ import androidx.recyclerview.widget.AsyncListDiffer; import androidx.recyclerview.widget.RecyclerView; -import java.util.List; +import java.util.ArrayList; import de.florianisme.wakeonlan.R; import de.florianisme.wakeonlan.ui.home.scan.model.NetworkScanDevice; @@ -20,12 +20,14 @@ public class NetworkScanAdapter extends RecyclerView.Adapter listDiffer = new AsyncListDiffer<>(this, new NetworkScanDiffCallback()); - public NetworkScanAdapter(List initialDataset) { - updateDataset(initialDataset); + public void clearDataset() { + listDiffer.submitList(new ArrayList<>()); } - public void updateDataset(List updatedDevices) { - listDiffer.submitList(updatedDevices); + public void addItem(NetworkScanDevice networkScanDevice) { + ArrayList updatedList = new ArrayList<>(listDiffer.getCurrentList()); + updatedList.add(networkScanDevice); + listDiffer.submitList(updatedList); } @NonNull @@ -64,7 +66,6 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int po NetworkScanDevice networkScanDevice = listDiffer.getCurrentList().get(position); scanResultViewHolder.setIpAddress(networkScanDevice.getIpAddress()); - scanResultViewHolder.setMacAddress(networkScanDevice.getMacAddress()); } } @@ -73,7 +74,7 @@ public long getItemId(int position) { if (listDiffer.getCurrentList().isEmpty()) { return RecyclerView.NO_ID; } - return listDiffer.getCurrentList().get(position).getMacAddress().hashCode(); + return listDiffer.getCurrentList().get(position).getIpAddress().hashCode(); } @Override diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java index dc08529..5d8f56d 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java @@ -11,12 +11,11 @@ public class NetworkScanDiffCallback extends DiffUtil.ItemCallback Toast.makeText(getContext(), errorStringReference, Toast.LENGTH_SHORT).show()); + } + + @Override + public void onDeviceFound(String ip) { + NetworkScanDevice networkScanDevice = new NetworkScanDevice(); + networkScanDevice.setIpAddress(ip); + + networkScanAdapter.addItem(networkScanDevice); + } + }; } private void setupRecyclerView() { RecyclerView recyclerView = binding.networkList; - recyclerView.setAdapter(new NetworkScanAdapter(new ArrayList<>())); + networkScanAdapter = new NetworkScanAdapter(); + recyclerView.setAdapter(networkScanAdapter); recyclerView.setLayoutManager(new LinearLayoutManagerWrapper(getContext())); } } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkSniffTask.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkSniffTask.java new file mode 100644 index 0000000..c3d03cb --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkSniffTask.java @@ -0,0 +1,64 @@ +package de.florianisme.wakeonlan.ui.home.scan; + +import android.content.Context; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.AsyncTask; +import android.text.format.Formatter; +import android.util.Log; + +import java.lang.ref.WeakReference; +import java.net.InetAddress; + +import de.florianisme.wakeonlan.R; + +public class NetworkSniffTask extends AsyncTask { + + private final WeakReference contextWeakReference; + private final ScanCallback scanCallback; + + public NetworkSniffTask(Context context, ScanCallback scanCallback) { + super(); + contextWeakReference = new WeakReference<>(context); + this.scanCallback = scanCallback; + } + + @Override + protected Void doInBackground(Void... voids) { + try { + Context context = contextWeakReference.get(); + + if (context != null) { + WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + + WifiInfo connectionInfo = wm.getConnectionInfo(); + int ipAddress = connectionInfo.getIpAddress(); + String ipString = Formatter.formatIpAddress(ipAddress);//InetAddress.getByName(String.valueOf(ipAddress)).getHostAddress(); + + if (ipString == null) { + scanCallback.onError(R.string.network_scan_error_ip); + return null; + } + + String prefix = ipString.substring(0, ipString.lastIndexOf(".") + 1); + + for (int i = 0; i < 255; i++) { + String testIp = prefix + i; + + InetAddress address = InetAddress.getByName(testIp); + boolean reachable = address.isReachable(20); + String hostName = address.getCanonicalHostName(); + + if (reachable) { + scanCallback.onDeviceFound(address.getHostAddress()); + } + } + } + } catch (Exception e) { + scanCallback.onError(R.string.network_scan_error_general); + Log.e(getClass().getSimpleName(), "Error while scanning network", e); + } + + return null; + } +} \ No newline at end of file diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/ScanCallback.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/ScanCallback.java new file mode 100644 index 0000000..586f5e2 --- /dev/null +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/ScanCallback.java @@ -0,0 +1,9 @@ +package de.florianisme.wakeonlan.ui.home.scan; + +public interface ScanCallback { + + void onError(int errorStringReference); + + void onDeviceFound(String ip); + +} diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java index cbad198..977d49c 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java @@ -3,7 +3,6 @@ public class NetworkScanDevice { private String ipAddress; - private String macAddress; public String getIpAddress() { return ipAddress; @@ -13,11 +12,4 @@ public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } - public String getMacAddress() { - return macAddress; - } - - public void setMacAddress(String macAddress) { - this.macAddress = macAddress; - } } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java index d637b88..07b54b8 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java @@ -13,7 +13,6 @@ public class ScanResultViewHolder extends RecyclerView.ViewHolder { private final TextView deviceIp; - private final TextView deviceMac; private final Button addDevice; @@ -21,7 +20,6 @@ public ScanResultViewHolder(@NonNull View itemView) { super(itemView); deviceIp = itemView.findViewById(R.id.scan_device_ip); - deviceMac = itemView.findViewById(R.id.scan_device_mac); addDevice = itemView.findViewById(R.id.scan_device_add); } @@ -29,10 +27,6 @@ public void setIpAddress(String ipAddress) { deviceIp.setText(ipAddress); } - public void setMacAddress(String macAddress) { - deviceMac.setText(macAddress); - } - public void setOnAddClickListener(NetworkScanDevice scanDevice) { addDevice.setOnClickListener(new View.OnClickListener() { @Override diff --git a/app/src/main/res/layout/network_list_item.xml b/app/src/main/res/layout/network_list_item.xml index 739a3f8..5462fd6 100644 --- a/app/src/main/res/layout/network_list_item.xml +++ b/app/src/main/res/layout/network_list_item.xml @@ -2,14 +2,16 @@ + android:paddingStart="16dp" + android:paddingTop="16dp" + android:paddingBottom="8dp"> - - Add Device No devices found Are you connected to a WiFI Network? + Can not obtain IP Address + Error while scanning network @string/title_fragment_device_list From fc3c106d05c54e23e8f5fde6478bca48991815d7 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Sun, 13 Feb 2022 21:36:30 +0100 Subject: [PATCH 03/13] Launch AddNetworkScanDeviceActivity when clicking an item --- app/src/main/AndroidManifest.xml | 8 +++++-- .../AddDeviceActivity.java | 2 +- .../details/AddNetworkScanDeviceActivity.java | 23 +++++++++++++++++++ .../EditDeviceActivity.java | 2 +- .../ModifyDeviceActivity.java | 10 ++++---- .../autocomplete/MacAddressAutocomplete.java | 2 +- .../watcher/validator/IpAddressValidator.java | 2 +- .../watcher/validator/MacValidator.java | 2 +- .../watcher/validator/NameValidator.java | 2 +- .../watcher/validator/ValidationResult.java | 5 ++++ .../watcher/validator/Validator.java | 2 +- .../list/viewholder/DeviceItemViewHolder.java | 2 +- .../watcher/validator/ValidationResult.java | 5 ---- .../ui/home/scan/NetworkScanAdapter.java | 1 + .../ui/home/scan/NetworkScanFragment.java | 11 +++++++-- ...orkSniffTask.java => NetworkScanTask.java} | 6 ++--- .../scan/{ => callbacks}/ScanCallback.java | 2 +- .../scan/viewholder/ScanResultViewHolder.java | 14 +++++++++-- .../res/layout/activity_modify_device.xml | 2 +- app/src/main/res/navigation/nav_graph.xml | 2 +- 20 files changed, 75 insertions(+), 30 deletions(-) rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/AddDeviceActivity.java (96%) create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/details/AddNetworkScanDeviceActivity.java rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/EditDeviceActivity.java (98%) rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/ModifyDeviceActivity.java (94%) rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/watcher/autocomplete/MacAddressAutocomplete.java (96%) rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/watcher/validator/IpAddressValidator.java (94%) rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/watcher/validator/MacValidator.java (91%) rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/watcher/validator/NameValidator.java (87%) create mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/details/watcher/validator/ValidationResult.java rename app/src/main/java/de/florianisme/wakeonlan/ui/home/{modify => details}/watcher/validator/Validator.java (94%) delete mode 100644 app/src/main/java/de/florianisme/wakeonlan/ui/home/modify/watcher/validator/ValidationResult.java rename app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/{NetworkSniffTask.java => NetworkScanTask.java} (90%) rename app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/{ => callbacks}/ScanCallback.java (67%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index dedcafc..a648d3b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,13 +23,17 @@ + { +public class NetworkScanTask extends AsyncTask { private final WeakReference contextWeakReference; private final ScanCallback scanCallback; - public NetworkSniffTask(Context context, ScanCallback scanCallback) { + public NetworkScanTask(Context context, ScanCallback scanCallback) { super(); contextWeakReference = new WeakReference<>(context); this.scanCallback = scanCallback; @@ -47,7 +48,6 @@ protected Void doInBackground(Void... voids) { InetAddress address = InetAddress.getByName(testIp); boolean reachable = address.isReachable(20); - String hostName = address.getCanonicalHostName(); if (reachable) { scanCallback.onDeviceFound(address.getHostAddress()); diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/ScanCallback.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java similarity index 67% rename from app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/ScanCallback.java rename to app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java index 586f5e2..91d96dc 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/ScanCallback.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java @@ -1,4 +1,4 @@ -package de.florianisme.wakeonlan.ui.home.scan; +package de.florianisme.wakeonlan.ui.home.scan.callbacks; public interface ScanCallback { diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java index 07b54b8..b5e679d 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java @@ -1,5 +1,8 @@ package de.florianisme.wakeonlan.ui.home.scan.viewholder; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -8,6 +11,7 @@ import androidx.recyclerview.widget.RecyclerView; import de.florianisme.wakeonlan.R; +import de.florianisme.wakeonlan.ui.home.details.AddNetworkScanDeviceActivity; import de.florianisme.wakeonlan.ui.home.scan.model.NetworkScanDevice; public class ScanResultViewHolder extends RecyclerView.ViewHolder { @@ -30,8 +34,14 @@ public void setIpAddress(String ipAddress) { public void setOnAddClickListener(NetworkScanDevice scanDevice) { addDevice.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { - // TODO start AddDevice Activity + public void onClick(View view) { + Context context = view.getContext(); + + Intent intent = new Intent(context, AddNetworkScanDeviceActivity.class); + Bundle bundle = new Bundle(); + bundle.putString(AddNetworkScanDeviceActivity.MACHINE_IP_KEY, scanDevice.getIpAddress()); + intent.putExtras(bundle); + context.startActivity(intent); } }); } diff --git a/app/src/main/res/layout/activity_modify_device.xml b/app/src/main/res/layout/activity_modify_device.xml index 7a9d9ae..480bc6f 100644 --- a/app/src/main/res/layout/activity_modify_device.xml +++ b/app/src/main/res/layout/activity_modify_device.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.home.modify.ModifyDeviceActivity"> + tools:context=".ui.home.details.ModifyDeviceActivity"> From 997cf2c0e8e4ce7b6064fbf87c11b7fa247ba400 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Sun, 13 Feb 2022 21:45:21 +0100 Subject: [PATCH 04/13] Add swipe to refresh layout --- app/build.gradle | 1 + .../ui/home/scan/NetworkScanFragment.java | 18 +++++++++++++++++- .../ui/home/scan/NetworkScanTask.java | 2 ++ .../ui/home/scan/callbacks/ScanCallback.java | 2 ++ .../main/res/layout/fragment_network_scan.xml | 14 ++++++++++---- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7763931..9608cf8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,6 +19,7 @@ dependencies { implementation 'androidx.navigation:navigation-fragment:2.4.1' implementation 'androidx.navigation:navigation-ui:2.4.1' implementation 'com.google.guava:guava:31.0.1-jre' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' def room_version = "2.4.1" implementation "androidx.room:room-runtime:$room_version" diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java index b8993d0..d8be48c 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java @@ -20,6 +20,7 @@ public class NetworkScanFragment extends Fragment { private FragmentNetworkScanBinding binding; private NetworkScanAdapter networkScanAdapter; + private NetworkScanTask networkScanTask; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -34,15 +35,25 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat super.onViewCreated(view, savedInstanceState); setupRecyclerView(); + setupSwipeToRefresh(); + + networkScanTask = new NetworkScanTask(getContext(), getScanCallback()); startNetworkScan(); } private void startNetworkScan() { + binding.swipeRefresh.setRefreshing(true); networkScanAdapter.clearDataset(); - NetworkScanTask networkScanTask = new NetworkScanTask(getContext(), getScanCallback()); + + networkScanTask.cancel(true); + networkScanTask = new NetworkScanTask(getContext(), getScanCallback()); networkScanTask.execute(); } + private void setupSwipeToRefresh() { + binding.swipeRefresh.setOnRefreshListener(this::startNetworkScan); + } + private ScanCallback getScanCallback() { return new ScanCallback() { @Override @@ -57,6 +68,11 @@ public void onDeviceFound(String ip) { networkScanAdapter.addItem(networkScanDevice); } + + @Override + public void onTaskEnd() { + binding.swipeRefresh.setRefreshing(false); + } }; } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java index 6e6f997..5b501b4 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java @@ -56,9 +56,11 @@ protected Void doInBackground(Void... voids) { } } catch (Exception e) { scanCallback.onError(R.string.network_scan_error_general); + scanCallback.onTaskEnd(); Log.e(getClass().getSimpleName(), "Error while scanning network", e); } + scanCallback.onTaskEnd(); return null; } } \ No newline at end of file diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java index 91d96dc..0670fa4 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java @@ -6,4 +6,6 @@ public interface ScanCallback { void onDeviceFound(String ip); + void onTaskEnd(); + } diff --git a/app/src/main/res/layout/fragment_network_scan.xml b/app/src/main/res/layout/fragment_network_scan.xml index e8f6121..c2bf95e 100644 --- a/app/src/main/res/layout/fragment_network_scan.xml +++ b/app/src/main/res/layout/fragment_network_scan.xml @@ -1,7 +1,13 @@ - \ No newline at end of file + android:layout_height="match_parent"> + + + \ No newline at end of file From a2f534646c77c591c9aa24cf1bf954724ec4d6a0 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Mon, 14 Feb 2022 20:54:55 +0100 Subject: [PATCH 05/13] Fix order of clear statements --- .../florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java index d8be48c..85f4f95 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java @@ -43,9 +43,9 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat private void startNetworkScan() { binding.swipeRefresh.setRefreshing(true); - networkScanAdapter.clearDataset(); networkScanTask.cancel(true); + networkScanAdapter.clearDataset(); networkScanTask = new NetworkScanTask(getContext(), getScanCallback()); networkScanTask.execute(); } From befdee56538ea4a085608956e39b30b6d735c779 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Mon, 14 Feb 2022 21:43:21 +0100 Subject: [PATCH 06/13] Fix list flashing and load hostname aswell --- .../details/AddNetworkScanDeviceActivity.java | 4 +++ .../ui/home/details/ModifyDeviceActivity.java | 7 +++-- .../ui/home/scan/NetworkScanAdapter.java | 28 +++++++++++++++---- .../ui/home/scan/NetworkScanDiffCallback.java | 3 +- .../ui/home/scan/NetworkScanFragment.java | 13 +++++++-- .../ui/home/scan/NetworkScanTask.java | 10 +++++-- .../ui/home/scan/callbacks/ScanCallback.java | 2 +- .../ui/home/scan/model/NetworkScanDevice.java | 28 +++++++++++++++++++ .../scan/viewholder/ScanResultViewHolder.java | 14 ++++++++++ app/src/main/res/layout/network_list_item.xml | 12 +++++++- 10 files changed, 106 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/AddNetworkScanDeviceActivity.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/AddNetworkScanDeviceActivity.java index 597a9ab..7742736 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/AddNetworkScanDeviceActivity.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/AddNetworkScanDeviceActivity.java @@ -5,6 +5,7 @@ public class AddNetworkScanDeviceActivity extends AddDeviceActivity { public static final String MACHINE_IP_KEY = "deviceIp"; + public static final String MACHINE_NAME_KEY = "deviceName"; @Override protected void onCreate(Bundle savedInstanceState) { @@ -15,9 +16,12 @@ protected void onCreate(Bundle savedInstanceState) { private void prepopulateInputs() { Bundle extras = getIntent().getExtras(); if (extras != null) { + String machineName = extras.getString(MACHINE_NAME_KEY, null); String machineIp = extras.getString(MACHINE_IP_KEY, null); + deviceNameInput.setText(machineName); deviceStatusIpInput.setText(machineIp); + broadcastAutofill.callOnClick(); } } } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/ModifyDeviceActivity.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/ModifyDeviceActivity.java index 9027f91..6b0e438 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/ModifyDeviceActivity.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/details/ModifyDeviceActivity.java @@ -4,6 +4,7 @@ import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; +import android.widget.ImageButton; import android.widget.Toast; import androidx.annotation.NonNull; @@ -36,6 +37,7 @@ public abstract class ModifyDeviceActivity extends AppCompatActivity { protected TextInputEditText deviceNameInput; protected TextInputEditText deviceStatusIpInput; protected TextInputEditText deviceBroadcastInput; + protected ImageButton broadcastAutofill; protected MaterialAutoCompleteTextView devicePorts; @Override @@ -50,6 +52,7 @@ protected void onCreate(Bundle savedInstanceState) { deviceNameInput = binding.device.deviceName; deviceStatusIpInput = binding.device.deviceStatusIp; deviceBroadcastInput = binding.device.deviceBroadcast; + broadcastAutofill = binding.device.broadcastAutofill; setSupportActionBar(binding.toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -62,12 +65,12 @@ protected void onCreate(Bundle savedInstanceState) { } private void addAutofillClickHandler() { - binding.device.broadcastAutofill.setOnClickListener(new View.OnClickListener() { + broadcastAutofill.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { Optional broadcastAddress = BroadcastHelper.getBroadcastAddress(); - broadcastAddress.ifPresent(inetAddress -> binding.device.deviceBroadcast.setText(inetAddress.getHostAddress())); + broadcastAddress.ifPresent(inetAddress -> deviceBroadcastInput.setText(inetAddress.getHostAddress())); } catch (IOException e) { Log.e(this.getClass().getName(), "Can not retrieve Broadcast Address", e); } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java index 1e3acce..b639414 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanAdapter.java @@ -8,7 +8,12 @@ import androidx.recyclerview.widget.AsyncListDiffer; import androidx.recyclerview.widget.RecyclerView; +import com.google.common.base.Strings; + import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; import de.florianisme.wakeonlan.R; import de.florianisme.wakeonlan.ui.home.scan.model.NetworkScanDevice; @@ -24,10 +29,22 @@ public void clearDataset() { listDiffer.submitList(new ArrayList<>()); } - public void addItem(NetworkScanDevice networkScanDevice) { - ArrayList updatedList = new ArrayList<>(listDiffer.getCurrentList()); - updatedList.add(networkScanDevice); - listDiffer.submitList(updatedList); + public void updateList(List updatedList) { + List sortedList = updatedList.stream() + .distinct() + .sorted(getScanDeviceComparator()) + .collect(Collectors.toList()); + + listDiffer.submitList(sortedList); + } + + private Comparator getScanDeviceComparator() { + Comparator networkScanDeviceComparator = + Comparator.comparing(device -> + Strings.nullToEmpty(device.getIpAddress()) + .substring(0, device.getIpAddress() + .lastIndexOf(".") + 1)); + return networkScanDeviceComparator.reversed(); } @NonNull @@ -65,6 +82,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int po NetworkScanDevice networkScanDevice = listDiffer.getCurrentList().get(position); + scanResultViewHolder.setNameIfPresent(networkScanDevice.getName()); scanResultViewHolder.setIpAddress(networkScanDevice.getIpAddress()); scanResultViewHolder.setOnAddClickListener(networkScanDevice); } @@ -75,7 +93,7 @@ public long getItemId(int position) { if (listDiffer.getCurrentList().isEmpty()) { return RecyclerView.NO_ID; } - return listDiffer.getCurrentList().get(position).getIpAddress().hashCode(); + return listDiffer.getCurrentList().get(position).hashCode(); } @Override diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java index 5d8f56d..d27a866 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanDiffCallback.java @@ -16,6 +16,7 @@ public boolean areItemsTheSame(@NonNull NetworkScanDevice oldItem, @NonNull Netw @Override public boolean areContentsTheSame(@NonNull NetworkScanDevice oldItem, @NonNull NetworkScanDevice newItem) { - return Strings.nullToEmpty(oldItem.getIpAddress()).equals(newItem.getIpAddress()); + return Strings.nullToEmpty(oldItem.getIpAddress()).equals(newItem.getIpAddress()) + && (oldItem.getName().isPresent() && newItem.getName().isPresent() && oldItem.getName().get().equals(newItem.getName().get())); } } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java index 85f4f95..23cc08a 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java @@ -11,6 +11,9 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; +import java.util.ArrayList; +import java.util.List; + import de.florianisme.wakeonlan.databinding.FragmentNetworkScanBinding; import de.florianisme.wakeonlan.ui.home.list.LinearLayoutManagerWrapper; import de.florianisme.wakeonlan.ui.home.scan.callbacks.ScanCallback; @@ -55,6 +58,8 @@ private void setupSwipeToRefresh() { } private ScanCallback getScanCallback() { + List resultList = new ArrayList<>(15); + return new ScanCallback() { @Override public void onError(int errorStringReference) { @@ -62,11 +67,15 @@ public void onError(int errorStringReference) { } @Override - public void onDeviceFound(String ip) { + public void onDeviceFound(String ip, String hostName) { NetworkScanDevice networkScanDevice = new NetworkScanDevice(); networkScanDevice.setIpAddress(ip); + if (!ip.equals(hostName)) { + networkScanDevice.setName(hostName); + } - networkScanAdapter.addItem(networkScanDevice); + resultList.add(networkScanDevice); + networkScanAdapter.updateList(resultList); } @Override diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java index 5b501b4..9b04efa 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java @@ -34,7 +34,7 @@ protected Void doInBackground(Void... voids) { WifiInfo connectionInfo = wm.getConnectionInfo(); int ipAddress = connectionInfo.getIpAddress(); - String ipString = Formatter.formatIpAddress(ipAddress);//InetAddress.getByName(String.valueOf(ipAddress)).getHostAddress(); + String ipString = Formatter.formatIpAddress(ipAddress); if (ipString == null) { scanCallback.onError(R.string.network_scan_error_ip); @@ -47,10 +47,14 @@ protected Void doInBackground(Void... voids) { String testIp = prefix + i; InetAddress address = InetAddress.getByName(testIp); - boolean reachable = address.isReachable(20); + boolean reachable = address.isReachable(50); if (reachable) { - scanCallback.onDeviceFound(address.getHostAddress()); + scanCallback.onDeviceFound(address.getHostAddress(), address.getHostName()); + } + + if (isCancelled()) { + return null; } } } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java index 0670fa4..b507fe5 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/callbacks/ScanCallback.java @@ -4,7 +4,7 @@ public interface ScanCallback { void onError(int errorStringReference); - void onDeviceFound(String ip); + void onDeviceFound(String ip, String hostName); void onTaskEnd(); diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java index 977d49c..24834d5 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/model/NetworkScanDevice.java @@ -1,15 +1,43 @@ package de.florianisme.wakeonlan.ui.home.scan.model; +import java.util.Optional; + public class NetworkScanDevice { + private Optional name = Optional.empty(); private String ipAddress; public String getIpAddress() { return ipAddress; } + public void setName(String name) { + this.name = Optional.of(name); + } + + public Optional getName() { + return name; + } + public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + NetworkScanDevice that = (NetworkScanDevice) o; + + if (name.isPresent() ? !name.equals(that.name) : that.name.isPresent()) return false; + return ipAddress.equals(that.ipAddress); + } + + @Override + public int hashCode() { + int result = name.isPresent() ? name.hashCode() : 0; + result = 31 * result + ipAddress.hashCode(); + return result; + } } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java index b5e679d..69d5450 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java @@ -10,12 +10,15 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; +import java.util.Optional; + import de.florianisme.wakeonlan.R; import de.florianisme.wakeonlan.ui.home.details.AddNetworkScanDeviceActivity; import de.florianisme.wakeonlan.ui.home.scan.model.NetworkScanDevice; public class ScanResultViewHolder extends RecyclerView.ViewHolder { + private final TextView deviceName; private final TextView deviceIp; private final Button addDevice; @@ -23,6 +26,7 @@ public class ScanResultViewHolder extends RecyclerView.ViewHolder { public ScanResultViewHolder(@NonNull View itemView) { super(itemView); + deviceName = itemView.findViewById(R.id.scan_device_name); deviceIp = itemView.findViewById(R.id.scan_device_ip); addDevice = itemView.findViewById(R.id.scan_device_add); } @@ -31,6 +35,15 @@ public void setIpAddress(String ipAddress) { deviceIp.setText(ipAddress); } + public void setNameIfPresent(Optional name) { + if (name.isPresent()) { + deviceName.setVisibility(View.VISIBLE); + deviceName.setText(name.get()); + } else { + deviceName.setVisibility(View.GONE); + } + } + public void setOnAddClickListener(NetworkScanDevice scanDevice) { addDevice.setOnClickListener(new View.OnClickListener() { @Override @@ -39,6 +52,7 @@ public void onClick(View view) { Intent intent = new Intent(context, AddNetworkScanDeviceActivity.class); Bundle bundle = new Bundle(); + bundle.putString(AddNetworkScanDeviceActivity.MACHINE_NAME_KEY, scanDevice.getName().orElse(null)); bundle.putString(AddNetworkScanDeviceActivity.MACHINE_IP_KEY, scanDevice.getIpAddress()); intent.putExtras(bundle); context.startActivity(intent); diff --git a/app/src/main/res/layout/network_list_item.xml b/app/src/main/res/layout/network_list_item.xml index 5462fd6..5edac36 100644 --- a/app/src/main/res/layout/network_list_item.xml +++ b/app/src/main/res/layout/network_list_item.xml @@ -14,11 +14,21 @@ android:paddingBottom="8dp"> + + From f1ccc8b91a46333bf60e2dd09b628a321c2f851c Mon Sep 17 00:00:00 2001 From: Florianisme Date: Mon, 14 Feb 2022 21:52:10 +0100 Subject: [PATCH 07/13] Fix styling when hostname is empty --- .../florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java | 2 +- .../wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java index 23cc08a..b7ebac2 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java @@ -70,7 +70,7 @@ public void onError(int errorStringReference) { public void onDeviceFound(String ip, String hostName) { NetworkScanDevice networkScanDevice = new NetworkScanDevice(); networkScanDevice.setIpAddress(ip); - if (!ip.equals(hostName)) { + if (hostName != null && !ip.equals(hostName) && !hostName.isEmpty()) { networkScanDevice.setName(hostName); } diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java index 69d5450..fad29fe 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/viewholder/ScanResultViewHolder.java @@ -39,8 +39,10 @@ public void setNameIfPresent(Optional name) { if (name.isPresent()) { deviceName.setVisibility(View.VISIBLE); deviceName.setText(name.get()); + deviceIp.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body2); } else { deviceName.setVisibility(View.GONE); + deviceIp.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6); } } From 2d26433c63939707e1fae81d1f984cd6da742737 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Mon, 14 Feb 2022 21:54:30 +0100 Subject: [PATCH 08/13] Add german translations --- app/src/main/res/values-de/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ad90f0f..e722797 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -44,4 +44,10 @@ Fehler beim Importieren der Geräte %1$d Geräte erfolgreich exportiert Fehler beim Exportieren der Geräte + Netzwerk Scan + Gerät hinzufügen + Keine Geräte gefunden + Sind Sie mit einem WLAN Netzwerk verbunden? + IP Addresse kann nicht abgefragt werden + Fehler beim Scannen des Netzwerks \ No newline at end of file From f936be48a551c76a3d5b787c3bcc3ae216ab427a Mon Sep 17 00:00:00 2001 From: Florianisme Date: Mon, 14 Feb 2022 21:55:03 +0100 Subject: [PATCH 09/13] Do not reload list onResume --- .../wakeonlan/ui/home/scan/NetworkScanFragment.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java index b7ebac2..cc74c7a 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java @@ -92,10 +92,4 @@ private void setupRecyclerView() { recyclerView.setAdapter(networkScanAdapter); recyclerView.setLayoutManager(new LinearLayoutManagerWrapper(getContext())); } - - @Override - public void onResume() { - super.onResume(); - startNetworkScan(); - } } From 8119bf2e596b8d082a2fb262fad33dabfd8ecaa3 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Wed, 16 Feb 2022 21:36:50 +0100 Subject: [PATCH 10/13] Switch to simple Runnable/Thread implementation --- .../ui/home/scan/NetworkScanFragment.java | 20 +++++++++++++++---- .../ui/home/scan/NetworkScanTask.java | 18 +++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java index cc74c7a..6e3aba1 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanFragment.java @@ -40,23 +40,35 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat setupRecyclerView(); setupSwipeToRefresh(); - networkScanTask = new NetworkScanTask(getContext(), getScanCallback()); startNetworkScan(); } private void startNetworkScan() { binding.swipeRefresh.setRefreshing(true); - - networkScanTask.cancel(true); networkScanAdapter.clearDataset(); + + if (networkScanTask != null) { + networkScanTask.cancel(); + } + networkScanTask = new NetworkScanTask(getContext(), getScanCallback()); - networkScanTask.execute(); + Thread networkScanThread = new Thread(networkScanTask); + + networkScanThread.start(); } private void setupSwipeToRefresh() { binding.swipeRefresh.setOnRefreshListener(this::startNetworkScan); } + @Override + public void onPause() { + super.onPause(); + if (networkScanTask != null) { + networkScanTask.cancel(); + } + } + private ScanCallback getScanCallback() { List resultList = new ArrayList<>(15); diff --git a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java index 9b04efa..6825e2e 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java +++ b/app/src/main/java/de/florianisme/wakeonlan/ui/home/scan/NetworkScanTask.java @@ -3,7 +3,6 @@ import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.os.AsyncTask; import android.text.format.Formatter; import android.util.Log; @@ -13,19 +12,19 @@ import de.florianisme.wakeonlan.R; import de.florianisme.wakeonlan.ui.home.scan.callbacks.ScanCallback; -public class NetworkScanTask extends AsyncTask { +public class NetworkScanTask implements Runnable { private final WeakReference contextWeakReference; private final ScanCallback scanCallback; + private boolean canceled = false; public NetworkScanTask(Context context, ScanCallback scanCallback) { - super(); contextWeakReference = new WeakReference<>(context); this.scanCallback = scanCallback; } @Override - protected Void doInBackground(Void... voids) { + public void run() { try { Context context = contextWeakReference.get(); @@ -38,7 +37,7 @@ protected Void doInBackground(Void... voids) { if (ipString == null) { scanCallback.onError(R.string.network_scan_error_ip); - return null; + return; } String prefix = ipString.substring(0, ipString.lastIndexOf(".") + 1); @@ -53,8 +52,8 @@ protected Void doInBackground(Void... voids) { scanCallback.onDeviceFound(address.getHostAddress(), address.getHostName()); } - if (isCancelled()) { - return null; + if (this.canceled) { + return; } } } @@ -65,6 +64,9 @@ protected Void doInBackground(Void... voids) { } scanCallback.onTaskEnd(); - return null; + } + + public void cancel() { + this.canceled = true; } } \ No newline at end of file From 5a9e4684adf7cf3c9dc86207c8c9b5eb4b68b835 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Wed, 16 Feb 2022 21:38:10 +0100 Subject: [PATCH 11/13] Increase version code/name --- app/build.gradle | 2 +- shared-build.gradle | 2 +- wear/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9608cf8..696ecdd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,7 @@ apply from: "$rootProject.projectDir/shared-build.gradle" android { defaultConfig { - versionCode 28 + versionCode 30 wearAppUnbundled true } buildFeatures { diff --git a/shared-build.gradle b/shared-build.gradle index e7ca733..8427096 100644 --- a/shared-build.gradle +++ b/shared-build.gradle @@ -19,7 +19,7 @@ android { minSdk 24 targetSdk 31 versionCode 4 - versionName "1.3.1" + versionName "1.4.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/wear/build.gradle b/wear/build.gradle index 2a7ee7d..bab54b5 100644 --- a/wear/build.gradle +++ b/wear/build.gradle @@ -3,7 +3,7 @@ apply from: "$rootProject.projectDir/shared-build.gradle" android { defaultConfig { - versionCode 27 + versionCode 31 } } From 4475b87e54628a0fd39618313ee5ab8806ad6db4 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Thu, 3 Mar 2022 20:42:09 +0100 Subject: [PATCH 12/13] replace super.getQsTile calls --- .../wakeonlan/quicksettings/DeviceTileService.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/de/florianisme/wakeonlan/quicksettings/DeviceTileService.java b/app/src/main/java/de/florianisme/wakeonlan/quicksettings/DeviceTileService.java index 7100c59..fd13f2c 100644 --- a/app/src/main/java/de/florianisme/wakeonlan/quicksettings/DeviceTileService.java +++ b/app/src/main/java/de/florianisme/wakeonlan/quicksettings/DeviceTileService.java @@ -30,20 +30,22 @@ private void updateTileState() { appDatabase = DatabaseInstanceManager.getInstance(this); Optional optionalMachine = getMachineAtIndex(machineAtIndex()); + Tile tile = super.getQsTile(); + if (optionalMachine.isPresent()) { Device device = optionalMachine.get(); this.device = device; - super.getQsTile().setLabel(device.name); + tile.setLabel(device.name); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - super.getQsTile().setSubtitle(getString(R.string.tile_subtitle)); + tile.setSubtitle(getString(R.string.tile_subtitle)); } - super.getQsTile().setState(Tile.STATE_ACTIVE); + tile.setState(Tile.STATE_ACTIVE); } else { - super.getQsTile().setLabel(getString(R.string.tile_no_device_found)); - super.getQsTile().setState(Tile.STATE_UNAVAILABLE); + tile.setLabel(getString(R.string.tile_no_device_found)); + tile.setState(Tile.STATE_UNAVAILABLE); } - super.getQsTile().updateTile(); + tile.updateTile(); } private Optional getMachineAtIndex(int index) { From e1812632e52a374b97ce7cccd88e7e232d5756b9 Mon Sep 17 00:00:00 2001 From: Florianisme Date: Thu, 3 Mar 2022 20:44:13 +0100 Subject: [PATCH 13/13] Increase version code/name --- app/build.gradle | 2 +- shared-build.gradle | 2 +- wear/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 696ecdd..5180c23 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,7 @@ apply from: "$rootProject.projectDir/shared-build.gradle" android { defaultConfig { - versionCode 30 + versionCode 33 wearAppUnbundled true } buildFeatures { diff --git a/shared-build.gradle b/shared-build.gradle index 8427096..99274c4 100644 --- a/shared-build.gradle +++ b/shared-build.gradle @@ -19,7 +19,7 @@ android { minSdk 24 targetSdk 31 versionCode 4 - versionName "1.4.0" + versionName "1.4.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/wear/build.gradle b/wear/build.gradle index bab54b5..3156598 100644 --- a/wear/build.gradle +++ b/wear/build.gradle @@ -3,7 +3,7 @@ apply from: "$rootProject.projectDir/shared-build.gradle" android { defaultConfig { - versionCode 31 + versionCode 32 } }