2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-30 13:47:41 +00:00

Merge branch '1.x'

# Conflicts:
#	src/org/kde/kdeconnect/Plugins/TelepathyPlugin/TelepathyPlugin.java
This commit is contained in:
Albert Vaca
2017-07-14 01:38:37 +02:00
10 changed files with 131 additions and 45 deletions

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.kde.kdeconnect_tp" package="org.kde.kdeconnect_tp"
android:versionCode="1621" android:versionCode="1650"
android:versionName="1.6.2"> android:versionName="1.6.5">
<uses-sdk android:minSdkVersion="9" <uses-sdk android:minSdkVersion="9"
android:targetSdkVersion="25" /> android:targetSdkVersion="25" />

View File

@@ -59,7 +59,7 @@ public class ContactsHelper {
, PhoneLookup.ID */ , PhoneLookup.ID */
}, },
null, null, null); null, null, null);
} catch (IllegalArgumentException e) { } catch (Exception e) {
return contactInfo; return contactInfo;
} }

View File

@@ -6,25 +6,53 @@ import android.net.Network;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.util.Log; import android.util.Log;
import java.io.FileReader;
import java.io.LineNumberReader;
public class NetworkHelper { public class NetworkHelper {
public static boolean isOnMobileNetwork(Context context) { 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 return false; //No good way to know it
} }
boolean mobile = false; try {
final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); boolean mobile = false;
Network[] networks = connMgr.getAllNetworks(); final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
for (Network network : networks) { Network[] networks = connMgr.getAllNetworks();
NetworkInfo info = connMgr.getNetworkInfo(network); for (Network network : networks) {
if (info.getType() == ConnectivityManager.TYPE_MOBILE) { NetworkInfo info = connMgr.getNetworkInfo(network);
mobile = info.isConnected(); if (info == null) {
continue; 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 (mobile) { //We suspect we are on a mobile net
if (info.isAvailable()) return false; //We are connected to at least one non-mobile network 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;
} }
} }

View File

@@ -40,7 +40,7 @@ public class BatteryPlugin extends Plugin {
private static final int THRESHOLD_EVENT_NONE= 0; private static final int THRESHOLD_EVENT_NONE= 0;
private static final int THRESHOLD_EVENT_BATTERY_LOW = 1; private static final int THRESHOLD_EVENT_BATTERY_LOW = 1;
private NetworkPackage lastInfo = null; private NetworkPackage batteryInfo = new NetworkPackage(PACKAGE_TYPE_BATTERY);
@Override @Override
public String getDisplayName() { public String getDisplayName() {
@@ -56,18 +56,18 @@ public class BatteryPlugin extends Plugin {
@Override @Override
public void onReceive(Context context, Intent batteryIntent) { public void onReceive(Context context, Intent batteryIntent) {
Intent batteryChargeIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int level = batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
int scale = batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1); int plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
int currentCharge = level*100 / scale;
boolean isCharging = (0 != batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)); 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()); boolean lowBattery = Intent.ACTION_BATTERY_LOW.equals(batteryIntent.getAction());
int thresholdEvent = lowBattery? THRESHOLD_EVENT_BATTERY_LOW : THRESHOLD_EVENT_NONE; int thresholdEvent = lowBattery? THRESHOLD_EVENT_BATTERY_LOW : THRESHOLD_EVENT_NONE;
if (lastInfo != null if (isCharging == batteryInfo.getBoolean("isCharging")
&& isCharging == lastInfo.getBoolean("isCharging") && currentCharge == batteryInfo.getInt("currentCharge")
&& currentCharge == lastInfo.getInt("currentCharge") && thresholdEvent == batteryInfo.getInt("thresholdEvent")
&& thresholdEvent == lastInfo.getInt("thresholdEvent")
) { ) {
//Do not send again if nothing has changed //Do not send again if nothing has changed
@@ -75,12 +75,10 @@ public class BatteryPlugin extends Plugin {
} else { } else {
NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_BATTERY); batteryInfo.set("currentCharge", currentCharge);
np.set("currentCharge", currentCharge); batteryInfo.set("isCharging", isCharging);
np.set("isCharging", isCharging); batteryInfo.set("thresholdEvent", thresholdEvent);
np.set("thresholdEvent", thresholdEvent); device.sendPackage(batteryInfo);
device.sendPackage(np);
lastInfo = np;
} }
@@ -89,8 +87,10 @@ public class BatteryPlugin extends Plugin {
@Override @Override
public boolean onCreate() { public boolean onCreate() {
context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); IntentFilter intentFilter = new IntentFilter();
context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_LOW)); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
intentFilter.addAction(Intent.ACTION_BATTERY_LOW);
context.registerReceiver(receiver, intentFilter);
return true; return true;
} }
@@ -104,9 +104,7 @@ public class BatteryPlugin extends Plugin {
public boolean onPackageReceived(NetworkPackage np) { public boolean onPackageReceived(NetworkPackage np) {
if (np.getBoolean("request")) { if (np.getBoolean("request")) {
if (lastInfo != null) { device.sendPackage(batteryInfo);
device.sendPackage(lastInfo);
}
} }
return true; return true;

View File

@@ -138,6 +138,10 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
@Override @Override
public void onNotificationRemoved(StatusBarNotification statusBarNotification) { public void onNotificationRemoved(StatusBarNotification statusBarNotification) {
if (statusBarNotification == null) {
Log.w("onNotificationRemoved", "notification is null");
return;
}
String id = getNotificationKeyCompat(statusBarNotification); String id = getNotificationKeyCompat(statusBarNotification);
NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_NOTIFICATION); NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_NOTIFICATION);
np.set("id", id); np.set("id", id);

View File

@@ -125,7 +125,7 @@ class SimpleSftpServer {
public void stop() { public void stop() {
try { try {
started = false; started = false;
sshd.stop(); sshd.stop(true);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -144,6 +144,17 @@ class SimpleSftpServer {
try { try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement(); 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<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement(); InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) { if (!inetAddress.isLoopbackAddress()) {

View File

@@ -27,6 +27,8 @@ import android.support.v4.content.ContextCompat;
import android.telephony.SmsManager; import android.telephony.SmsManager;
import android.util.Log; import android.util.Log;
import java.util.ArrayList;
import org.kde.kdeconnect.NetworkPackage; import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin; import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.Plugins.TelephonyPlugin.TelephonyPlugin; import org.kde.kdeconnect.Plugins.TelephonyPlugin.TelephonyPlugin;
@@ -70,10 +72,17 @@ public class TelepathyPlugin extends Plugin {
String phoneNo = np.getString("phoneNumber"); String phoneNo = np.getString("phoneNumber");
String sms = np.getString("messageBody"); String sms = np.getString("messageBody");
try { try {
SmsManager smsManager = SmsManager.getDefault(); if(permissionCheck == PackageManager.PERMISSION_GRANTED) {
smsManager.sendTextMessage(phoneNo, null, sms, null, null); SmsManager smsManager = SmsManager.getDefault();
Log.d("TelepathyPlugin", "SMS sent");
ArrayList<String> 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 //TODO: Notify other end
} catch (Exception e) { } catch (Exception e) {
//TODO: Notify other end //TODO: Notify other end

View File

@@ -37,8 +37,10 @@ import android.util.Log;
import org.kde.kdeconnect.Helpers.ContactsHelper; import org.kde.kdeconnect.Helpers.ContactsHelper;
import org.kde.kdeconnect.NetworkPackage; import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin; import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect_tp.BuildConfig;
import org.kde.kdeconnect_tp.R; import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@@ -78,11 +80,19 @@ public class TelephonyPlugin extends Plugin {
final Bundle bundle = intent.getExtras(); final Bundle bundle = intent.getExtras();
if (bundle == null) return; if (bundle == null) return;
final Object[] pdus = (Object[]) bundle.get("pdus"); final Object[] pdus = (Object[]) bundle.get("pdus");
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
for (Object pdu : pdus) { for (Object pdu : pdus) {
SmsMessage message = SmsMessage.createFromPdu((byte[])pdu); // I hope, but am not sure, that the pdus array is in the order that the parts
smsBroadcastReceived(message); // 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)) { } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
@@ -208,7 +218,14 @@ public class TelephonyPlugin extends Plugin {
lastState = state; lastState = state;
} }
private void smsBroadcastReceived(SmsMessage message) { private void smsBroadcastReceived(ArrayList<SmsMessage> messages) {
if (BuildConfig.DEBUG) {
if (!(messages.size() > 0))
{
throw new AssertionError("This method requires at least one message");
}
}
//Log.e("SmsBroadcastReceived", message.toString()); //Log.e("SmsBroadcastReceived", message.toString());
@@ -216,12 +233,18 @@ public class TelephonyPlugin extends Plugin {
np.set("event","sms"); 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) { if (messageBody != null) {
np.set("messageBody",messageBody); np.set("messageBody",messageBody);
} }
String phoneNumber = message.getOriginatingAddress(); String phoneNumber = messages.get(0).getOriginatingAddress();
int permissionCheck = ContextCompat.checkSelfPermission(context, int permissionCheck = ContextCompat.checkSelfPermission(context,
Manifest.permission.READ_CONTACTS); Manifest.permission.READ_CONTACTS);

View File

@@ -446,6 +446,10 @@ public class DeviceFragment extends Fragment {
BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() { BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() {
public void onServiceStart(BackgroundService service) { public void onServiceStart(BackgroundService service) {
Device dev = service.getDevice(devId); Device dev = service.getDevice(devId);
if (dev == null) {
Log.w("rejectPairing", "Device no longer exists: "+devId);
return;
}
activity.getSupportActionBar().setTitle(dev.getName()); activity.getSupportActionBar().setTitle(dev.getName());
dev.addPairingCallback(frag.pairingCallback); dev.addPairingCallback(frag.pairingCallback);
@@ -465,6 +469,10 @@ public class DeviceFragment extends Fragment {
BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() { BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() {
public void onServiceStart(BackgroundService service) { public void onServiceStart(BackgroundService service) {
Device dev = service.getDevice(devId); Device dev = service.getDevice(devId);
if (dev == null) {
Log.w("rejectPairing", "Device no longer exists: "+devId);
return;
}
activity.getSupportActionBar().setTitle(dev.getName()); activity.getSupportActionBar().setTitle(dev.getName());
dev.addPairingCallback(frag.pairingCallback); dev.addPairingCallback(frag.pairingCallback);

View File

@@ -132,6 +132,11 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
@Override @Override
public void run() { 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) { if (listRefreshCalledThisFrame) {
// This makes sure we don't try to call list.getFirstVisiblePosition() // This makes sure we don't try to call list.getFirstVisiblePosition()
// twice per frame, because the second time the list hasn't been drawn // twice per frame, because the second time the list hasn't been drawn