+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.kde.kdeconnect.Plugins.SMSPlugin;
+
+import android.content.Context;
+import android.content.Intent;
+
+import com.klinker.android.send_message.Transaction;
+import com.klinker.android.send_message.Utils;
+
+public class MmsSentReceiver extends com.klinker.android.send_message.MmsSentReceiver {
+
+ @Override
+ public void updateInInternalDatabase(Context context, Intent intent, int resultCode) {
+ super.updateInInternalDatabase(context, intent, resultCode);
+
+ if (Utils.isDefaultSmsApp(context)) {
+ // Notify messageUpdateReceiver about the successful sending of the mms message
+ Intent refreshIntent = new Intent(Transaction.REFRESH);
+ context.sendBroadcast(refreshIntent);
+ }
+ }
+
+ @Override
+ public void onMessageStatusUpdated(Context context, Intent intent, int resultCode) {
+ }
+}
diff --git a/src/org/kde/kdeconnect/Plugins/SMSPlugin/SMSPlugin.java b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SMSPlugin.java
index 0a49288d..71daecaa 100644
--- a/src/org/kde/kdeconnect/Plugins/SMSPlugin/SMSPlugin.java
+++ b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SMSPlugin.java
@@ -39,7 +39,6 @@ import android.provider.Telephony;
import android.telephony.PhoneNumberUtils;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
-import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
@@ -63,6 +62,11 @@ import java.util.concurrent.locks.ReentrantLock;
import androidx.core.content.ContextCompat;
+import com.klinker.android.send_message.ApnUtils;
+import com.klinker.android.send_message.Transaction;
+import com.klinker.android.send_message.Utils;
+import com.klinker.android.logger.Log;
+
import static org.kde.kdeconnect.Plugins.TelephonyPlugin.TelephonyPlugin.PACKET_TYPE_TELEPHONY;
@PluginFactory.LoadablePlugin
@@ -125,9 +129,10 @@ public class SMSPlugin extends Plugin {
*
* The body should look like so:
* { "sendSms": true,
- * "phoneNumber": "542904563213",
- * "messageBody": "Hi mom!",
- * "sub_id": "3859358340534"
+ * "phoneNumber": "542904563213" // For older desktop versions of SMS app this packet carries phoneNumber field
+ * "addresses": // For newer desktop versions of SMS app it contains addresses field instead of phoneNumber field
+ * "messageBody": "Hi mom!",
+ * "sub_id": "3859358340534"
* }
*/
private final static String PACKET_TYPE_SMS_REQUEST = "kdeconnect.sms.request";
@@ -210,33 +215,64 @@ public class SMSPlugin extends Plugin {
*/
@Override
public void onChange(boolean selfChange) {
- // Lock so no one uses the mostRecentTimestamp between the moment we read it and the
- // moment we update it. This is because reading the Messages DB can take long.
- mostRecentTimestampLock.lock();
-
- if (mostRecentTimestamp == 0) {
- // Since the timestamp has not been initialized, we know that nobody else
- // has requested a message. That being the case, there is most likely
- // nobody listening for message updates, so just drop them
- mostRecentTimestampLock.unlock();
+ // If the KDE Connect is set as default Sms app
+ // prevent from reading the latest message in the database before the sentReceivers mark it as sent
+ if (Utils.isDefaultSmsApp(context)) {
return;
}
- SMSHelper.Message message = SMSHelper.getNewestMessage(context);
-
- if (message == null || message.date <= mostRecentTimestamp) {
- // onChange can trigger many times for a single message. Don't make unnecessary noise
- mostRecentTimestampLock.unlock();
- return;
- }
-
- // Update the most recent counter
- mostRecentTimestamp = message.date;
- mostRecentTimestampLock.unlock();
-
- // Send the alert about the update
- device.sendPacket(constructBulkMessagePacket(Collections.singleton(message)));
+ sendLatestMessage();
}
+
+ }
+
+ /**
+ * This receiver will be invoked only when the app will be set as the default sms app
+ * Whenever the app will be set as the default, the database update alert will be sent
+ * using messageUpdateReceiver and not the contentObserver class
+ */
+ private final BroadcastReceiver messagesUpdateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ String action = intent.getAction();
+
+ if (Transaction.REFRESH.equals(action)) {
+ sendLatestMessage();
+ }
+ }
+ };
+
+ /**
+ * Helper method to read the latest message from the sms-mms database and sends it to the desktop
+ */
+ private void sendLatestMessage() {
+ // Lock so no one uses the mostRecentTimestamp between the moment we read it and the
+ // moment we update it. This is because reading the Messages DB can take long.
+ mostRecentTimestampLock.lock();
+
+ if (mostRecentTimestamp == 0) {
+ // Since the timestamp has not been initialized, we know that nobody else
+ // has requested a message. That being the case, there is most likely
+ // nobody listening for message updates, so just drop them
+ mostRecentTimestampLock.unlock();
+ return;
+ }
+ SMSHelper.Message message = SMSHelper.getNewestMessage(context);
+
+ if (message == null || message.date <= mostRecentTimestamp) {
+ // onChange can trigger many times for a single message. Don't make unnecessary noise
+ mostRecentTimestampLock.unlock();
+ return;
+ }
+
+ // Update the most recent counter
+ mostRecentTimestamp = message.date;
+ mostRecentTimestampLock.unlock();
+
+ // Send the alert about the update
+ device.sendPacket(constructBulkMessagePacket(Collections.singleton(message)));
+ Log.e("sent", "update");
}
/**
@@ -304,6 +340,10 @@ public class SMSPlugin extends Plugin {
filter.setPriority(500);
context.registerReceiver(receiver, filter);
+ IntentFilter refreshFilter = new IntentFilter(Transaction.REFRESH);
+ refreshFilter.setPriority(500);
+ context.registerReceiver(messagesUpdateReceiver, refreshFilter);
+
Looper helperLooper = SMSHelper.MessageLooper.getLooper();
ContentObserver messageObserver = new MessageContentObserver(new Handler(helperLooper));
SMSHelper.registerObserver(messageObserver, context);
@@ -312,6 +352,13 @@ public class SMSPlugin extends Plugin {
Log.w("SMSPlugin", "This is a very old version of Android. The SMS Plugin might not function as intended.");
}
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ ApnUtils.initDefaultApns(context, null);
+ }
+
+ // To see debug messages for Klinker library, uncomment the below line
+ //Log.setDebug(true);
+
return true;
}
@@ -334,8 +381,22 @@ public class SMSPlugin extends Plugin {
case PACKET_TYPE_SMS_REQUEST_CONVERSATION:
return this.handleRequestConversation(np);
case PACKET_TYPE_SMS_REQUEST:
- // Fall through to old-style handling
- // This space may be filled in differently once MMS support is implemented
+ if (np.getBoolean("sendSms")) {
+ String textMessage = np.getString("messageBody");
+ long subID = np.getLong("subID", -1);
+
+ List addressList = SMSHelper.jsonArrayToAddressList(np.getJSONArray("addresses"));
+ if (addressList == null) {
+ // If the List of Address is null, then the SMS_REQUEST packet is
+ // most probably from the older version of the desktop app.
+ addressList = new ArrayList<>();
+ addressList.add(new SMSHelper.Address(np.getString("phoneNumber")));
+ }
+
+ SmsMmsUtils.sendMessage(context, textMessage, addressList, (int) subID);
+ }
+ break;
+
case TelephonyPlugin.PACKET_TYPE_TELEPHONY_REQUEST:
if (np.getBoolean("sendSms")) {
String phoneNo = np.getString("phoneNumber");
@@ -432,6 +493,17 @@ public class SMSPlugin extends Plugin {
conversation = SMSHelper.getMessagesInRange(this.context, threadID, rangeStartTimestamp, numberToGet);
}
+ // Sometimes when desktop app is kept open while android app is restarted for any reason
+ // mostRecentTimeStamp must be updated in that scenario too if a user request for a
+ // single conversation and not the entire conversation list
+ mostRecentTimestampLock.lock();
+ for (SMSHelper.Message message : conversation) {
+ if (message.date > mostRecentTimestamp) {
+ mostRecentTimestamp = message.date;
+ }
+ }
+ mostRecentTimestampLock.unlock();
+
NetworkPacket reply = constructBulkMessagePacket(conversation);
device.sendPacket(reply);
@@ -451,6 +523,10 @@ public class SMSPlugin extends Plugin {
return false;
}
+ @Override
+ public boolean hasSettings() {
+ return true;
+ }
@Override
public String[] getSupportedPacketTypes() {
@@ -478,6 +554,19 @@ public class SMSPlugin extends Plugin {
};
}
+ /**
+ * Permissions required for sending and receiving MMs messages
+ */
+ public static String[] getMmsPermissions() {
+ return new String[]{
+ Manifest.permission.RECEIVE_SMS,
+ Manifest.permission.RECEIVE_MMS,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.CHANGE_NETWORK_STATE,
+ Manifest.permission.WAKE_LOCK,
+ };
+ }
+
/**
* With versions older than KITKAT, lots of the content providers used in SMSHelper become
* un-documented. Most manufacturers *did* do things the same way as was done in mainline
diff --git a/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsMmsUtils.java b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsMmsUtils.java
new file mode 100644
index 00000000..ee60270a
--- /dev/null
+++ b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsMmsUtils.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2020 Aniket Kumar
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.kde.kdeconnect.Plugins.SMSPlugin;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.preference.PreferenceManager;
+
+import com.klinker.android.send_message.Message;
+import com.klinker.android.send_message.MmsSentReceiver;
+import com.klinker.android.send_message.Settings;
+import com.klinker.android.send_message.Transaction;
+import com.klinker.android.send_message.Utils;
+
+import org.kde.kdeconnect.Helpers.SMSHelper;
+import org.kde.kdeconnect_tp.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SmsMmsUtils {
+
+ private static final String SENDING_MESSAGE = "Sending message";
+
+ /**
+ * Sends SMS or MMS message.
+ *
+ * @param context context in which the method is called.
+ * @param textMessage text body of the message to be sent.
+ * @param addressList List of addresses.
+ * @param subID Note that here subID is of type int and not long because klinker library requires it as int
+ * I don't really know the exact reason why they implemented it as int instead of long
+ */
+ public static void sendMessage(Context context, String textMessage, List addressList, int subID) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ boolean longTextAsMms = prefs.getBoolean(context.getString(R.string.set_long_text_as_mms), false);
+ boolean groupMessageAsMms = prefs.getBoolean(context.getString(R.string.set_group_message_as_mms), true);
+ int sendLongAsMmsAfter = Integer.parseInt(
+ prefs.getString(context.getString(R.string.convert_to_mms_after),
+ context.getString(R.string.convert_to_mms_after_default)));
+
+ try {
+ Settings settings = new Settings();
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ // If the build version is less than lollipop then we have to manually take the APN settings
+ // from the user in order to be able to send MMS.
+ settings.setMmsc(prefs.getString(context.getString(R.string.sms_pref_set_mmsc), ""));
+ settings.setProxy(prefs.getString(context.getString(R.string.sms_pref_set_mms_proxy), ""));
+ settings.setPort(prefs.getString(context.getString(R.string.sms_pref_set_mms_port), ""));
+ }
+
+ settings.setUseSystemSending(true);
+
+ if (Utils.isDefaultSmsApp(context)) {
+ settings.setSendLongAsMms(longTextAsMms);
+ settings.setSendLongAsMmsAfter(sendLongAsMmsAfter);
+ }
+
+ settings.setGroup(groupMessageAsMms);
+
+ if (subID != -1) {
+ settings.setSubscriptionId(subID);
+ }
+
+ Transaction transaction = new Transaction(context, settings);
+ transaction.setExplicitBroadcastForSentSms(new Intent(context, SmsSentReceiver.class));
+ transaction.setExplicitBroadcastForSentMms(new Intent(context, MmsSentReceiver.class));
+
+ List addresses = new ArrayList<>();
+ for (SMSHelper.Address address : addressList) {
+ addresses.add(address.toString());
+ }
+
+ Message message = new Message(textMessage, addresses.toArray(new String[0]));
+ message.setSave(true);
+
+ // Sending MMS on android requires the app to be set as the default SMS app,
+ // but sending SMS doesn't needs the app to be set as the default app.
+ // This is the reason why there are separate branch handling for SMS and MMS.
+ if (transaction.checkMMS(message)) {
+ if (Utils.isDefaultSmsApp(context)) {
+ if (Utils.isMobileDataEnabled(context)) {
+ com.klinker.android.logger.Log.v("", "Sending new MMS");
+ transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
+ }
+ } else {
+ com.klinker.android.logger.Log.v(SENDING_MESSAGE, "KDE Connect is not set to default SMS app.");
+ //TODO: Notify other end that they need to enable the mobile data in order to send MMS
+ }
+ } else {
+ com.klinker.android.logger.Log.v(SENDING_MESSAGE, "Sending new SMS");
+ transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
+ }
+ //TODO: Notify other end
+ } catch (Exception e) {
+ //TODO: Notify other end
+ com.klinker.android.logger.Log.e(SENDING_MESSAGE, "Exception", e);
+ }
+ }
+}
diff --git a/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsReceiver.java b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsReceiver.java
new file mode 100644
index 00000000..63a97de1
--- /dev/null
+++ b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsReceiver.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 Aniket Kumar
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.kde.kdeconnect.Plugins.SMSPlugin;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.telephony.SmsMessage;
+import android.provider.Telephony.Sms;
+import android.net.Uri;
+import android.content.ContentValues;
+
+import com.klinker.android.send_message.Transaction;
+import com.klinker.android.send_message.Utils;
+
+public class SmsReceiver extends BroadcastReceiver {
+
+ private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!Utils.isDefaultSmsApp(context)) {
+ return;
+ }
+
+ if (intent != null && intent.getAction().equals(SMS_RECEIVED)) {
+ Bundle dataBundle = intent.getExtras();
+
+ if (dataBundle != null) {
+ Object[] smsExtra = (Object[]) dataBundle.get("pdus");
+ final SmsMessage[] message = new SmsMessage[smsExtra.length];
+
+ for (int i = 0; i < smsExtra.length; ++i) {
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ String format = dataBundle.getString("format");
+ message[i] = SmsMessage.createFromPdu((byte[]) smsExtra[i], format);
+ } else {
+ message[i] = SmsMessage.createFromPdu((byte[]) smsExtra[i]);
+ }
+
+ // Write the received sms to the sms provider
+ for (SmsMessage msg : message) {
+ ContentValues values = new ContentValues();
+ values.put(Sms.ADDRESS, msg.getDisplayOriginatingAddress());
+ values.put(Sms.BODY, msg.getMessageBody());
+ values.put(Sms.DATE, System.currentTimeMillis()+"");
+ values.put(Sms.TYPE, Sms.MESSAGE_TYPE_INBOX);
+ values.put(Sms.STATUS, msg.getStatus());
+ values.put(Sms.READ, 0);
+ values.put(Sms.SEEN, 0);
+ context.getApplicationContext().getContentResolver().insert(Uri.parse("content://sms/"), values);
+
+ // Notify messageUpdateReceiver about the arrival of the new sms message
+ Intent refreshIntent = new Intent(Transaction.REFRESH);
+ context.sendBroadcast(refreshIntent);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsSentReceiver.java b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsSentReceiver.java
new file mode 100644
index 00000000..b942ca81
--- /dev/null
+++ b/src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsSentReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020 Aniket Kumar
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.kde.kdeconnect.Plugins.SMSPlugin;
+
+import android.content.Context;
+import android.content.Intent;
+
+import com.klinker.android.send_message.SentReceiver;
+import com.klinker.android.send_message.Transaction;
+import com.klinker.android.send_message.Utils;
+
+public class SmsSentReceiver extends SentReceiver {
+
+ @Override
+ public void updateInInternalDatabase(Context context, Intent intent, int receiverResultCode) {
+ super.updateInInternalDatabase(context, intent, receiverResultCode);
+
+ if (Utils.isDefaultSmsApp(context)) {
+ // Notify messageUpdateReceiver about the successful sending of the sms message
+ Intent refreshIntent = new Intent(Transaction.REFRESH);
+ context.sendBroadcast(refreshIntent);
+ }
+ }
+
+ @Override
+ public void onMessageStatusUpdated(Context context, Intent intent, int receiverResultCode) {
+ }
+}
diff --git a/src/org/kde/kdeconnect/UserInterface/DefaultSmsAppAlertDialogFragment.java b/src/org/kde/kdeconnect/UserInterface/DefaultSmsAppAlertDialogFragment.java
new file mode 100644
index 00000000..77f445d4
--- /dev/null
+++ b/src/org/kde/kdeconnect/UserInterface/DefaultSmsAppAlertDialogFragment.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 Erik Duisters
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.kde.kdeconnect.UserInterface;
+
+import android.app.Activity;
+import android.app.role.RoleManager;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Telephony;
+
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+
+public class DefaultSmsAppAlertDialogFragment extends AlertDialogFragment {
+ private static final String KEY_PERMISSIONS = "Permissions";
+ private static final String KEY_REQUEST_CODE = "RequestCode";
+
+ private String[] permissions;
+ private int requestCode;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Bundle args = getArguments();
+
+ if (args == null) {
+ return;
+ }
+
+ permissions = args.getStringArray(KEY_PERMISSIONS);
+ requestCode = args.getInt(KEY_REQUEST_CODE, 0);
+
+ setCallback(new Callback() {
+ @Override
+ public void onPositiveButtonClicked() {
+ Activity host = requireActivity();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ RoleManager roleManager = host.getSystemService(RoleManager.class);
+
+ if (roleManager.isRoleAvailable(RoleManager.ROLE_SMS)) {
+ if (!roleManager.isRoleHeld(RoleManager.ROLE_SMS)) {
+ Intent roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_SMS);
+ host.startActivityForResult(roleRequestIntent, requestCode);
+ }
+ }
+ } else {
+ Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
+ intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getActivity().getPackageName());
+ host.startActivityForResult(intent, requestCode);
+ }
+
+ ActivityCompat.requestPermissions(requireActivity(), permissions, requestCode);
+ }
+ });
+ }
+
+ public static class Builder extends AlertDialogFragment.AbstractBuilder {
+
+ @Override
+ public Builder getThis() {
+ return this;
+ }
+
+ public Builder setPermissions(String[] permissions) {
+ args.putStringArray(KEY_PERMISSIONS, permissions);
+
+ return getThis();
+ }
+
+ public Builder setRequestCode(int requestCode) {
+ args.putInt(KEY_REQUEST_CODE, requestCode);
+
+ return getThis();
+ }
+
+ @Override
+ protected DefaultSmsAppAlertDialogFragment createFragment() {
+ return new DefaultSmsAppAlertDialogFragment();
+ }
+ }
+}
diff --git a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java
index f4e34c59..b9cf9af3 100644
--- a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java
+++ b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java
@@ -40,14 +40,18 @@ import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
+import com.klinker.android.send_message.Utils;
+
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Plugins.Plugin;
+import org.kde.kdeconnect.Plugins.SMSPlugin.SMSPlugin;
import org.kde.kdeconnect.UserInterface.List.PluginListHeaderItem;
import org.kde.kdeconnect.UserInterface.List.FailedPluginListItem;
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
import org.kde.kdeconnect.UserInterface.List.PluginItem;
+import org.kde.kdeconnect.UserInterface.List.SetDefaultAppPluginListItem;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
@@ -337,6 +341,29 @@ public class DeviceFragment extends Fragment {
dialog.show(getChildFragmentManager(), null);
}
});
+
+ // Add a button to the pluginList for setting KDE Connect as default sms app for allowing it to send mms
+ // for now I'm not able to integrate it with other plugin list, but this needs to be reimplemented in a better way.
+ if (!Utils.isDefaultSmsApp(mActivity)) {
+ for (Plugin p : plugins) {
+ if (p.getPluginKey().equals("SMSPlugin")) {
+ pluginListItems.add(new SetDefaultAppPluginListItem(p, mActivity.getResources().getString(R.string.pref_plugin_telepathy_mms), (action) -> {
+ DialogFragment dialog = new DefaultSmsAppAlertDialogFragment.Builder()
+ .setTitle(R.string.set_default_sms_app_title)
+ .setMessage(R.string.pref_plugin_telepathy_mms_desc)
+ .setPositiveButton(R.string.ok)
+ .setNegativeButton(R.string.cancel)
+ .setPermissions(SMSPlugin.getMmsPermissions())
+ .setRequestCode(MainActivity.RESULT_NEEDS_RELOAD)
+ .create();
+
+ if (dialog != null) {
+ dialog.show(getChildFragmentManager(), null);
+ }
+ }));
+ }
+ }
+ }
}
ListAdapter adapter = new ListAdapter(mActivity, pluginListItems);
diff --git a/src/org/kde/kdeconnect/UserInterface/List/SetDefaultAppPluginListItem.java b/src/org/kde/kdeconnect/UserInterface/List/SetDefaultAppPluginListItem.java
new file mode 100644
index 00000000..10ca8933
--- /dev/null
+++ b/src/org/kde/kdeconnect/UserInterface/List/SetDefaultAppPluginListItem.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 Aniket Kumar
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.kde.kdeconnect.UserInterface.List;
+
+import org.kde.kdeconnect.Plugins.Plugin;
+
+public class SetDefaultAppPluginListItem extends SmallEntryItem {
+
+ public interface Action {
+ void action(Plugin plugin);
+ }
+
+ public SetDefaultAppPluginListItem(Plugin plugin, String displayName, SetDefaultAppPluginListItem.Action action) {
+ super(displayName, (view) -> action.action(plugin));
+ }
+}
\ No newline at end of file