mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 18:07:55 +00:00
Modifying SMSHelper.Message class and PACKET_TYPE_SMS_MESSAGE to contain list of attachment objects.
This commit is contained in:
parent
31dd2cbd5f
commit
f3d683e2c5
@ -26,6 +26,9 @@ import android.content.Context;
|
|||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.media.MediaMetadataRetriever;
|
||||||
|
import android.media.ThumbnailUtils;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@ -46,6 +49,8 @@ import org.apache.commons.lang3.math.NumberUtils;
|
|||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.kde.kdeconnect.Plugins.SMSPlugin.MimeType;
|
||||||
|
import org.kde.kdeconnect.Plugins.SMSPlugin.SmsMmsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -56,7 +61,6 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -71,6 +75,9 @@ import kotlin.text.Charsets;
|
|||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
public class SMSHelper {
|
public class SMSHelper {
|
||||||
|
|
||||||
|
private static final int THUMBNAIL_HEIGHT = 100;
|
||||||
|
private static final int THUMBNAIL_WIDTH = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a URI for querying SMS messages
|
* Get a URI for querying SMS messages
|
||||||
*/
|
*/
|
||||||
@ -86,7 +93,7 @@ public class SMSHelper {
|
|||||||
return Telephony.Mms.CONTENT_URI;
|
return Telephony.Mms.CONTENT_URI;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Uri getMMSPartUri() {
|
public static Uri getMMSPartUri() {
|
||||||
// Android says we should have Telephony.Mms.Part.CONTENT_URI. Alas, we do not.
|
// Android says we should have Telephony.Mms.Part.CONTENT_URI. Alas, we do not.
|
||||||
return Uri.parse("content://mms/part/");
|
return Uri.parse("content://mms/part/");
|
||||||
}
|
}
|
||||||
@ -606,7 +613,8 @@ public class SMSHelper {
|
|||||||
threadID,
|
threadID,
|
||||||
uID,
|
uID,
|
||||||
event,
|
event,
|
||||||
subscriptionID
|
subscriptionID,
|
||||||
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,6 +636,7 @@ public class SMSHelper {
|
|||||||
@NonNull ThreadID threadID = new ThreadID(Long.parseLong(messageInfo.get(Message.THREAD_ID)));
|
@NonNull ThreadID threadID = new ThreadID(Long.parseLong(messageInfo.get(Message.THREAD_ID)));
|
||||||
long uID = Long.parseLong(messageInfo.get(Message.U_ID));
|
long uID = Long.parseLong(messageInfo.get(Message.U_ID));
|
||||||
int subscriptionID = NumberUtils.toInt(messageInfo.get(Message.SUBSCRIPTION_ID));
|
int subscriptionID = NumberUtils.toInt(messageInfo.get(Message.SUBSCRIPTION_ID));
|
||||||
|
List<Attachment> attachments = new ArrayList<>();
|
||||||
|
|
||||||
String[] columns = {
|
String[] columns = {
|
||||||
Telephony.Mms.Part._ID, // The content ID of this part
|
Telephony.Mms.Part._ID, // The content ID of this part
|
||||||
@ -660,7 +669,7 @@ public class SMSHelper {
|
|||||||
long partID = cursor.getLong(partIDColumn);
|
long partID = cursor.getLong(partIDColumn);
|
||||||
String contentType = cursor.getString(contentTypeColumn);
|
String contentType = cursor.getString(contentTypeColumn);
|
||||||
String data = cursor.getString(dataColumn);
|
String data = cursor.getString(dataColumn);
|
||||||
if ("text/plain".equals(contentType)) {
|
if (MimeType.isTypeText(contentType)) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
// data != null means the data is on disk. Go get it.
|
// data != null means the data is on disk. Go get it.
|
||||||
body = getMmsText(context, partID);
|
body = getMmsText(context, partID);
|
||||||
@ -668,10 +677,41 @@ public class SMSHelper {
|
|||||||
body = cursor.getString(textColumn);
|
body = cursor.getString(textColumn);
|
||||||
}
|
}
|
||||||
event = addEventFlag(event, Message.EVENT_TEXT_MESSAGE);
|
event = addEventFlag(event, Message.EVENT_TEXT_MESSAGE);
|
||||||
} //TODO: Parse more content types (photos and other attachments) here
|
} else if (MimeType.isTypeImage(contentType)) {
|
||||||
|
String mimeType = contentType;
|
||||||
|
String fileName = data.substring(data.lastIndexOf('/') + 1);
|
||||||
|
|
||||||
|
// Get the actual image from the mms database convert it into thumbnail and encode to Base64
|
||||||
|
Bitmap image = SmsMmsUtils.getMmsImage(context, partID);
|
||||||
|
Bitmap thumbnailImage = ThumbnailUtils.extractThumbnail(image, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
|
||||||
|
String encodedThumbnail = SmsMmsUtils.bitMapToBase64(thumbnailImage);
|
||||||
|
|
||||||
|
attachments.add(new Attachment(partID, mimeType, encodedThumbnail, fileName));
|
||||||
|
} else if (MimeType.isTypeVideo(contentType)) {
|
||||||
|
String mimeType = contentType;
|
||||||
|
String fileName = data.substring(data.lastIndexOf('/') + 1);
|
||||||
|
|
||||||
|
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||||
|
retriever.setDataSource(context, ContentUris.withAppendedId(getMMSPartUri(), partID));
|
||||||
|
Bitmap videoThumbnail = retriever.getFrameAtTime();
|
||||||
|
|
||||||
|
String encodedThumbnail = SmsMmsUtils.bitMapToBase64(
|
||||||
|
Bitmap.createScaledBitmap(videoThumbnail, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
attachments.add(new Attachment(partID, mimeType, encodedThumbnail, fileName));
|
||||||
|
} else if (MimeType.isTypeAudio(contentType)) {
|
||||||
|
String mimeType = contentType;
|
||||||
|
String fileName = data.substring(data.lastIndexOf('/') + 1);
|
||||||
|
|
||||||
|
attachments.add(new Attachment(partID, mimeType, null, fileName));
|
||||||
|
} else {
|
||||||
|
Log.v("SMSHelper", "Unsupported attachment type: " + contentType);
|
||||||
|
}
|
||||||
} while (cursor.moveToNext());
|
} while (cursor.moveToNext());
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine whether the message was in- our out- bound
|
// Determine whether the message was in- our out- bound
|
||||||
@ -689,7 +729,26 @@ public class SMSHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get address(es) of the message
|
// Get address(es) of the message
|
||||||
List<Address> addresses = getMmsAddresses(context, Long.parseLong(mmsID), userPhoneNumbers);
|
Uri uri = ContentUris.appendId(getMMSUri().buildUpon(), uID).build();
|
||||||
|
Address from = SmsMmsUtils.getMmsFrom(context, uri);
|
||||||
|
|
||||||
|
List<Address> to = SmsMmsUtils.getMmsTo(context, uri);
|
||||||
|
|
||||||
|
List<Address> addresses = new ArrayList<>();
|
||||||
|
if (from != null) {
|
||||||
|
if (!userPhoneNumbers.contains(from.toString()) && !from.toString().equals("insert-address-token")) {
|
||||||
|
addresses.add(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to != null) {
|
||||||
|
for (Address address : to) {
|
||||||
|
if (!userPhoneNumbers.contains(address.toString()) && !address.toString().equals("insert-address-token")) {
|
||||||
|
addresses.add(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// It looks like addresses[0] is always the sender of the message and
|
// It looks like addresses[0] is always the sender of the message and
|
||||||
// following addresses are recipient(s)
|
// following addresses are recipient(s)
|
||||||
// This usually means the addresses list is at least 2 long, but there are cases (special
|
// This usually means the addresses list is at least 2 long, but there are cases (special
|
||||||
@ -713,78 +772,11 @@ public class SMSHelper {
|
|||||||
threadID,
|
threadID,
|
||||||
uID,
|
uID,
|
||||||
event,
|
event,
|
||||||
subscriptionID
|
subscriptionID,
|
||||||
|
attachments
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the address(es) of an MMS message
|
|
||||||
* Original implementation from https://stackoverflow.com/a/6446831/3723163
|
|
||||||
*
|
|
||||||
* The message at the first position of the list should be the sender of the message
|
|
||||||
*
|
|
||||||
* @param messageID ID of this message in the MMS database for looking up the remaining info
|
|
||||||
* @param userPhoneNumbers List of phone numbers which should be removed from the list of addresses
|
|
||||||
*/
|
|
||||||
private static @NonNull List<Address> getMmsAddresses(
|
|
||||||
@NonNull Context context,
|
|
||||||
@NonNull Long messageID,
|
|
||||||
@NonNull List<String> userPhoneNumbers
|
|
||||||
) {
|
|
||||||
Uri uri = ContentUris.appendId(getMMSUri().buildUpon(), messageID).appendPath("addr").build();
|
|
||||||
|
|
||||||
String[] columns = {
|
|
||||||
Telephony.Mms.Addr.MSG_ID, // ID of the message for which we are fetching addresses
|
|
||||||
Telephony.Mms.Addr.ADDRESS, // Address of this part
|
|
||||||
Telephony.Mms.Addr.CHARSET, // Charset of the returned address (where relevant) //TODO: Handle
|
|
||||||
};
|
|
||||||
|
|
||||||
String selection = Telephony.Mms.Addr.MSG_ID + " = ?";
|
|
||||||
String[] selectionArgs = {messageID.toString()};
|
|
||||||
|
|
||||||
// Keep an ordered set rather than a list because Android sometimes throws duplicates at us
|
|
||||||
Set<Address> addresses = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
try (Cursor addrCursor = context.getContentResolver().query(
|
|
||||||
uri,
|
|
||||||
columns,
|
|
||||||
selection,
|
|
||||||
selectionArgs,
|
|
||||||
null
|
|
||||||
)) {
|
|
||||||
if (addrCursor != null && addrCursor.moveToFirst()) {
|
|
||||||
int addressIndex = addrCursor.getColumnIndex(Telephony.Mms.Addr.ADDRESS);
|
|
||||||
|
|
||||||
do {
|
|
||||||
String address = addrCursor.getString(addressIndex);
|
|
||||||
addresses.add(new Address(address));
|
|
||||||
} while (addrCursor.moveToNext());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prune the user's phone numbers from the list of addresses
|
|
||||||
List<Address> prunedAddresses = new ArrayList<>(addresses);
|
|
||||||
prunedAddresses.removeAll(userPhoneNumbers);
|
|
||||||
|
|
||||||
if (prunedAddresses.size() == 0) {
|
|
||||||
// If it turns out that we have pruned away everything, prune away nothing
|
|
||||||
// (The user is allowed to talk to themself)
|
|
||||||
|
|
||||||
// Remove duplicate entries, since the user knows if a conversation says "Me" on it,
|
|
||||||
// it is the conversation with themself. (We don't need to say "Me, Me")
|
|
||||||
// This leaves the multi-sim case alone, so the returned address list might say
|
|
||||||
// "Me1, Me2"
|
|
||||||
|
|
||||||
prunedAddresses = new ArrayList<>(addresses.size()); // The old one was empty too, but just to be clear...
|
|
||||||
for (Address address : addresses) {
|
|
||||||
if (!prunedAddresses.contains(address)) {
|
|
||||||
prunedAddresses.add(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prunedAddresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a text part of an MMS message
|
* Get a text part of an MMS message
|
||||||
* Original implementation from https://stackoverflow.com/a/6446831/3723163
|
* Original implementation from https://stackoverflow.com/a/6446831/3723163
|
||||||
@ -846,6 +838,46 @@ public class SMSHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Attachment {
|
||||||
|
final long partID;
|
||||||
|
final String mimeType;
|
||||||
|
final String base64EncodedFile;
|
||||||
|
final String uniqueIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attachment object field names
|
||||||
|
*/
|
||||||
|
public static final String PART_ID = "part_id";
|
||||||
|
public static final String MIME_TYPE = "mime_type";
|
||||||
|
public static final String ENCODED_THUMBNAIL = "encoded_thumbnail";
|
||||||
|
public static final String UNIQUE_IDENTIFIER = "unique_identifier";
|
||||||
|
|
||||||
|
public Attachment(long partID,
|
||||||
|
String mimeType,
|
||||||
|
@Nullable String base64EncodedFile,
|
||||||
|
String uniqueIdentifier
|
||||||
|
) {
|
||||||
|
this.partID = partID;
|
||||||
|
this.mimeType = mimeType;
|
||||||
|
this.base64EncodedFile = base64EncodedFile;
|
||||||
|
this.uniqueIdentifier = uniqueIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject toJson() throws JSONException {
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
|
json.put(Attachment.PART_ID, this.partID);
|
||||||
|
json.put(Attachment.MIME_TYPE, this.mimeType);
|
||||||
|
|
||||||
|
if (this.base64EncodedFile != null) {
|
||||||
|
json.put(Attachment.ENCODED_THUMBNAIL, this.base64EncodedFile);
|
||||||
|
}
|
||||||
|
json.put(Attachment.UNIQUE_IDENTIFIER, this.uniqueIdentifier);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Address {
|
public static class Address {
|
||||||
final String address;
|
final String address;
|
||||||
|
|
||||||
@ -905,7 +937,6 @@ public class SMSHelper {
|
|||||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||||
String address = jsonObject.getString("address");
|
String address = jsonObject.getString("address");
|
||||||
addresses.add(new Address(address));
|
addresses.add(new Address(address));
|
||||||
Log.e("address", address);
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -951,6 +982,7 @@ public class SMSHelper {
|
|||||||
public final long uID;
|
public final long uID;
|
||||||
public final int event;
|
public final int event;
|
||||||
public final int subscriptionID;
|
public final int subscriptionID;
|
||||||
|
public final List<Attachment> attachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Named constants which are used to construct a Message
|
* Named constants which are used to construct a Message
|
||||||
@ -965,6 +997,7 @@ public class SMSHelper {
|
|||||||
static final String U_ID = Telephony.Sms._ID; // Something which uniquely identifies this message
|
static final String U_ID = Telephony.Sms._ID; // Something which uniquely identifies this message
|
||||||
static final String EVENT = "event";
|
static final String EVENT = "event";
|
||||||
static final String SUBSCRIPTION_ID = Telephony.Sms.SUBSCRIPTION_ID; // An ID which appears to identify a SIM card
|
static final String SUBSCRIPTION_ID = Telephony.Sms.SUBSCRIPTION_ID; // An ID which appears to identify a SIM card
|
||||||
|
static final String ATTACHMENTS = "attachments"; // List of files attached in an MMS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event flags
|
* Event flags
|
||||||
@ -1016,7 +1049,8 @@ public class SMSHelper {
|
|||||||
@NonNull ThreadID threadID,
|
@NonNull ThreadID threadID,
|
||||||
long uID,
|
long uID,
|
||||||
int event,
|
int event,
|
||||||
int subscriptionID
|
int subscriptionID,
|
||||||
|
@Nullable List<Attachment> attachments
|
||||||
) {
|
) {
|
||||||
this.addresses = addresses;
|
this.addresses = addresses;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
@ -1035,6 +1069,7 @@ public class SMSHelper {
|
|||||||
this.uID = uID;
|
this.uID = uID;
|
||||||
this.subscriptionID = subscriptionID;
|
this.subscriptionID = subscriptionID;
|
||||||
this.event = event;
|
this.event = event;
|
||||||
|
this.attachments = attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject toJSONObject() throws JSONException {
|
public JSONObject toJSONObject() throws JSONException {
|
||||||
@ -1055,6 +1090,14 @@ public class SMSHelper {
|
|||||||
json.put(Message.SUBSCRIPTION_ID, subscriptionID);
|
json.put(Message.SUBSCRIPTION_ID, subscriptionID);
|
||||||
json.put(Message.EVENT, event);
|
json.put(Message.EVENT, event);
|
||||||
|
|
||||||
|
if (this.attachments != null) {
|
||||||
|
JSONArray jsonAttachments = new JSONArray();
|
||||||
|
for (Attachment attachment : this.attachments) {
|
||||||
|
jsonAttachments.put(attachment.toJson());
|
||||||
|
}
|
||||||
|
json.put(Message.ATTACHMENTS, jsonAttachments);
|
||||||
|
}
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
src/org/kde/kdeconnect/Plugins/SMSPlugin/MimeType.java
Normal file
42
src/org/kde/kdeconnect/Plugins/SMSPlugin/MimeType.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public final class MimeType {
|
||||||
|
|
||||||
|
public static final String TYPE_TEXT = "text/plain";
|
||||||
|
public static final String TYPE_IMAGE = "image";
|
||||||
|
public static final String TYPE_VIDEO = "video";
|
||||||
|
public static final String TYPE_AUDIO = "audio";
|
||||||
|
|
||||||
|
public static boolean isTypeText(String mimeType) { return mimeType.startsWith(TYPE_TEXT); }
|
||||||
|
|
||||||
|
public static boolean isTypeImage(String mimeType) {
|
||||||
|
return mimeType.startsWith(TYPE_IMAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTypeVideo(String mimeType) { return mimeType.startsWith(TYPE_VIDEO); }
|
||||||
|
|
||||||
|
public static boolean isTypeAudio(String mimeType) { return mimeType.startsWith(TYPE_AUDIO); }
|
||||||
|
|
||||||
|
public static String postfixOf(String mimeType) { return mimeType.substring(mimeType.lastIndexOf('/')+1); }
|
||||||
|
}
|
||||||
|
|
@ -113,6 +113,16 @@ public class SMSPlugin extends Plugin {
|
|||||||
* // If this value is not defined or if it does not match a valid subscriber_id known by
|
* // If this value is not defined or if it does not match a valid subscriber_id known by
|
||||||
* // Android, we will use whatever subscriber ID Android gives us as the default
|
* // Android, we will use whatever subscriber ID Android gives us as the default
|
||||||
*
|
*
|
||||||
|
* "attachments": <List<Attachment>> // List of Attachment objects, one for each attached file in the message.
|
||||||
|
*
|
||||||
|
* An Attachment object looks like:
|
||||||
|
* {
|
||||||
|
* "part_id": <long> // part_id of the attachment used to read the file from MMS database
|
||||||
|
* "mime_type": <int> // contains the mime type of the file (image, video, audio, etc.)
|
||||||
|
* "encoded_thumbnail": <String> // Optional base64-encoded thumbnail preview of the content for types which support it
|
||||||
|
* "unique_identifier": <String> // Unique name of te file
|
||||||
|
* }
|
||||||
|
*
|
||||||
* An Address object looks like:
|
* An Address object looks like:
|
||||||
* {
|
* {
|
||||||
* "address": <String> // Address (phone number, email address, etc.) of this object
|
* "address": <String> // Address (phone number, email address, etc.) of this object
|
||||||
|
@ -26,6 +26,10 @@ import android.content.SharedPreferences;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import com.google.android.mms.pdu_alt.EncodedStringValue;
|
||||||
|
import com.google.android.mms.pdu_alt.MultimediaMessagePdu;
|
||||||
|
import com.google.android.mms.pdu_alt.PduPersister;
|
||||||
|
import com.google.android.mms.pdu_alt.RetrieveConf;
|
||||||
import com.klinker.android.send_message.Message;
|
import com.klinker.android.send_message.Message;
|
||||||
import com.klinker.android.send_message.MmsSentReceiver;
|
import com.klinker.android.send_message.MmsSentReceiver;
|
||||||
import com.klinker.android.send_message.Settings;
|
import com.klinker.android.send_message.Settings;
|
||||||
@ -34,8 +38,11 @@ import com.klinker.android.send_message.Utils;
|
|||||||
|
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.provider.Telephony;
|
import android.provider.Telephony;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
@ -45,6 +52,9 @@ import org.kde.kdeconnect.Helpers.SMSHelper;
|
|||||||
import org.kde.kdeconnect.Helpers.TelephonyHelper;
|
import org.kde.kdeconnect.Helpers.TelephonyHelper;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -129,6 +139,123 @@ public class SmsMmsUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Address of the sender of the MMS message.
|
||||||
|
* @param uri content://mms/msgId/addr
|
||||||
|
* @param context context in which the method is called.
|
||||||
|
* @return sender's Address
|
||||||
|
*/
|
||||||
|
public static SMSHelper.Address getMmsFrom(Context context, Uri uri) {
|
||||||
|
MultimediaMessagePdu msg;
|
||||||
|
|
||||||
|
try {
|
||||||
|
msg = (MultimediaMessagePdu) PduPersister.getPduPersister(context).load(uri);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedStringValue encodedStringValue = msg.getFrom();
|
||||||
|
SMSHelper.Address from = new SMSHelper.Address(encodedStringValue.getString());
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a List of Addresses of all the recipients of a MMS message.
|
||||||
|
* @param uri content://mms/part_id
|
||||||
|
* @param context Context in which the method is called.
|
||||||
|
* @return List of Addresses of all recipients of an MMS message
|
||||||
|
*/
|
||||||
|
public static List<SMSHelper.Address> getMmsTo(Context context, Uri uri) {
|
||||||
|
MultimediaMessagePdu msg;
|
||||||
|
|
||||||
|
try {
|
||||||
|
msg = (MultimediaMessagePdu) PduPersister.getPduPersister(context).load(uri);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder toBuilder = new StringBuilder();
|
||||||
|
EncodedStringValue to[] = msg.getTo();
|
||||||
|
|
||||||
|
if (to != null) {
|
||||||
|
toBuilder.append(EncodedStringValue.concat(to));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg instanceof RetrieveConf) {
|
||||||
|
EncodedStringValue cc[] = ((RetrieveConf) msg).getCc();
|
||||||
|
if (cc != null && cc.length == 0) {
|
||||||
|
toBuilder.append(";");
|
||||||
|
toBuilder.append(EncodedStringValue.concat(cc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String built = toBuilder.toString().replace(";", ", ");
|
||||||
|
if (built.startsWith(", ")) {
|
||||||
|
built = built.substring(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stripDuplicatePhoneNumbers(built);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes duplicate addresses from the string and returns List of Addresses
|
||||||
|
*/
|
||||||
|
public static List<SMSHelper.Address> stripDuplicatePhoneNumbers(String phoneNumbers) {
|
||||||
|
if (phoneNumbers == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String numbers[] = phoneNumbers.split(", ");
|
||||||
|
|
||||||
|
List<SMSHelper.Address> uniqueNumbers = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String number : numbers) {
|
||||||
|
if (!uniqueNumbers.contains(number.trim())) {
|
||||||
|
uniqueNumbers.add(new SMSHelper.Address(number.trim()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueNumbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a given bitmap to an encoded Base64 string for sending to desktop
|
||||||
|
* @param bitmap bitmap to be encoded into string*
|
||||||
|
* @return Returns the Base64 encoded string
|
||||||
|
*/
|
||||||
|
public static String bitMapToBase64(Bitmap bitmap) {
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// The below line is not really compressing to PNG so much as encoding as PNG, since PNG is lossless
|
||||||
|
boolean isCompressed = bitmap.compress(Bitmap.CompressFormat.PNG,100, byteArrayOutputStream);
|
||||||
|
if (isCompressed) {
|
||||||
|
byte[] b = byteArrayOutputStream.toByteArray();
|
||||||
|
String encodedString = Base64.encodeToString(b, Base64.DEFAULT);
|
||||||
|
return encodedString;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the image files attached with an MMS from MMS database
|
||||||
|
* @param context Context in which the method is called
|
||||||
|
* @param id part ID of the image file attached with an MMS message
|
||||||
|
* @return Returns the image as a bitmap
|
||||||
|
*/
|
||||||
|
public static Bitmap getMmsImage(Context context, long id) {
|
||||||
|
Uri partURI = ContentUris.withAppendedId(SMSHelper.getMMSPartUri(), id);
|
||||||
|
Bitmap bitmap = null;
|
||||||
|
|
||||||
|
try (InputStream inputStream = context.getContentResolver().openInputStream(partURI)) {
|
||||||
|
bitmap = BitmapFactory.decodeStream(inputStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e("SmsMmsUtils", "Exception", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks a conversation as read in the database.
|
* Marks a conversation as read in the database.
|
||||||
*
|
*
|
||||||
|
@ -31,7 +31,6 @@ import android.telephony.SmsMessage;
|
|||||||
import android.provider.Telephony.Sms;
|
import android.provider.Telephony.Sms;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.Person;
|
import androidx.core.app.Person;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user