From 7283caa09c87a03a1e14d8f1e071b3e08c6ce578 Mon Sep 17 00:00:00 2001 From: Achilleas Koutsou Date: Thu, 20 Nov 2014 23:47:43 -0800 Subject: [PATCH] Manual IP connection This patch adds a new menu to add and remove IP addresses and hostnames, and makes LanBackend read that list of addresses and send identity packets to them. This bypasses the autodiscovery which usually happens via broadcast packets, and allows the pairing and communication of devices even if broadcast is not possible between them. BUG: 326509 REVIEW: 121104 --- src/main/AndroidManifest.xml | 11 ++ .../Backends/LanBackend/LanLinkProvider.java | 43 ++++-- .../UserInterface/CustomDevicesActivity.java | 142 ++++++++++++++++++ .../UserInterface/MainActivity.java | 3 + src/main/res/layout/custom_ip_list.xml | 36 +++++ src/main/res/menu/main.xml | 9 ++ src/main/res/values/strings.xml | 5 + 7 files changed, 234 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java create mode 100644 src/main/res/layout/custom_ip_list.xml diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 886e27cd..a15a529e 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -88,6 +88,17 @@ android:value="org.kde.kdeconnect.UserInterface.DeviceActivity" /> + + + + + + () { @Override protected Void doInBackground(Void... voids) { - - try { - NetworkPackage identity = NetworkPackage.createIdentityPackage(context); - identity.set("tcpPort",finalTcpPort); - byte[] b = identity.serialize().getBytes("UTF-8"); - DatagramPacket packet = new DatagramPacket(b, b.length, InetAddress.getByAddress(new byte[]{-1,-1,-1,-1}), port); - DatagramSocket socket = new DatagramSocket(); - socket.setReuseAddress(true); - socket.setBroadcast(true); - socket.send(packet); - //Log.e("LanLinkProvider","Udp identity package sent"); - } catch(Exception e) { - e.printStackTrace(); - Log.e("LanLinkProvider","Sending udp identity package failed"); + String deviceListPrefs = PreferenceManager.getDefaultSharedPreferences(context).getString( + KEY_CUSTOM_DEVLIST_PREFERENCE, ""); + ArrayList iplist = new ArrayList(); + if (!deviceListPrefs.isEmpty()) { + iplist = CustomDevicesActivity.deserializeIpList(deviceListPrefs); + } + iplist.add("255.255.255.255"); + for (String ipstr : iplist) { + try { + InetAddress client = InetAddress.getByName(ipstr); + NetworkPackage identity = NetworkPackage.createIdentityPackage(context); + identity.set("tcpPort", finalTcpPort); + byte[] b = identity.serialize().getBytes("UTF-8"); + DatagramPacket packet = new DatagramPacket(b, b.length, client, port); + DatagramSocket socket = new DatagramSocket(); + socket.setReuseAddress(true); + socket.setBroadcast(true); + socket.send(packet); + //Log.i("LanLinkProvider","Udp identity package sent to address "+packet.getAddress()); + } catch(Exception e) { + e.printStackTrace(); + Log.e("LanLinkProvider","Sending udp identity package failed. Invalid address? ("+ipstr+")"); + } } return null; diff --git a/src/main/java/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java b/src/main/java/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java new file mode 100644 index 00000000..98f0f73d --- /dev/null +++ b/src/main/java/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java @@ -0,0 +1,142 @@ +package org.kde.kdeconnect.UserInterface; + +import android.app.AlertDialog; +import android.app.ListActivity; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; + +import org.kde.kdeconnect_tp.R; + +import java.util.ArrayList; + +public class CustomDevicesActivity extends ListActivity { + + private static final String LOG_ID = "CustomDevicesActivity"; + public static final String KEY_CUSTOM_DEVLIST_PREFERENCE = "device_list_preference"; + private static final String IP_DELIM = ","; + + ArrayList ipAddressList = new ArrayList(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initializeDeviceList(this); + setContentView(R.layout.custom_ip_list); + setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, ipAddressList)); + + + EditText ipEntryBox = (EditText)findViewById(R.id.ip_edittext); + ipEntryBox.setOnEditorActionListener(new TextView.OnEditorActionListener() { + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEND) { + addNewIp(v); + return true; + } + return false; + } + }); + } + + @Override + public void onListItemClick(ListView l, View v, final int position, final long id) { + Log.i(LOG_ID, "Item clicked pos: "+position+" id: "+id); + // remove touched item after confirmation + DialogInterface.OnClickListener confirmationListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + ipAddressList.remove(position); + Log.i(LOG_ID, "Removed item pos: "+position+" id: "+id); + saveList(); + break; + case DialogInterface.BUTTON_NEGATIVE: + break; + } + } + }; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage("Delete "+ipAddressList.get(position)+" ?"); + builder.setPositiveButton("Yes", confirmationListener); + builder.setNegativeButton("No", confirmationListener); + builder.show(); + ((ArrayAdapter)getListAdapter()).notifyDataSetChanged(); + } + + public void addNewIp(View v) { + EditText ipEntryBox = (EditText)findViewById(R.id.ip_edittext); + String enteredText = ipEntryBox.getText().toString().trim(); + if (!enteredText.equals("")) { + // don't add empty string (after trimming) + ipAddressList.add(enteredText); + } + + saveList(); + // clear entry box + ipEntryBox.setText(""); + InputMethodManager inputManager = (InputMethodManager) + getSystemService(Context.INPUT_METHOD_SERVICE); + + inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), + InputMethodManager.HIDE_NOT_ALWAYS); + } + + void saveList() { + // add entry to list and save to preferences (unless empty) + String serialized = ""; + if (!ipAddressList.isEmpty()) { + serialized = serializeIpList(ipAddressList); + } + PreferenceManager.getDefaultSharedPreferences(this).edit().putString( + KEY_CUSTOM_DEVLIST_PREFERENCE, serialized).commit(); + ((ArrayAdapter)getListAdapter()).notifyDataSetChanged(); + + } + + static String serializeIpList(ArrayList iplist) { + String serialized = ""; + for (String ipaddr : iplist) { + serialized += IP_DELIM+ipaddr; + } + // remove first delimiter + serialized = serialized.substring(IP_DELIM.length()); + Log.d(LOG_ID, serialized); + return serialized; + } + + public static ArrayList deserializeIpList(String serialized) { + ArrayList iplist = new ArrayList(); + Log.d(LOG_ID, serialized); + for (String ipaddr : serialized.split(IP_DELIM)) { + iplist.add(ipaddr); + Log.d(LOG_ID, ipaddr); + } + return iplist; + } + + void initializeDeviceList(Context context){ + String deviceListPrefs = PreferenceManager.getDefaultSharedPreferences(context).getString( + KEY_CUSTOM_DEVLIST_PREFERENCE, + ""); + if(deviceListPrefs.isEmpty()){ + Log.i(LOG_ID, "Initialising empty custom device list"); + PreferenceManager.getDefaultSharedPreferences(context).edit().putString( + KEY_CUSTOM_DEVLIST_PREFERENCE, + deviceListPrefs).commit(); + } else { + Log.i(LOG_ID, "Populating device list"); + ipAddressList = deserializeIpList(deviceListPrefs); + } + } +} diff --git a/src/main/java/org/kde/kdeconnect/UserInterface/MainActivity.java b/src/main/java/org/kde/kdeconnect/UserInterface/MainActivity.java index a2c6c6d7..99fcddc3 100644 --- a/src/main/java/org/kde/kdeconnect/UserInterface/MainActivity.java +++ b/src/main/java/org/kde/kdeconnect/UserInterface/MainActivity.java @@ -89,6 +89,9 @@ public class MainActivity extends ActionBarActivity { case R.id.menu_settings: startActivity(new Intent(this,MainSettingsActivity.class)); break; + case R.id.menu_custom_device_list: + startActivity(new Intent(this, CustomDevicesActivity.class)); + break; default: break; } diff --git a/src/main/res/layout/custom_ip_list.xml b/src/main/res/layout/custom_ip_list.xml new file mode 100644 index 00000000..65162eb1 --- /dev/null +++ b/src/main/res/layout/custom_ip_list.xml @@ -0,0 +1,36 @@ + + + + + + + + +