diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 481efc38..ed7ecbaf 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="1650" + android:versionName="1.6.5"> diff --git a/src/org/kde/kdeconnect/Helpers/ContactsHelper.java b/src/org/kde/kdeconnect/Helpers/ContactsHelper.java index 92a860bb..90279638 100644 --- a/src/org/kde/kdeconnect/Helpers/ContactsHelper.java +++ b/src/org/kde/kdeconnect/Helpers/ContactsHelper.java @@ -59,7 +59,7 @@ public class ContactsHelper { , PhoneLookup.ID */ }, null, null, null); - } catch (IllegalArgumentException e) { + } catch (Exception e) { return contactInfo; } diff --git a/src/org/kde/kdeconnect/Helpers/NetworkHelper.java b/src/org/kde/kdeconnect/Helpers/NetworkHelper.java index f6d37425..27825970 100644 --- a/src/org/kde/kdeconnect/Helpers/NetworkHelper.java +++ b/src/org/kde/kdeconnect/Helpers/NetworkHelper.java @@ -6,25 +6,53 @@ import android.net.Network; import android.net.NetworkInfo; import android.util.Log; +import java.io.FileReader; +import java.io.LineNumberReader; + public class NetworkHelper { public static boolean isOnMobileNetwork(Context context) { - if (context == null || android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) { + if (context == null) { + return false; + } + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) { return false; //No good way to know it } - boolean mobile = false; - final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - Network[] networks = connMgr.getAllNetworks(); - for (Network network : networks) { - NetworkInfo info = connMgr.getNetworkInfo(network); - if (info.getType() == ConnectivityManager.TYPE_MOBILE) { - mobile = info.isConnected(); - continue; + try { + boolean mobile = false; + final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + Network[] networks = connMgr.getAllNetworks(); + for (Network network : networks) { + NetworkInfo info = connMgr.getNetworkInfo(network); + if (info == null) { + continue; + } + if (info.getType() == ConnectivityManager.TYPE_MOBILE) { + mobile = info.isConnected(); + continue; + } + //Log.e(info.getTypeName(),""+info.isAvailable()); + if (info.isAvailable()) return false; //We are connected to at least one non-mobile network } - Log.e(info.getTypeName(),""+info.isAvailable()); - if (info.isAvailable()) return false; //We are connected to at least one non-mobile network + if (mobile) { //We suspect we are on a mobile net + try { + //Check the number of network neighbours, on data it should be 0 + LineNumberReader is = new LineNumberReader(new FileReader("/proc/net/arp")); + is.skip(Long.MAX_VALUE); + //Log.e("NetworkHelper", "procnetarp has " + is.getLineNumber() + " lines"); + if (is.getLineNumber() > 1) { //The first line are the headers + return false; //I have neighbours, so this doesn't look like a mobile network + } + } catch (Exception e) { + Log.e("NetworkHelper", "Exception reading procnetarp"); + e.printStackTrace(); + } + } + } catch(Exception e) { + e.printStackTrace(); + Log.d("isOnMobileNetwork", "Something went wrong, but this is non-critical."); } - return mobile; + return false; } } diff --git a/src/org/kde/kdeconnect/Plugins/BatteryPlugin/BatteryPlugin.java b/src/org/kde/kdeconnect/Plugins/BatteryPlugin/BatteryPlugin.java index 142b4dfe..b4f1697d 100644 --- a/src/org/kde/kdeconnect/Plugins/BatteryPlugin/BatteryPlugin.java +++ b/src/org/kde/kdeconnect/Plugins/BatteryPlugin/BatteryPlugin.java @@ -40,7 +40,7 @@ public class BatteryPlugin extends Plugin { private static final int THRESHOLD_EVENT_NONE= 0; private static final int THRESHOLD_EVENT_BATTERY_LOW = 1; - private NetworkPackage lastInfo = null; + private NetworkPackage batteryInfo = new NetworkPackage(PACKAGE_TYPE_BATTERY); @Override public String getDisplayName() { @@ -56,18 +56,18 @@ public class BatteryPlugin extends Plugin { @Override public void onReceive(Context context, Intent batteryIntent) { - Intent batteryChargeIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - int level = batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - int scale = batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1); - int currentCharge = level*100 / scale; - boolean isCharging = (0 != batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)); + int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); + int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1); + int plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + + int currentCharge = (level == -1)? batteryInfo.getInt("currentCharge") : level*100 / scale; + boolean isCharging = (plugged == -1)? batteryInfo.getBoolean("isCharging") : (0 != plugged); boolean lowBattery = Intent.ACTION_BATTERY_LOW.equals(batteryIntent.getAction()); int thresholdEvent = lowBattery? THRESHOLD_EVENT_BATTERY_LOW : THRESHOLD_EVENT_NONE; - if (lastInfo != null - && isCharging == lastInfo.getBoolean("isCharging") - && currentCharge == lastInfo.getInt("currentCharge") - && thresholdEvent == lastInfo.getInt("thresholdEvent") + if (isCharging == batteryInfo.getBoolean("isCharging") + && currentCharge == batteryInfo.getInt("currentCharge") + && thresholdEvent == batteryInfo.getInt("thresholdEvent") ) { //Do not send again if nothing has changed @@ -75,12 +75,10 @@ public class BatteryPlugin extends Plugin { } else { - NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_BATTERY); - np.set("currentCharge", currentCharge); - np.set("isCharging", isCharging); - np.set("thresholdEvent", thresholdEvent); - device.sendPackage(np); - lastInfo = np; + batteryInfo.set("currentCharge", currentCharge); + batteryInfo.set("isCharging", isCharging); + batteryInfo.set("thresholdEvent", thresholdEvent); + device.sendPackage(batteryInfo); } @@ -89,8 +87,10 @@ public class BatteryPlugin extends Plugin { @Override public boolean onCreate() { - context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_LOW)); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); + intentFilter.addAction(Intent.ACTION_BATTERY_LOW); + context.registerReceiver(receiver, intentFilter); return true; } @@ -104,9 +104,7 @@ public class BatteryPlugin extends Plugin { public boolean onPackageReceived(NetworkPackage np) { if (np.getBoolean("request")) { - if (lastInfo != null) { - device.sendPackage(lastInfo); - } + device.sendPackage(batteryInfo); } return true; diff --git a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java index d2643c09..3fb320f5 100644 --- a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java +++ b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java @@ -138,6 +138,10 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver. @Override public void onNotificationRemoved(StatusBarNotification statusBarNotification) { + if (statusBarNotification == null) { + Log.w("onNotificationRemoved", "notification is null"); + return; + } String id = getNotificationKeyCompat(statusBarNotification); NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_NOTIFICATION); np.set("id", id); diff --git a/src/org/kde/kdeconnect/Plugins/SftpPlugin/SimpleSftpServer.java b/src/org/kde/kdeconnect/Plugins/SftpPlugin/SimpleSftpServer.java index 67b5a73b..9fa6571f 100644 --- a/src/org/kde/kdeconnect/Plugins/SftpPlugin/SimpleSftpServer.java +++ b/src/org/kde/kdeconnect/Plugins/SftpPlugin/SimpleSftpServer.java @@ -125,7 +125,7 @@ class SimpleSftpServer { public void stop() { try { started = false; - sshd.stop(); + sshd.stop(true); } catch (Exception e) { e.printStackTrace(); } @@ -144,6 +144,17 @@ class SimpleSftpServer { try { for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); + + // Anything with rmnet is related to cellular connections or USB + // tethering mechanisms. See: + // + // https://android.googlesource.com/kernel/msm/+/android-msm-flo-3.4-kitkat-mr1/Documentation/usb/gadget_rmnet.txt + // + // If we run across an interface that has this, we can safely + // ignore it. In fact, it's much safer to do. If we don't, we + // might get invalid IP adddresses out of it. + if(intf.getDisplayName().contains("rmnet")) continue; + for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress()) { diff --git a/src/org/kde/kdeconnect/Plugins/TelepathyPlugin/TelepathyPlugin.java b/src/org/kde/kdeconnect/Plugins/TelepathyPlugin/TelepathyPlugin.java index 50312ae8..de466a9a 100644 --- a/src/org/kde/kdeconnect/Plugins/TelepathyPlugin/TelepathyPlugin.java +++ b/src/org/kde/kdeconnect/Plugins/TelepathyPlugin/TelepathyPlugin.java @@ -27,6 +27,8 @@ import android.support.v4.content.ContextCompat; import android.telephony.SmsManager; import android.util.Log; +import java.util.ArrayList; + import org.kde.kdeconnect.NetworkPackage; import org.kde.kdeconnect.Plugins.Plugin; import org.kde.kdeconnect.Plugins.TelephonyPlugin.TelephonyPlugin; @@ -70,10 +72,17 @@ public class TelepathyPlugin extends Plugin { String phoneNo = np.getString("phoneNumber"); String sms = np.getString("messageBody"); try { - SmsManager smsManager = SmsManager.getDefault(); - smsManager.sendTextMessage(phoneNo, null, sms, null, null); - Log.d("TelepathyPlugin", "SMS sent"); + if(permissionCheck == PackageManager.PERMISSION_GRANTED) { + SmsManager smsManager = SmsManager.getDefault(); + ArrayList parts = smsManager.divideMessage(sms); + + // If this message turns out to fit in a single SMS, sendMultpartTextMessage + // properly handles that case + smsManager.sendMultipartTextMessage(phoneNo, null, parts, null, null); + } else if(permissionCheck == PackageManager.PERMISSION_DENIED){ + // TODO Request Permission SEND_SMS + } //TODO: Notify other end } catch (Exception e) { //TODO: Notify other end diff --git a/src/org/kde/kdeconnect/Plugins/TelephonyPlugin/TelephonyPlugin.java b/src/org/kde/kdeconnect/Plugins/TelephonyPlugin/TelephonyPlugin.java index d0b6d7bb..d0237214 100644 --- a/src/org/kde/kdeconnect/Plugins/TelephonyPlugin/TelephonyPlugin.java +++ b/src/org/kde/kdeconnect/Plugins/TelephonyPlugin/TelephonyPlugin.java @@ -37,8 +37,10 @@ import android.util.Log; import org.kde.kdeconnect.Helpers.ContactsHelper; import org.kde.kdeconnect.NetworkPackage; import org.kde.kdeconnect.Plugins.Plugin; +import org.kde.kdeconnect_tp.BuildConfig; import org.kde.kdeconnect_tp.R; +import java.util.ArrayList; import java.util.Map; import java.util.Timer; import java.util.TimerTask; @@ -78,11 +80,19 @@ public class TelephonyPlugin extends Plugin { final Bundle bundle = intent.getExtras(); if (bundle == null) return; final Object[] pdus = (Object[]) bundle.get("pdus"); + ArrayList messages = new ArrayList(); + for (Object pdu : pdus) { - SmsMessage message = SmsMessage.createFromPdu((byte[])pdu); - smsBroadcastReceived(message); + // I hope, but am not sure, that the pdus array is in the order that the parts + // of the SMS message should be + // If it is not, I belive the pdu contains the information necessary to put it + // in order, but in my testing the order seems to be correct, so I won't worry + // about it now. + messages.add(SmsMessage.createFromPdu((byte[])pdu)); } + smsBroadcastReceived(messages); + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); @@ -208,7 +218,14 @@ public class TelephonyPlugin extends Plugin { lastState = state; } - private void smsBroadcastReceived(SmsMessage message) { + private void smsBroadcastReceived(ArrayList messages) { + + if (BuildConfig.DEBUG) { + if (!(messages.size() > 0)) + { + throw new AssertionError("This method requires at least one message"); + } + } //Log.e("SmsBroadcastReceived", message.toString()); @@ -216,12 +233,18 @@ public class TelephonyPlugin extends Plugin { np.set("event","sms"); - String messageBody = message.getMessageBody(); + String messageBody = new String(); + + for (int index = 0; index < messages.size(); index ++) + { + messageBody += messages.get(index).getMessageBody(); + } + if (messageBody != null) { np.set("messageBody",messageBody); } - String phoneNumber = message.getOriginatingAddress(); + String phoneNumber = messages.get(0).getOriginatingAddress(); int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS); diff --git a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java index 0cc89d6c..057064df 100644 --- a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java +++ b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java @@ -446,6 +446,10 @@ public class DeviceFragment extends Fragment { BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() { public void onServiceStart(BackgroundService service) { Device dev = service.getDevice(devId); + if (dev == null) { + Log.w("rejectPairing", "Device no longer exists: "+devId); + return; + } activity.getSupportActionBar().setTitle(dev.getName()); dev.addPairingCallback(frag.pairingCallback); @@ -465,6 +469,10 @@ public class DeviceFragment extends Fragment { BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() { public void onServiceStart(BackgroundService service) { Device dev = service.getDevice(devId); + if (dev == null) { + Log.w("rejectPairing", "Device no longer exists: "+devId); + return; + } activity.getSupportActionBar().setTitle(dev.getName()); dev.addPairingCallback(frag.pairingCallback); diff --git a/src/org/kde/kdeconnect/UserInterface/PairingFragment.java b/src/org/kde/kdeconnect/UserInterface/PairingFragment.java index 2db9ecb2..67c37543 100644 --- a/src/org/kde/kdeconnect/UserInterface/PairingFragment.java +++ b/src/org/kde/kdeconnect/UserInterface/PairingFragment.java @@ -132,6 +132,11 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb @Override public void run() { + if (!isAdded()) { + //Fragment is not attached to an activity. We will crash if we try to do anything here. + return; + } + if (listRefreshCalledThisFrame) { // This makes sure we don't try to call list.getFirstVisiblePosition() // twice per frame, because the second time the list hasn't been drawn