Creating a default viewer / receiver for Android email attachments - android

I'm trying to create a default handler for .p7s/.p7b files in Android.
I figured the best start would be to create a BroadcastReceiver that will capture the intent from the Android email application (or K-9 if that's a need) for opening of certain attachments (filtered by mime type). Specifically I'm trying to handle s/mime email so looking for the "application/x-pkcs7-certificates" and "application/x-pkcs7-certificates" mime types.
Just as a basic test I've been trying something like this:
Manifest.xml
<receiver android:name=".IntentReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/x-pki-signature"/>
</intent-filter>
</receiver>
Class file.
public class IntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "Intent was caught");
//Do something here
}
}
I've tried using the following mimeType filters as well (testing signatures first):
application/pkcs7-signature
application/x-pkcs7-signature
application/keychain_access
I can't seem to get the IntentReceiver class to capture the intent no matter what filtering I use though. Am I going about this the wrong way?

FIXED: I tried to simply use a regular activity and add the mimeType filtering into that and BAM! it worked. Seems there must be a discrepancies with the BroadcastReceiver not supporting this type of VIEW intent.
New manifest:
<activity android:name=".PkixReceiver"
android:label="#string/app_name">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="application/x-pkcs7-signature" />
<data android:mimeType="application/pkcs7-signature" />
<data android:mimeType="application/keychain_access" />
</intent-filter>
</activity>
And now the activity gets fired when the "open" attachment is clicked, success!

I would include all of those MIME types (just use multiple <data> elements).
It may be that the MIME type is not being included in the email, though. I don't know how you are sending the emails, but try sending them to some account where you can examine the full source of the email message. If the MIME types are not included in the message, you are out of luck.
You might also test a link to one of these files in a Web page (where the Web server serves up the MIME type header), to confirm that your basic handling is OK.

Related

Launch Specific App when NFC is discovered

