I want to send MMS from my application to a specific number. I've searched and found this code but I have no idea if this code what I need or not.
My Questions is :
-can anyone explain this code to me.i am beginner in MMS.
-also, i thought this code is let the user send MMS from my application without move it to the native Messaging inbox (and this is what i want) Am i right?
-also i have a problem ,i do not know how can i put this code in my project.
this is what i found
MMS is just a http-post request. You should perform the request using extra network feature :
final ConnectivityManager connMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
final int result = connMgr.startUsingNetworkFeature( ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_MMS);
If you get back the result with Phone.APN_REQUEST_STARTED value, you have to wait for proper state. Register BroadCastReciver and wait until Phone.APN_ALREADY_ACTIVE appears:
final IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(reciver, filter);
If background connection is ready, then build content and perform request. If you want to do that using android's internal code, please use this:
final SendReq sendRequest = new SendReq();
final EncodedStringValue[] sub = EncodedStringValue.extract(subject);
if (sub != null && sub.length > 0) {
sendRequest.setSubject(sub[0]);
}
final EncodedStringValue[] phoneNumbers = EncodedStringValue.extract(recipient);
if (phoneNumbers != null && phoneNumbers.length > 0) {
sendRequest.addTo(phoneNumbers[0]);
}
final PduBody pduBody = new PduBody();
if (parts != null) {
for (MMSPart part : parts) {
final PduPart partPdu = new PduPart();
partPdu.setName(part.Name.getBytes());
partPdu.setContentType(part.MimeType.getBytes());
partPdu.setData(part.Data);
pduBody.addPart(partPdu);
}
}
sendRequest.setBody(pduBody);
final PduComposer composer = new PduComposer(this.context, sendRequest);
final byte[] bytesToSend = composer.make();
HttpUtils.httpConnection(context, 4444L, MMSCenterUrl, bytesToSendFromPDU, HttpUtils.HTTP_POST_METHOD, !TextUtils.isEmpty(MMSProxy), MMSProxy, port);
MMSCenterUrl: url from MMS-APNs,
MMSProxy: proxy from MMS-APNs,
port: port from MMS-APNs
Note that some classes are from internal packages. Download from android git is required.
The request should be done with url from user's apn-space code:
public class APNHelper {
public class APN {
public String MMSCenterUrl = "";
public String MMSPort = "";
public String MMSProxy = "";
}
public APNHelper(final Context context) {
this.context = context;
}
public List<APN> getMMSApns() {
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"), null, null, null, null);
if ( apnCursor == null ) {
return Collections.EMPTY_LIST;
} else {
final List<APN> results = new ArrayList<APN>();
while ( apnCursor.moveToNext() ) {
final String type = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.TYPE));
if ( !TextUtils.isEmpty(type) && ( type.equalsIgnoreCase(Phone.APN_TYPE_ALL) || type.equalsIgnoreCase(Phone.APN_TYPE_MMS) ) ) {
final String mmsc = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSC));
final String mmsProxy = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSPROXY));
final String port = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSPORT));
final APN apn = new APN();
apn.MMSCenterUrl = mmsc;
apn.MMSProxy = mmsProxy;
apn.MMSPort = port;
results.add(apn);
}
}
apnCursor.close();
return results;
}
Please help me
why don't you use the android system functions:
Please have a look on
https://developer.android.com/guide/components/intents-common.html
public void composeMmsMessage(String message, Uri attachment) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setData(Uri.parse("smsto:")); // This ensures only SMS apps respond
intent.putExtra("sms_body", message);
intent.putExtra(Intent.EXTRA_STREAM, attachment);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent); }
}
Cheers
Tom
I found a link in an other thread to a github project that works 100% https://github.com/klinker41/android-smsmms
Notice, that obligatory settings are only
Settings sendSettings = new Settings();
sendSettings.setMmsc(mmsc);
sendSettings.setProxy(proxy);
sendSettings.setPort(port);
you can get them something like (found at Set APN programmatically on Android - answear by vincent091):
Cursor cursor = null;
if (Utils.hasICS()){
cursor =SqliteWrapper.query(activity, activity.getContentResolver(),
Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), APN_PROJECTION, null, null, null);
} else {
cursor = activity.getContentResolver().query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"),
null, null, null, null);
}
cursor.moveToLast();
String type = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.TYPE));
String mmsc = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.MMSC));
String proxy = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.MMSPROXY));
String port = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.MMSPORT));
Related
I found out a message sent via AnswerInlineQuery can be edited by EditMessageText() in "supergroup" chats only.
The created group by default has the "group" type, but after changing any settings, it changes to "supergroup" (I read this from the documentation).
Next, I changed the chat where I couldn't edit the message sent via AnswerInlineQuery to "supergroup" and it worked. There is no information about the group type in the telegram client itself.
Also, the message sent via AnswerInlineQuery to the "private" type chat is not editable too. Haven't tried channels.
And messages sent via SendMessage() are edited without problems in any chat type, the main thing is to catch the messageID.
Is it library limitation, or it's not possible for API in common?
private final TelegramBot bot = new TelegramBot(System.getenv("TG_BOT_TOKEN"));
long chatID;
int messageID;
public void listen() {
this.bot.setUpdatesListener(updates -> {
updates.forEach(this::process);
return UpdatesListener.CONFIRMED_UPDATES_ALL;
});
}
#SuppressWarnings("unchecked")
private void process(Update update) {
Message message = update.message();
InlineQuery inlineQuery = update.inlineQuery();
BaseRequest request = null;
if (message != null && message.viaBot() != null) {
chatID = message.chat().id();
messageID = message.messageId();
request = new EditMessageText(chatID, messageID, String.valueOf(update.message().messageId()));
}
if (inlineQuery != null) request = new AnswerInlineQuery(inlineQuery.id(), new InlineQueryResultArticle("id", "title", "text"));
if (request != null) bot.execute(request);
}
}```
I know this is a big topic, as seen here and here, so I just wanted to post how I solved both the issue of receiving incoming MMS and SMS messages and the issue of grabbing data from those MMS and SMS messages on Android 9.0 version 28+ using Xamarin.Forms. This code can easily be translated to Java. Here is the completed Android app so you can try it yourself. It also shows how to do some Azure machine learning if you're interested in that.
For Broadcast Receivers:
Classes, registering class instances , permissions needed.
Note that the broadcast receivers were added dynamically, they can be added statically using Xamarin's intent-filter decorator , or (if you're not using Xamarin) the AndroidManifest.xml file.
Here is a code snippet to show how to parse incoming SMS data with a Broadcast Receiver:
public override void OnReceive(Context context, Intent intent)
{
Log.Info(TAG, "Intent action received: " + intent.Action);
// Retrieve message from the intent and analyze it.
SmsMessage msg = Android.Provider.Telephony.Sms.Intents.GetMessagesFromIntent(intent)[0];
string message = msg.DisplayMessageBody;
(string, bool) result = MMSReceiver.CleanUpMessage(message);
// If there were one or more rooster words.
if (result.Item2)
{
string title = "Rooster Text Received From: " + msg.DisplayOriginatingAddress;
DependencyService.Get<INotificationManager>().ScheduleNotification(title, result.Item1);
}
}
And here is a code snippet to show how to parse incoming MMS data with a Broadcast Receiver:
public override void OnReceive(Context context, Intent intent)
{
Log.Info(TAG, "Intent action received: " + intent.Action);
// Get the MMS ID. Adapted from: https://stackoverflow.com/questions/10065249/how-to-get-mms-id-android-application
ContentResolver contentResolver = AndroidApp.Context.ContentResolver;
Android.Net.Uri mmsInboxUri = Android.Net.Uri.Parse("content://mms");
Android.Database.ICursor mmsInboxCursor = contentResolver.Query(mmsInboxUri, new string[]
{"_id","msg_box","ct_t","date"}, "msg_box=1 or msg_box=2", null, null);
int id = -1;
if (mmsInboxCursor != null)
{
try
{
if (mmsInboxCursor.MoveToFirst())
{
id = Int32.Parse(mmsInboxCursor.GetString(0));
Log.Info(TAG, "Id is this: " + mmsInboxCursor.GetString(0));
}
}
catch (System.Exception error)
{
Log.Error(TAG, "Error requesting the MMS ID: " + error.Message);
}
}// if (mmsInboxCursor != null)
// Get text and picture from MMS message. Adapted from: https://stackoverflow.com/questions/3012287/how-to-read-mms-data-in-android
string message = ""; // text
Android.Graphics.Bitmap bitmap = null; // picture
string selectionPart = "mid=" + id;
Android.Net.Uri mmsTextUri = Android.Net.Uri.Parse("content://mms/part");
Android.Database.ICursor cursor = contentResolver.Query(mmsTextUri, null,
selectionPart, null, null);
if (cursor.MoveToFirst())
{
do
{
string partId = cursor.GetString(cursor.GetColumnIndex("_id"));
string type = cursor.GetString(cursor.GetColumnIndex("ct"));
// Get text.
if ("text/plain".Equals(type))
{
string data = cursor.GetString(cursor.GetColumnIndex("_data"));
if (data != null)
{
message = GetMmsText(partId);
Log.Info(TAG, "Body is this: " + message);
}
else
{
message = cursor.GetString(cursor.GetColumnIndex("text"));
Log.Info(TAG, "Body is this: " + message);
}
}
//Get picture.
if ("image/jpeg".Equals(type) || "image/bmp".Equals(type) ||
"image/gif".Equals(type) || "image/jpg".Equals(type) ||
"image/png".Equals(type))
{
bitmap = GetMmsImage(partId);
}
} while (cursor.MoveToNext());
}// if (cursor.MoveToFirst())
}
When I try to send a message using Microsoft Graph Java API, It's state is Draft.
Authentication.initialize(appId);
final String accessToken = Authentication.getUserAccessToken(appScopes);
authProvider = new SimpleAuthProvider(accessToken);
// Create default logger to only log errors
DefaultLogger logger = new DefaultLogger();
logger.setLoggingLevel(LoggerLevel.DEBUG);
// Build a Graph client
graphClient = GraphServiceClient.builder()
.authenticationProvider(authProvider)
.logger(logger)
.buildClient();
IMailFolderDeltaCollectionPage mailFolderCollectionPage = graphClient.me().mailFolders().delta()
.buildRequest().get();
AtomicReference<String> inBoxFolderId = new AtomicReference<>("");
while (mailFolderCollectionPage.getNextPage() != null) {
List<MailFolder> mailFolders = mailFolderCollectionPage.getCurrentPage();
mailFolders.forEach(m -> {
if (m.displayName.equals("Inbox")) {
inBoxFolderId.set(m.id);
}
});
mailFolderCollectionPage = mailFolderCollectionPage.getNextPage().buildRequest().get();
}
IMessageDeltaCollectionPage messageCollectionPage = graphClient.me().mailFolders("Inbox")
.messages().delta().buildRequest().get();
Message backedMessaged = null;
while (messageCollectionPage.getNextPage() != null) {
System.out.println("messageCollectionPage = " + messageCollectionPage);
List<Message> messageList = messageCollectionPage.getCurrentPage();
backedMessaged = messageList.get(0);
break;
}
graphClient.me().mailFolders("Inbox").messages().buildRequest().post(backedMessaged);
When you create an Outlook message, its state will remain as draft until you send it. You should use the send request to send your message. It will then not be marked as draft anymore.
Look here for more informations : https://learn.microsoft.com/fr-fr/graph/api/message-send?view=graph-rest-1.0&tabs=http
I have webapp in Vaadin Framework 8. I have Windows GUI app in C#.
The gui app is using WebBrowser component to display webapp. WebBrowser component is internally using IE11 core through ActiveX. I can successfully load and display the webapp in the gui app browser component.
I need to pass data from webapp to the gui app.
The webapp has many rows loaded on server side, only few are displayed in grid. I want to pass all data from webapp to gui app in some format (csv or json).
I have tryed some approaches, but I wasn't successfull.
[Approach 1]
Webapp: attach downloadable resource (csv) to Link with predefined id using FileDownloader. Download by user mouse click works fine, file save dialog pops up and data are downloaded successfully.
Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
FileDownloader downloader = new FileDownloader(resource);
downloader.extend(link);
Page.getCurrent().getJavaScript().addFunction("test", new JavaScriptFunction() {
#Override
public void call(JsonArray arguments) {
Page.getCurrent().getJavaScript()
.execute("document.getElementById('myId').click()");
}
});
Gui app: raise onClick event on link and capture WebBrowser.FileDownload event, capture WebBrowser.Navigate event.
I have failed to raise onClick event from C# using:
HtmlElement el = webBrowser.Document.GetElementById("myId");
el.RaiseEvent("onClick");
el.InvokeMember("click");
webBrowser.Document.InvokeScript("document.getElementById('myId').click();", null);
webBrowser.Document.InvokeScript("test", null);
Result:
WebBrowser.FileDownload event doesn't work (is fired but can't capture url nor data), capture WebBrowser.Navigate event works partialy (can see resource url, but can't download data using byte[] b = new WebClient().DownloadData(e.Url);).
[Approach 2]
Similar to approach 1. I tryed to get resource url, put the direct url to Link and download the resource in c# using direct link. I can construct the same resource url as is used by browser to download data when user clicks the link.
Extended file downloader that keeps resource, key and connector:
public class ExtendedFileDownloader extends FileDownloader {
private String myKey;
private Resource myResource;
private ClientConnector myConnector;
public ExtendedFileDownloader(StreamResource resource, ClientConnector connector) {
super(resource);
myConnector = connector;
}
#Override
protected void setResource(String key, Resource resource) {
super.setResource(key, resource);
myKey = key;
myResource = resource;
}
public String getResourceUrl() {
ResourceReference ref =
ResourceReference.create(
myResource,
(myConnector != null) ? myConnector : this,
myKey);
String url = ref.getURL();
return url;
}
}
In view:
// fix app://path... urls to /<base-path>/path urls
private String fixResourceReferenceUrl(String resourceReferenceUrl) {
String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
String uiBaseUrl = ui.getUiRootPath();
String fixedUrl = uiBaseUrl + "/" + resourceReferencePath;
return fixedUrl;
}
Link link2 = new Link("Data2");
link2.setId("myId2");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource, this);
String fixedResourceUrl = fixResourceReferenceUrl(downloader.getResourceUrl());
link2.setResource(new ExternalResource(fixedResourceUrl));
Result:
The data cannot be downloaded using this link, server error 410 or NotFound errors.
Any Ideas ? Any other approaches to try ?
I have finally solved the problem. The solution is very close to approach 2.
The resource url is passed in element with custom attribute. C# WebClient needs to set cookies from WebBrowser and Referer HTTP headers. The data can be successfully downloaded by C# app.
Element attribute in vaadin webapp can be set using Vaadin-addon Attributes.
Cookies in C# app can be retrieved using this solution.
// Fix resource urls begining with app://
public String fixResourceReferenceUrl(String resourceReferenceUrl) {
try {
String uiRootPath = UI.getCurrent().getUiRootPath();
URI location = Page.getCurrent().getLocation();
String appLocation = new URIBuilder()
.setScheme(location.getScheme())
.setHost(location.getHost())
.setPort(location.getPort())
.setPath(uiRootPath)
.build()
.toString();
String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
String fixedUrl = appLocation + "/" + resourceReferencePath;
return fixedUrl;
}
catch (Exception e) {
return null;
}
}
In view (using ExtendedFileDownloader from above):
Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource);
downloader.extend(link);
Attribute attr = new Attribute("x-my-data", fixResourceReferenceUrl(downloader.getResourceUrl()));
attr.extend(link);
link.setVisible(true);
In C# app:
[DllImport("wininet.dll", SetLastError = true)]
public static extern bool InternetGetCookieEx(
string url,
string cookieName,
StringBuilder cookieData,
ref int size,
Int32 dwFlags,
IntPtr lpReserved);
private const Int32 InternetCookieHttponly = 0x2000;
public static String GetUriCookies(String uri)
{
// Determine the size of the cookie
int datasize = 8192 * 16;
StringBuilder cookieData = new StringBuilder(datasize);
if (!InternetGetCookieEx(uri, null, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
{
if (datasize < 0)
return null;
// Allocate stringbuilder large enough to hold the cookie
cookieData = new StringBuilder(datasize);
if (!InternetGetCookieEx(
uri,
null, cookieData,
ref datasize,
InternetCookieHttponly,
IntPtr.Zero))
return null;
}
return cookieData.ToString();
}
private void button_Click(object sender, EventArgs e)
{
HtmlElement el = webBrowser.Document.GetElementById("myId");
String url = el.GetAttribute("x-my-data");
String cookies = GetUriCookies(url);
WebClient wc = new WebClient();
wc.Headers.Add("Cookie", cookies);
wc.Headers.Add("Referer", WEB_APP_URL); // url of webapp base path, http://myhost/MyUI
byte[] data = wc.DownloadData(url);
}
Is it possible to delete all the alarms with state (INSUFFICIENT_DATA or any other) using AWS SDK java ?
I donot see any methods here.
AmazonCloudWatch cloudWatch = getAmazonCloudwatchClient();
DeleteAlarmsRequest request = new DeleteAlarmsRequest();
Use DeleteAlarms():
public DeleteAlarmsResult deleteAlarms(DeleteAlarmsRequest request)
I have come up with this approach and it helps me.
AmazonCloudWatch cloudWatch = getAmazonCloudwatchClient();
List<MetricAlarm> alarmsList = new ArrayList<>();
do {
DescribeAlarmsResult result = describeAlarms(cloudWatch, nextToken);
nextToken = result.getNextToken();
alarmsList.addAll(result.getMetricAlarms());
}
while (nextToken != null);
for(MetricAlarm alarm : alarmsList){
DeleteAlarmsRequest request = new DeleteAlarmsRequest();
request.withAlarmNames(alarm.getAlarmName());
cloudWatch.deleteAlarms(request);
}
private static DescribeAlarmsResult describeAlarms(AmazonCloudWatch cloudWatch, String nextToken){
DescribeAlarmsRequest request = new DescribeAlarmsRequest();
request.withStateValue("INSUFFICIENT_DATA");
request.withNextToken(nextToken);
return cloudWatch.describeAlarms(request);
}