mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 01:51:47 +00:00
Added MMS support to the SMSPlugin using Klinker library.
This commit is contained in:
parent
edbf3ccaab
commit
b119de8e76
@ -22,6 +22,8 @@
|
||||
<!-- <uses-permission android:name="android.permission.BLUETOOTH" /> -->
|
||||
<!-- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
@ -31,9 +33,13 @@
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.READ_CALL_LOG" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.SEND_SMS" />
|
||||
<uses-permission android:name="android.permission.READ_SMS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS" />
|
||||
<uses-permission android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
@ -49,6 +55,67 @@
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:theme="@style/KdeConnectTheme"
|
||||
android:name="org.kde.kdeconnect.MyApplication">
|
||||
<receiver
|
||||
android:name="org.kde.kdeconnect.Plugins.SMSPlugin.SmsReceiver"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BROADCAST_SMS">
|
||||
<intent-filter>
|
||||
<action android:name="android.provider.Telephony.SMS_DELIVER" />
|
||||
</intent-filter>
|
||||
<intent-filter android:priority="999">
|
||||
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="org.kde.kdeconnect.Plugins.SMSPlugin.SmsSentReceiver"
|
||||
android:exported="true"
|
||||
android:taskAffinity="${applicationId}.SMS_SENT" />
|
||||
|
||||
<receiver
|
||||
android:name="com.android.mms.transaction.PushReceiver"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BROADCAST_WAP_PUSH">
|
||||
<intent-filter>
|
||||
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
|
||||
|
||||
<data android:mimeType="application/vnd.wap.mms-message" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="org.kde.kdeconnect.Plugins.SMSPlugin.DelegatingMmsReceivedReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:taskAffinity="com.klinker.android.messaging.MMS_RECEIVED" />
|
||||
|
||||
<receiver
|
||||
android:name="org.kde.kdeconnect.Plugins.SMSPlugin.MmsSentReceiver"
|
||||
android:exported="true"
|
||||
android:enabled="true"
|
||||
android:taskAffinity="com.klinker.android.messaging.MMS_SENT" />
|
||||
|
||||
<service
|
||||
android:name="org.kde.kdeconnect.Plugins.SMSPlugin.HeadlessSmsSendService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:scheme="sms" />
|
||||
<data android:scheme="smsto" />
|
||||
<data android:scheme="mms" />
|
||||
<data android:scheme="mmsto" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="com.android.mms.transaction.TransactionService"
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
|
||||
<service
|
||||
android:name="org.kde.kdeconnect.BackgroundService"
|
||||
android:enabled="true" />
|
||||
@ -69,10 +136,29 @@
|
||||
android:name="org.kde.kdeconnect.UserInterface.MainActivity"
|
||||
android:label="KDE Connect"
|
||||
android:theme="@style/KdeConnectTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<action android:name="android.intent.action.SENDTO" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="sms" />
|
||||
<data android:scheme="smsto" />
|
||||
<data android:scheme="mms" />
|
||||
<data android:scheme="mmsto" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.app.role.SMS"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
|
@ -165,6 +165,8 @@ dependencies {
|
||||
implementation 'org.atteo.classindex:classindex:3.6'
|
||||
annotationProcessor 'org.atteo.classindex:classindex:3.6'
|
||||
|
||||
implementation 'com.klinkerapps:android-smsmms:5.2.6' //For SMS and MMS purposes
|
||||
|
||||
// Testing
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.powermock:powermock-core:2.0.0'
|
||||
|
4
proguard-rules.pro
vendored
4
proguard-rules.pro
vendored
@ -44,3 +44,7 @@
|
||||
-dontwarn android.test.**
|
||||
-dontwarn java.lang.management.**
|
||||
-dontwarn javax.**
|
||||
|
||||
-dontwarn android.net.ConnectivityManager
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||
-dontwarn android.net.LinkProperties
|
||||
|
@ -265,6 +265,8 @@
|
||||
<string name="no_file_browser">There are no file browsers installed.</string>
|
||||
<string name="pref_plugin_telepathy">Send SMS</string>
|
||||
<string name="pref_plugin_telepathy_desc">Send text messages from your desktop</string>
|
||||
<string name="pref_plugin_telepathy_mms">Send MMS</string>
|
||||
<string name="pref_plugin_telepathy_mms_desc">To be able to send MMS from KDE Connect you need to set it as the default SMS app.</string>
|
||||
<string name="findmyphone_title">Find my phone</string>
|
||||
<string name="findmyphone_title_tablet">Find my tablet</string>
|
||||
<string name="findmyphone_title_tv">Find my TV</string>
|
||||
@ -372,6 +374,38 @@
|
||||
<string name="bigscreen_optional_permission_explanation">To share microphone input from your phone you need to give access to the phone\'s audio input</string>
|
||||
<string name="bigscreen_speech_extra_prompt">Speech</string>
|
||||
|
||||
<string name="set_default_sms_app_title">Send MMS</string>
|
||||
<string name="set_group_message_as_mms_title">Send group MMS</string>
|
||||
<string name="set_group_message_as_mms" translatable="false">set_group_message_as_mms</string>
|
||||
<string name="set_long_text_as_mms_title">Send long text as MMS</string>
|
||||
<string name="set_long_text_as_mms" translatable="false">set_long_text_as_mms</string>
|
||||
<string name="convert_to_mms_after_title">Convert to MMS</string>
|
||||
<string name="convert_to_mms_after" translatable="false">convert_to_mms_after</string>
|
||||
<string name="sms_pref_set_mmsc_dialog_desc">Set MMSC</string>
|
||||
<string name="sms_pref_set_mmsc_title">MMSC</string>
|
||||
<string name="sms_pref_set_mmsc" translatable="false">sms_pref_set_mmsc</string>
|
||||
<string name="sms_pref_set_mms_proxy_dialog_desc">Set MMS proxy</string>
|
||||
<string name="sms_pref_set_mms_proxy_title">MMS proxy</string>
|
||||
<string name="sms_pref_set_mms_proxy" translatable="false">sms_pref_set_mms_proxy</string>
|
||||
<string name="sms_pref_set_mms_port_dialog_desc">Set MMS port</string>
|
||||
<string name="sms_pref_set_mms_port_title">MMS port</string>
|
||||
<string name="sms_pref_set_mms_port" translatable="false">sms_pref_set_mms_port</string>
|
||||
<string name="convert_to_mms_after_default" translatable="false">3</string>
|
||||
<string-array name="convert_to_mms_after_entries">
|
||||
<item>After one message</item>
|
||||
<item>After two messages</item>
|
||||
<item>After three messages</item>
|
||||
<item>After four messages</item>
|
||||
<item>After five messages</item>
|
||||
</string-array>
|
||||
<string-array name="convert_to_mms_after_values" translatable="false">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
</string-array>
|
||||
|
||||
<string name="theme_dialog_title">Choose theme</string>
|
||||
<string-array name="theme_list">
|
||||
<item>Set by Battery Saver</item>
|
||||
|
51
res/xml/smsplugin_preferences.xml
Normal file
51
res/xml/smsplugin_preferences.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:keep="@xml/smsplugin_preferences">
|
||||
|
||||
<EditTextPreference
|
||||
android:dialogMessage="@string/sms_pref_set_mmsc_dialog_desc"
|
||||
android:key="@string/sms_pref_set_mmsc"
|
||||
android:title="@string/sms_pref_set_mmsc_title"
|
||||
android:defaultValue="Not set"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<EditTextPreference
|
||||
android:dialogMessage="@string/sms_pref_set_mms_proxy_dialog_desc"
|
||||
android:key="@string/sms_pref_set_mms_proxy"
|
||||
android:title="@string/sms_pref_set_mms_proxy_title"
|
||||
android:defaultValue="Not set"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<EditTextPreference
|
||||
android:dialogMessage="@string/sms_pref_set_mms_port_dialog_desc"
|
||||
android:key="@string/sms_pref_set_mms_port"
|
||||
android:title="@string/sms_pref_set_mms_port_title"
|
||||
android:defaultValue="Not set"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:id="@+id/group_message_preference"
|
||||
android:defaultValue="true"
|
||||
android:key="@string/set_group_message_as_mms"
|
||||
android:title="@string/set_group_message_as_mms_title" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:id="@+id/long_text_message_preference"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/set_long_text_as_mms"
|
||||
android:title="@string/set_long_text_as_mms_title" />
|
||||
|
||||
<ListPreference
|
||||
android:id="@+id/convert_to_mms_after_preference"
|
||||
android:defaultValue="@string/convert_to_mms_after_default"
|
||||
android:entries="@array/convert_to_mms_after_entries"
|
||||
android:entryValues="@array/convert_to_mms_after_values"
|
||||
android:key="@string/convert_to_mms_after"
|
||||
android:summary="%s"
|
||||
android:title="@string/convert_to_mms_after_title" />
|
||||
|
||||
</PreferenceScreen>
|
@ -61,6 +61,8 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.klinker.android.send_message.Utils;
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
public class SMSHelper {
|
||||
|
||||
@ -295,6 +297,13 @@ public class SMSHelper {
|
||||
// of any MMSes
|
||||
List<String> userPhoneNumbers = TelephonyHelper.getAllPhoneNumbers(context);
|
||||
|
||||
if (Utils.isDefaultSmsApp(context)) {
|
||||
// Due to some reason, which I'm not able to find out yet, when message sending fails, no sent receiver
|
||||
// gets invoked to mark the message as failed to send. This is the reason we have to delete the failed
|
||||
// messages pending in the outbox before fetching new messages from the database
|
||||
deleteFailedMessages(uri, context, fetchColumns, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
|
||||
try (Cursor myCursor = context.getContentResolver().query(
|
||||
uri,
|
||||
fetchColumns.toArray(new String[]{}),
|
||||
@ -376,6 +385,83 @@ public class SMSHelper {
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes messages which are failed to send due to some reason
|
||||
*
|
||||
* @param uri Uri indicating the messages database to read
|
||||
* @param context android.content.Context running the request.
|
||||
* @param fetchColumns List of columns to fetch
|
||||
* @param selection Parameterizable filter to use with the ContentResolver query. May be null.
|
||||
* @param selectionArgs Parameters for selection. May be null.
|
||||
* @param sortOrder Sort ordering passed to Android's content resolver. May be null for unspecified
|
||||
*/
|
||||
private static void deleteFailedMessages(
|
||||
@NonNull Uri uri,
|
||||
@NonNull Context context,
|
||||
@NonNull Collection<String> fetchColumns,
|
||||
@Nullable String selection,
|
||||
@Nullable String[] selectionArgs,
|
||||
@Nullable String sortOrder
|
||||
) {
|
||||
try (Cursor myCursor = context.getContentResolver().query(
|
||||
uri,
|
||||
fetchColumns.toArray(new String[]{}),
|
||||
selection,
|
||||
selectionArgs,
|
||||
sortOrder)
|
||||
) {
|
||||
if (myCursor != null && myCursor.moveToFirst()) {
|
||||
do {
|
||||
String id = null;
|
||||
String type = null;
|
||||
String msgBox = null;
|
||||
|
||||
for (int columnIdx = 0; columnIdx < myCursor.getColumnCount(); columnIdx++) {
|
||||
String colName = myCursor.getColumnName(columnIdx);
|
||||
|
||||
if (colName.equals("_id")) {
|
||||
id = myCursor.getString(columnIdx);
|
||||
}
|
||||
|
||||
if(colName.equals("type")) {
|
||||
type = myCursor.getString(columnIdx);
|
||||
}
|
||||
|
||||
if (colName.equals("msg_box")) {
|
||||
msgBox = myCursor.getString(columnIdx);
|
||||
}
|
||||
}
|
||||
|
||||
if (type != null && id != null) {
|
||||
if (type.equals(Telephony.Sms.MESSAGE_TYPE_OUTBOX) || type.equals(Telephony.Sms.MESSAGE_TYPE_FAILED)) {
|
||||
Log.v("Deleting sms", "content://sms/" + id);
|
||||
context.getContentResolver().delete(Uri.parse("content://sms/" + id), null, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (msgBox != null && id != null) {
|
||||
if (msgBox.equals(Telephony.Mms.MESSAGE_BOX_OUTBOX) || msgBox.equals(Telephony.Mms.MESSAGE_BOX_FAILED)) {
|
||||
Log.v("Deleting mms", "content://mms/" + id);
|
||||
context.getContentResolver().delete(Uri.parse("content://mms/" + id), null, null);
|
||||
}
|
||||
}
|
||||
} while (myCursor.moveToNext());
|
||||
}
|
||||
} catch (SQLiteException e) {
|
||||
String[] unfilteredColumns = {};
|
||||
try (Cursor unfilteredColumnsCursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
||||
if (unfilteredColumnsCursor != null) {
|
||||
unfilteredColumns = unfilteredColumnsCursor.getColumnNames();
|
||||
}
|
||||
}
|
||||
if (unfilteredColumns.length == 0) {
|
||||
throw new MessageAccessException(uri, e);
|
||||
} else {
|
||||
throw new MessageAccessException(unfilteredColumns, uri, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets messages which match the selection
|
||||
*
|
||||
@ -818,6 +904,29 @@ public class SMSHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* converts a given JSONArray into List<Address>
|
||||
*/
|
||||
public static List<Address> jsonArrayToAddressList(JSONArray jsonArray) {
|
||||
if (jsonArray == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Address> addresses = new ArrayList<>();
|
||||
try {
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
String address = jsonObject.getString("address");
|
||||
addresses.add(new Address(address));
|
||||
Log.e("address", address);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that some error has occurred while reading a message.
|
||||
* More useful for logging than catching and handling
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.kde.kdeconnect.Plugins.SMSPlugin;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* A small BroadcastReceiver wrapper for MMSReceivedReceiver to load user preferences
|
||||
*/
|
||||
public class DelegatingMmsReceivedReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
MmsReceivedReceiver delegate = new MmsReceivedReceiver();
|
||||
|
||||
delegate.loadFromPreferences(context);
|
||||
delegate.onReceive(context, intent);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.kde.kdeconnect.Plugins.SMSPlugin;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.app.Service;
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
* Service for sending messages to a conversation without a UI present. These messages could come
|
||||
* from something like Phone, needed to make default sms app
|
||||
*/
|
||||
public class HeadlessSmsSendService extends Service {
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.kde.kdeconnect.Plugins.SMSPlugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.klinker.android.send_message.Transaction;
|
||||
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
/**
|
||||
* Receiver for notifying user when a new MMS has been received by the device. By default it will
|
||||
* persist the message to the internal database and notification service to notify the users will be
|
||||
* implemented later.
|
||||
*/
|
||||
public class MmsReceivedReceiver extends com.klinker.android.send_message.MmsReceivedReceiver {
|
||||
|
||||
private String mmscUrl = null;
|
||||
private String mmsProxy = null;
|
||||
private String mmsPort = null;
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(Context context, Uri messageUri) {
|
||||
Log.v("MmsReceived", "message received: " + messageUri.toString());
|
||||
|
||||
// Notify messageUpdateReceiver about the arrival of the new MMS message
|
||||
Intent refreshIntent = new Intent(Transaction.REFRESH);
|
||||
context.sendBroadcast(refreshIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context context, String error) {
|
||||
Log.v("MmsReceived", "error: " + error);
|
||||
}
|
||||
|
||||
public void loadFromPreferences(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
mmscUrl = prefs.getString(context.getString(R.string.sms_pref_set_mmsc), "");
|
||||
mmsProxy = prefs.getString(context.getString(R.string.sms_pref_set_mms_proxy), "");
|
||||
mmsPort = prefs.getString(context.getString(R.string.sms_pref_set_mms_port), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* some carriers will download duplicate MMS messages without this ACK. When using the
|
||||
* system sending method, apparently Android does not do this for us. Not sure why.
|
||||
* We might have to have users manually enter their APN settings if we cannot get them
|
||||
* from the system somehow.
|
||||
*/
|
||||
@Override
|
||||
public MmscInformation getMmscInfoForReceptionAck() {
|
||||
|
||||
if (mmscUrl != null || mmsProxy != null || mmsPort != null) {
|
||||
try {
|
||||
return new MmscInformation(mmscUrl, mmsProxy, Integer.parseInt(mmsPort));
|
||||
} catch (Exception e) {
|
||||
Log.e("MmsReceivedReceiver", "Exception", e);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
@ -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 {
|
||||
* <p>
|
||||
* 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": <List of 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<SMSHelper.Address> 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
|
||||
|
121
src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsMmsUtils.java
Normal file
121
src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsMmsUtils.java
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<SMSHelper.Address> 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<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
82
src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsReceiver.java
Normal file
82
src/org/kde/kdeconnect/Plugins/SMSPlugin/SmsReceiver.java
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2019 Erik Duisters <e.duisters1@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<DefaultSmsAppAlertDialogFragment.Builder, DefaultSmsAppAlertDialogFragment> {
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user