I am using NFC in my app and it is working fine. However I want to make sure that only my app is launched and no other App is there to handle the intent. Following is the code for it in my Manifest file:
<activity android:name="com.mypackage.name.BeamActivity">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
I have another sample app on my phone which is detecting NFC Intent and providing me Intent Chooser. Following is the code for it in Manifest file.
<activity android:name="com.package2.name.NFCStickyNotesActivity" android:label="Sticky Notes" >
<!-- Handle notes detected from outside our application -->
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
I would like my App to be the only app to handle the particular NFC Intent when my App push it across from another device.
I am not sure whether I have to do something specific in the manifest file or in the code. Any help is appreciated.
The reason why you get an intent chooser is that multiple activities are registered for the data type text/plain. This is a rather common case and you should therefore avoid using such generic data types for the NDEF record that should launch your activity. You have two options to overcome this problem:
Use an NFC Forum external type for your NDEF record (this is what ThomasRS already mentioned). With this method you create a custom record type that is meaningful to your application only. You can create such a record (to write it to your tag or to send over Beam) with something like this:
NdefRecord extRecord = NdefRecord.createExternal(
"yourdomain.com", // your domain name
"yourtype", // your type name
textBytes); // payload
You can then register your activity to launch upon this record like this:
<activity ...>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="vnd.android.nfc" android:host="ext"
android:pathPrefix="/yourdomain.com:yourtype" />
</intent-filter>
</activity>
Use an Android Application Record (AAR). An AAR will make sure that the NDEF_DISCOVERED intent is delivered to an app with a specific package name only. You can create such a record (to write it to your tag or to send over Beam) with something like this:
NdefRecord appRecord = NdefRecord.createApplicationRecord(
"com.yourdomain.yourapp");
NdefRecord textRecord = NdefRecord.createTextRecord(
"en", // language code
"yourtext" // human-readable text);
NdefMessage msg = new NdefMessage(
textRecord,
appRecord); // use the AAR as the *last* record in your NDEF message
Use the External Type NDEF record with your own domain and give your app a corresponding intent-filter.

intent-filter for a service : using a custom mime type

I want to add a custom mime so that my Android Service or a BroadcastReceiver would detect my custom files.
I have seen answers to questions like How to add custom mime type? and How to add custom mime type?
The answers here are shown for an Activity. But what modifications are required for service or BroadcastReceiver? I tried the same code for them, but it did not work.
I am new to android development. Some nice and detailed explanation is welcome. Is it possible?
Where am I going wrong.
The code that I used is :
<service android:name="XcardReceivedService"
android:exported="true"
android:enabled="true">
<intent-filter>
<!-- <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
-->
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.Xcard" />
<data android:host="*" />
</intent-filter>
</service>
but before the activity is started I want to add the data from that file to the database
You have to do that in the activity.
or that purpose I wanted to write a service or a broadcast receiver.
Files do not open in to a service or a broadcast receiver.
Is there any other possible way?
Put your code into your activity.
how should i differentiate between "how the activity was started" whether from other activity or when user clicked on this file.
Examine the Intent that was used to start your activity. You get this Intent via getIntent(). You can call getData() on the Intent to get the Uri associated with it. If this is not null, it should be the path to your file.

Android: share CSV file

My aplication can generate CSV files that I want to share. I'm using MIME type text/comma_separated_values/csv, but when I send the Intent the chooser isn't shown, I guess my device doesn't know how to handle the file. Which type should I use?
This is my code:
Uri csv = lh.createDailyCSV();
if(csv == null){
Toast.makeText(this, getString(R.string.error_creating_csv), Toast.LENGTH_LONG).show();
}
else{
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/comma_separated_values/csv");
sharingIntent.setData(csv);
startActivity(Intent.createChooser(sharingIntent, getResources().getText(R.string.send_to)));
}
I declared in my manifest:
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/comma_separated_values/csv" />
</intent-filter>
And I get the exception
03-12 12:19:23.430: E/ActivityThread(24011): Activity com.android.internal.app.ChooserActivity has leaked IntentReceiver com.android.internal.app.ResolverActivity$1#412fc920 that was originally registered here. Are you missing a call to unregisterReceiver()?
I've read this Exception occurs when there is none or just 1 option in the chooser.
[EDIT]
I changed how I attach the data to the Intent. Instead of sharingIntent.setData(csv) I used:
sharingIntent.putExtra(Intent.EXTRA_STREAM, csv);
And now the chooser works fine, but if I try to send the file via e-mail I get an error: File couldn't be shown.
[/EDIT]
The correct MIME type would be text/csv. If that doesn't work, you can use text/plain which will allow the user to potentially choose from a lot of apps, including Evernote etc.
Update After the update, it seems that you don't want to "share" the file with arbitrary other apps but only send it by e-mail? Please clarify.
In my case, the following works in Goo:
intent.setType("text/*");
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
<data android:mimeType="text/*"/>
</intent-filter>

How to add custom mime type?

What I want: To be able to send my custom file by mail and import it with my application from the preview button in GMail or when opening it in a file browser.
What I know: I've read a lot of custom mime type handlers, that android doesn't care about file extension etc., but how to create the mime type for my custom file?
The question: Do I need to be a content provider? I just want to import files (from backup) not provide anything. I've seen people having handlers for "application/abc" saying it's working fine, but how to add that connection for my file "myFile.abc" and the mime type?
Some direction how to register/map custom mime types would be appreciated! :)
As far as I can tell, mime types are pretty flexible (I created mine as application/whatever) and they're accepted immediately by Android, as far back as Dalvik version 2.1. To handle them properly, I added this intent-filter:
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/whatever" />
</intent-filter>
There is a caveat though. Even though I always set the type of the send Intent with intent.setType("application/whatever");, on some phones I've seen the actual data on arrival as application/octet (to see the value, I assigned the incoming Intent and inspected its value directly Intent currentIntent = getIntent();). The receiving Android device didn't know what to do with the incoming data and told me so. So I added
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/octet-stream" />
</intent-filter>
This approach could be troublesome of course, but the problem with Gmail at least is that it doesn't necessarily write the file with the name as it comes in, which renders any Path I choose to define useless. And at least with an incoming octet-stream you know it's not any app's specific data you're stealing away... Still, you should validate the data afterwards and not just assume it's valid for your app.
I have added custom mime type in android contacts list. After a long research i decided to share this with you guys, i have tested this on all Android cell phone including android 9.0.
here is my Github link
Untested, but something like this should work. Put it in your AndroidManifest.xml with the activity you want to open the file:
<activity name=".ActivityHere">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="mimeTypeHere" />
</intent-filter>
</activity>
<activity
android:name="MainActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="{your mime}.com"
android:scheme="http" >
</data>
</intent-filter>
</activity>
<!--
android:scheme="http" will make android "think" thats this is a link
-->
Now, when you receiving a sms with the text "http://{your mime}.com" or clicking link on the web with this text, your activity (MainActivity) will run.
You also can add parameters:
text = "http://{your mime}.com/?number=111";
Then in onCreate() or onResume() methods you'll add:
Intent intentURI = getIntent();
Uri uri = null;
String receivedNum = "";
Log.d("TAG", "intent= "+intentURI);
if (Intent.ACTION_VIEW.equals(intentURI.getAction())) {
if (intentURI!=null){
uri = intentURI.getData();
Log.d("TAG", "uri= "+uri);
}
if (uri!=null)
receivedNum = uri.getQueryParameter("number");
}
Register a custom mime type using android.webkit.MimeTypeMap

Make my activity one of the mail apps shown in the intent chooser

When clicking an email address from a browser or contacts app...
Is there any way for my app to show a mail client in the intent list?
As you can see from the Mail application's source, having your application catch the intent is as simple as adding the intent-filter to your AndroidManifest.xml inside your mail composition activity definition.
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
You can see that the <data> tag specifies to handle mailto: links. The BROWSABLE category means it can be launched from the browser.
K-9 Mail is similar, except using the SENDTO action only with the DEFAULT category, and the VIEW action only with the BROWSABLE category.
You need to use an Intent Filter. Check out http://developer.android.com/guide/topics/intents/intents-filters.html for more information. You usually declare these in your manifest file. The intent I believe you're looking for is Intent.ACTION_SEND.

Categories

Resources