I have do an android application, and now, this application needs to read emails. I found this code:
protected ArrayList<Mail> doInBackground(Void... params) {
ArrayList<Mail> mails = new ArrayList<Mail>(32);
boolean finish = false;
try {
String direcCompleta = URI_PREFIX + email;
Uri a = Uri.parse(direcCompleta);
Cursor cCursor = resolver.query(a, null, null , null, null);
while (cCursor.moveToNext() && (! finish)) {
finish = fromTime.before(new Date(cCursor.getLong(1)));
if (! finish){
String conv_id = cCursor.getString(cCursor.getColumnIndex("_id"));
Uri uri = Uri.parse(URI_PREFIX + email + "/" + conv_id + "/messages");
Cursor mCursor = resolver.query(uri, MESSAGE_PROJECTION, null, null, null);
while (mCursor.moveToNext() && (! finish)){
long mtime = mCursor.getLong(4);
finish = fromTime.before(new Date(mtime));
if (! finish){
mails.add(new Mail(mCursor.getString(0), mCursor.getString(2), mCursor.getString(1), mCursor.getString(4), mtime));
}
}
}
}
} catch (Exception ex){
Log.e("GmailReadApp", ex.toString());
mails.add(new Mail(null, null, ex.toString(), ex.toString(), 0));
}
return mails;
}
But cCursor is null. I have my mail account in app: "Email", because i work with android sdk, and it doesn´t have app: "GMAIL". And android sdk doesn´t have market.
Somebody can help me please? thanks. (no matter if it's for gmail, yahoo, hotmail,....)
I have do an android application, and now, this application needs to read emails
Write your own email client from scratch, then. There is an Android port of JavaMail floating around somewhere. Or, grab an existing open source email client (e.g., K9) and modify it to suit.
I found this code
There is no possible value of URI_PREFIX that is documented and supported for use on Android. Even for the undocumented and unsupported values, you cannot hold the permissions necessary to read those messages.
You can do it with Kotlin.
Download jar files: additionnal.jar, mail.jar, activation.jar
Add those jars in External Libraries in android studio
Add internet permission in manifest file:
<uses-permission android:name="android.permission.INTERNET" />
Enable less secure apps to access your Gmail
Add this code to your app:
GlobalScope.launch {
val props = Properties()
props.setProperty("mail.store.protocol", "imaps")
try{
val session = Session.getInstance(props, null)
val store = session.store
store.connect("imap.gmail.com", "youremail#gmail.com", "password")
val inbox = store.getFolder("INBOX")
inbox.open(Folder.READ_ONLY)
Log.d("MyLog", inbox.messageCount.toString())
val msg = inbox.getMessage(inbox.messageCount)
val address = msg.from
for (adr in address) {
Log.d("MyLog", adr.toString())
}
val mp = msg.content as Multipart
val bp = mp.getBodyPart(0)
Log.d("MyLog", bp.content.toString())
}catch (e: Exception){
Log.d("MyLog", "Error $e")
}
}
Related
According to the Android docs
TV Inputs provided and signed by the device manufacturer (signature
apps) or other apps installed in the system partition will have access
to the entire TV Provider database. This access can be used to
construct apps to browse and search across all available TV channels
and programs.
Assuming I signed as device manufacturer or installed app in system partition, how can I access the TvProvider and thus its channel information?
EDIT:
val tifSupport: Boolean = packageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_TV)
Log.d("XXX", "TIF Support ? $tifSupport")
This line says true. Then I run these lines:
val tvInputManager = applicationContext.getSystemService(TV_INPUT_SERVICE) as TvInputManager?
Log.d("XXX", "TvInputManager $tvInputManager")
val il = tvInputManager?.tvInputList
Log.d("XXX", "TvInputList size --> ${il?.size}")
tvInputManager?.tvInputList?.forEach { info ->
Log.d("XXX", "TvInputListInfo ${info.id} ${info.serviceInfo} # ${info.extras.size()}")
}
First log prints
TvInputManager android.media.tv.TvInputManager#95728c2
so the tvInputManager looks valid. Second shows 0 as the TvInputList size and thus third log (in forEach()) is not printed at all.
You have to start with background for Android. By provider in the doc, they mean ContentProvider, which will share information between process within Android. Now to start with:
If TV Provider supported by our system.
If All the Manifest Permission set to the application
If Application installed under the system apps (and has right SE Policy)
Then you will be able to use ContentProvider to fetch all kind of information you need. To see the full support for TVContent Provider you can refer to this file (ensure it's aligned with your Android OS version) and other AOSP information. For ex.
/**
* Returns the current list of channels your app provides.
*
* #param resolver Application's ContentResolver.
* #return List of channels.
*/
public static List<Channel> getChannels(ContentResolver resolver) {
List<Channel> channels = new ArrayList<>();
// TvProvider returns programs in chronological order by default.
Cursor cursor = null;
try {
cursor = resolver.query(Channels.CONTENT_URI, Channel.PROJECTION, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return channels;
}
while (cursor.moveToNext()) {
channels.add(Channel.fromCursor(cursor));
}
} catch (Exception e) {
Log.w(TAG, "Unable to get channels", e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return channels;
}
Another ex.
TvInputManager tv = (TvInputManager)getApplicationContext().getSystemService(Context.TV_INPUT_SERVICE);
List<TvInputInfo> list = tv.getTvInputList();
String[] projection = {
TvContract.Channels._ID,
TvContract.Channels.COLUMN_DISPLAY_NUMBER
};
ContentResolver cr = getContentResolver();
Iterator<TvInputInfo> it = list.iterator();
while(it.hasNext()) {
TvInputInfo aux = it.next();
Uri uri = TvContract.buildChannelsUriForInput(aux.getId());
Log.d("TAG", uri.toString());
Log.d("TAG", aux.toString());
Cursor cur = cr.query(uri, projection, null, null ,null);
Log.d("TAG", cur.toString());
if(cur.moveToFirst()) {
Log.d("TAG", "not empty cursors");
}
}
UPDATE:
The basic permission you should have(Also refer to the official documentation):
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"/>
I want to delete sms from android inbox when I receive it in my app. I already researched stackoverflow and found the codes but it doesn't work. I am not sure this is because I am using the latest android, gradle and emulator.
private fun deleteSMS(message: String, number: String): Boolean {
try {
Log.d(TAG, "Deleting SMS from inbox")
val uri = Uri.parse("content://sms/inbox")
val c = this.contentResolver.query(uri, null, null, null, null)
c?.let {
if(!it.moveToFirst()) {
it.close()
return false
}
do {
val id = it.getInt(0)
val threadId = it.getInt(1)
val address = it.getString(2)
val body = it.getString(5)
Log.d(TAG, "address, body: $address : $body")
this.contentResolver.delete(Uri.parse("content://sms/$id"), null, null)
}while (it.moveToNext())
}
c?.close()
return true
}catch (e: Exception) {
Log.e(TAG, e.message)
return false
}
}
I tried this code in java but it also doesn't work. Anyone can help me?
Unfortunately, deleting SMS messages like that is no longer possible since Android 4.4 (KitKat), unless your app is the default SMS app or the device is rooted.
Also, the system now allows only the default app to write message data to the provider, although other apps can read at any time.
http://developer.android.com/about/versions/kitkat.html
If you try anyway, it silently fails - it won't delete anything, won't raise any exceptions and won't display error messages.
If you only intend to target 4.4 in your app, then this workaround might help, but it won't work in later versions.
I am trying to make an app that would send a MMS without using the native Android messaging app. I followed the example here. My log statements seem to be correctly printing, but I can't figure out why the MMS is not being sent.
Also on a different note, I am a bit confused about where in the example the attachment (like an image) is being selected to send as MMS. I tried to import the demo into Android Studio but I ran into issues.
My function for sending MMS is below:
public void sendMMS() {
Log.d(TAG, "sendMMS()");
Random random = new Random();
final String fileName = "send." + String.valueOf(Math.abs(random.nextLong())) + ".dat";
final File mSendFile = new File(mContext.getCacheDir(), fileName);
// Making RPC call in non-UI thread
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
#Override
public void run() {
final byte[] pdu = buildPdu();
Uri writerUri = (new Uri.Builder())
.authority("com.example.appname")
.path(fileName)
.scheme(ContentResolver.SCHEME_CONTENT)
.build();
Log.d(TAG, "sendMMS(): Uri: " + writerUri.toString());
FileOutputStream writer = null;
Uri contentUri = null;
try {
writer = new FileOutputStream(mSendFile);
writer.write(pdu);
contentUri = writerUri;
Log.d(TAG, "sendMMS(): just wrote file");
} catch (final IOException e) {
Log.d(TAG, "sendMMS(): FAILED: couldn't write file");
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
}
}
}
if (contentUri != null) {
SmsManager.getDefault().sendMultimediaMessage(mContext, contentUri, null, null, null);
Log.d(TAG, "sendMMS(): just sent");
} else {
Log.d(TAG, "sendMMS(): FAILED: couldn't write file so didn't send");
}
}
});
}
Helper functions
private byte[] buildPdu() {
final SendReq req = new SendReq();
// from
final String lineNumber = getSimNumber();
if (!TextUtils.isEmpty(lineNumber)) {
req.setFrom(new EncodedStringValue(lineNumber));
}
// to
String[] destsArray = mDestList.toArray(new String[mDestList.size()]);
EncodedStringValue[] encodedNumbers = EncodedStringValue.encodeStrings(destsArray);
if (encodedNumbers != null) {
req.setTo(encodedNumbers);
}
// date
req.setDate(System.currentTimeMillis() / 1000);
// body
PduBody body = new PduBody();
// message text
final int size = addMessagePart(body, true/* add text smil */);
req.setBody(body);
// message size
req.setMessageSize(size);
// message class
req.setMessageClass(PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes());
// expiry
req.setExpiry(DEFAULT_EXPIRY_TIME);
try {
// priority
req.setPriority(DEFAULT_PRIORITY);
// delivery report
req.setDeliveryReport(PduHeaders.VALUE_NO);
// read report
req.setReadReport(PduHeaders.VALUE_NO);
} catch (InvalidHeaderValueException e) {}
return new PduComposer(mContext, req).make();
}
private String getSimNumber() {
TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
return telephonyManager.getLine1Number();
}
private int addMessagePart(PduBody pb, boolean addTextSmil) {
PduPart part = new PduPart();
part.setCharset(CharacterSets.UTF_8);
part.setContentType(ContentType.TEXT_PLAIN.getBytes());
part.setContentLocation(TEXT_PART_FILENAME.getBytes());
int index = TEXT_PART_FILENAME.lastIndexOf(".");
String contentId = (index == -1) ? TEXT_PART_FILENAME : TEXT_PART_FILENAME.substring(0, index);
part.setContentId(contentId.getBytes());
part.setData(mMessage.getBytes());
pb.addPart(part);
if (addTextSmil) {
String smil = String.format(sSmilText, TEXT_PART_FILENAME);
addSmilPart(pb, smil);
}
return part.getData().length;
}
private void addSmilPart(PduBody pb, String smil) {
PduPart smilPart = new PduPart();
smilPart.setContentId("smil".getBytes());
smilPart.setContentType(ContentType.APP_SMIL.getBytes());
smilPart.setContentLocation("smil.xml".getBytes());
smilPart.setData(smil.getBytes());
pb.addPart(0, smilPart);
}
Relevant parts of my manifest
<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.READ_PHONE_STATE"/>
Relevant instance variables
private final long DEFAULT_EXPIRY_TIME = 7 * 24 * 60 * 60;
private final String TEXT_PART_FILENAME = "text_0.txt";
private final int DEFAULT_PRIORITY = PduHeaders.PRIORITY_NORMAL;
private String mMessage;
private ArrayList<String> mDestList;
private Context mContext;
private static final String sSmilText =
"<smil>" +
"<head>" +
"<layout>" +
"<root-layout/>" +
"<region height=\"100%%\" id=\"Text\" left=\"0%%\" top=\"0%%\" width=\"100%%\"/>" +
"</layout>" +
"</head>" +
"<body>" +
"<par dur=\"8000ms\">" +
"<text src=\"%s\" region=\"Text\"/>" +
"</par>" +
"</body>" +
"</smil>";
I already do input checks, so by the time sendMMS() is called, my message and destList are not null.
The flow should be as such:
Create the Mms send-request - new SendReq() and config its date, body, to, etc.
Create the Mms body - new PduBody().
Create Parts via new PduPart() for each attachment, and add to the body: body.addPart(pdu)
Add the body to the request - req.setBody(body)
Convert the send-request to a byte[] ready to be sent by calling new PduComposer(context, mySendReq).make() - note that you'll need to copy lots of code from Android's source code to get the PduComposer class.
Now's the interesting part - you save the byte[] to a local file accessible to your app only, and add ContentProvider class that allows other apps to request access to your file, this is MmsFileProvider class in the sample app, don't forget to declare your provider in your manifest file.
Now, when you call the SmsManager.sendMultimediaMessage api, your file provider will wake up to serve the file containing the pdu bytes to the system SmsManager that will read it and send it on the wire.
Having that said, this API is only working for me on some devices (e.g. Nexuses), but not on some others (e.g. HTC One).
See my SO question here:
SmsManager MMS APIs on HTC/LG
I want to design an Android file viewer for Google Drive.
At first, I implemented the app by using of the Google Android API, as follows,
private void retrieveNextPage(){
if(mHasMore == false)
return;
Query query = new Query.Builder().setPageToken(mNextPageToken).build();
com.google.android.gms.drive.Drive.DriveApi.query(getGoogleApiClient(), query).setResultCallback(metadataBufferResultResultCallback);
}
However, the Android Drive API only allows the app to view and fetch the files that created by itself. I cannot access other files on the drive through the app.
Therefore, I turned to another option, directly manipulate the Java Drive API.
According to the example on developer guide for Java,
https://developers.google.com/drive/web/quickstart/quickstart-java
The users have to manually copy and paste the "Authorization Code" between the browser and app, which is not a practical way to acquire the Access Token in Android.
To come out a new way, I used the GoogleAuthUtil in Android API to acquire the Access Token, coincided with the GoogleCredential and Drive in Java API to fetch the file list, as follows,
private static List<File> retrieveFiles(Drive service) throws IOException{
List<File> result = new ArrayList<File>();
Files.List request = service.files().list();
do {
try{
FileList fileList = request.execute();
result.addAll(fileList.getItems());
request.setPageToken(fileList.getNextPageToken());
}catch (IOException e){
Log.d(dbgT + "JavaRetrieveFiles", "Retrieved Failed");
request.setPageToken(null);
}
}while (request.getPageToken() != null && request.getPageToken().length() > 0);
return result;
}
private class RetrieveTokenTask extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params){
String accountName = params[0];
String scopes = "oauth2:" + "https://www.googleapis.com/auth/drive";
String token = null;
try{
token = GoogleAuthUtil.getToken(getApplicationContext(), accountName, scopes);
}
catch (IOException e){
Log.e(excpTAG, "IO Exception: " + e.getMessage());
}
catch (UserRecoverableAuthException e){
startActivityForResult(e.getIntent(), REQ_SIGN_IN_REQUIRED);
}
catch (GoogleAuthException e)
{
Log.e(excpTAG, "GoogleAuthException: " + e.getMessage());
}
return token;
}
#Override
protected void onPostExecute(String s){
super.onPostExecute(s);
//Get Access Token
Log.d( dbgT + "Token", s);
EditText tokenText = (EditText) findViewById(R.id.tokenText);
tokenText.setText(s);
EditText fileNameText = (EditText) findViewById(R.id.editTextMeta);
GoogleCredential credential = new GoogleCredential().setAccessToken(s);
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
Drive service = new Drive.Builder(httpTransport, jsonFactory, null).setHttpRequestInitializer(credential).build();
List<File> fileList;
try{
fileList = retrieveFiles(service);
for(int i=0; i< fileList.size(); i++)
fileNameText.append(fileList.get(i).getTitle());
}catch(IOException e){
Log.d(dbgT + "RetrieveFileList", "IO Exception" );
}
}
}
Unfortunately, the app always crashes by the causing of NetworkOnMainThreadException when request.execute() in retrieveFiles is invoked.
I checked my access token s, it is usually in form of ya29.xxx...etc., and it can also be passed to my other .NET program for retrieving files from Google Drive. Therefore I can certain the access token is correct.
So my question is, how to create a correct GoogleCredential by using of access token, instead of applying authorization code in setFromTokenResponse ?
Thanks in advance.
Many thanks for Andy's tips, this problem is simply caused by the network operations occurs on the main thread, which is a very basic newbie error.
The Drive in Google Drive SDK for Java, using network libraries without any background/thread worker, and now it is functional after I put the retrieveFiles() into background.
Applying the GoogleAuthUtil in Google Play Android SDK to acquire the access token, and followed by GoogleCredential+Drive in Java SDK that use the token to do the file operation in Google Drive.
This is a right way to avoid the scope restriction in Android SDK for Google Drive, allowing the developers to acquire the full permissive of accessing Google Drive.
I am trying to send MMS programatically by using the post How to send image via MMS in Android? ....
I am trying to retrieve the APN values MMSC, MMSProxy and MMSPort , but I am getting empty values for the MMSProxy and MMSPort.. then I checked for these values in my HTC device by navigating "Settings-->Wireless&Networks-->MobileNetworks-->AccessPointNames-->MMS-->"
but here actually nothing is was set for MMSProxy and MMSPort....
but I am able to send MMS manually..
Please help me in how to get MMSProxy and MMSPort values.. or plz tell me if built-in MMS application will use any other mechanism to send MMS..??
plz help me in this...
It might not matter, proxy can mean an "alternate" route. maybe sending MMS doesn't need an alternate route so it's null?
the built in MMS app uses a class called TransactionSettings.java and that class queries the Telephony content provider, code excerpt.
public TransactionSettings(Context context, String apnName) {
String selection = (apnName != null) ? APN + "='" + apnName.trim() + "'" : null;
Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(), Uri.withAppendedPath(Uri.parse(TELEPHONY_CONTENT_URI), "current"),
APN_PROJECTION, selection, null, null);
if (cursor == null) {
Log.e(TAG, "Apn is not found in Database!");
return;
}
boolean sawValidApn = false;
try {
while (cursor.moveToNext() && TextUtils.isEmpty(mServiceCenter)) {
// Read values from APN settings
if (isValidApnType(cursor.getString(COLUMN_TYPE), APN_TYPE_MMS)) {
sawValidApn = true;
mServiceCenter = cursor.getString(COLUMN_MMSC).trim();
mProxyAddress = cursor.getString(COLUMN_MMSPROXY);
if (isProxySet()) {
String portString = cursor.getString(COLUMN_MMSPORT);
try {
mProxyPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
if (TextUtils.isEmpty(portString)) {
Log.w(TAG, "mms port not set!");
} else {
Log.e(TAG, "Bad port number format: " + portString, e);
}
}
}
}
}
} finally {
cursor.close();
}
That being said, I use this method and still get null values.
Maybe you had better luck?