making NFC Activity private without android:exported=false - android

I have an NFC activity which specifies an intent filter and data. This is something like
<intent-filter>
<action android:name="android.nfc.action..." />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="..."
android:path="..." />
</intent-filter>
Now the concern here is that since I have not included android:exported="false". it makes this activity susceptible to malicious attack from outside apps as the activity is now publicly available. The problem here is that if I put the exported attribute as false, I am not able to get the activity called from the outside intent (which is supposed to trigger the activity via onNewIntent() )
Is there a way to make the activity "safe" while not affecting its general triggering mechanism i.e. via outside intent?

If you need to get notified about tags, you need the intent filter. The tag dispatcher uses this to find interested activities to consider when a tag is scanned. If you make your activity private, there will be no way of notifying it, as you have seen. What 'malicious attacks' are you concerned about? Your activity is as safe as you code it to be: if you only handle NFC intents, you will be 'safe' (unless of course the NFC payload triggers a device-wiping code or something...)

Related

Intent filter with navigation component to Receiving image data from other app

My Android application uses the navigation component to navigate between fragments.
And the project only has a single Activity and all the others are fragments.
My application is a social media application. I want to share an image from my phone gallery with my application. When a user clicks the share button on the gallery, my application wants to show in the sharing dialogue.
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
I have used this intent filter on my main activity, and then the share dialogue displays my app.
But my requirement is, I want to get that image on my fragment. How to use this intent filter on my fragment.
Can I use the deep-link for that? but what value will give on the uri section?.
<deepLink
app:uri="android.intent.category.DEFAULT"
app:action="android.intent.action.SEND"
app:mimeType="image/*"
/>
I tried this. but not working.
In short, I want to receive the data (image) in my fragment. How can I achieve this using the Navigation component?
To explain why it's not working for you, let's examine this piece of code,
app:uri="android.intent.category.DEFAULT"
app:action="android.intent.action.SEND"
app:mimeType="image/*"/>
app:uri attribute requires a scheme and a host e.g., https://example.com (it could be any made up uri like myapp://example.com) , but you are passing a category string to it.
To fix this, just pass "myapp://example.com" or any made up uri you can think of. That will work. Now, the important bit - you must add deeplink tag to the fragment which receives the image. Now, your code will work, however, if your application is already running, it will not receive the image from shared intent. For that, you need to override onNewIntent method in you activity and call NavController.handleDeepLink(intent), you have to pass the intent received in onNewIntent method to it, followed by a call to super.onNewIntent(). Now, your app can receive image from any application that can share it, whether your application is already running, or started by the intent itself.

Lollipop: making my activity stay in the task that launched the share intent

“My First App” has an activity that handles a “share” intent. Its activity in AndroidManifest.xml looks like this:
<activity
android:name="com.example.foo.myfirstapp.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/jpeg"/>
</intent-filter>
</activity>
In KitKat, sharing an image from the album to “My First App” causes MainActivity to be part of the album’s task. This is the desired behavior.
In Lollipop, sharing an image from the album to “My First App” causes a new instance of “My First App” to be launched. If I look at the overview screen, the album task is there...and then there's a separate entry for "My First App". If I share another image, I wind up with two instances of "My First App"...etc.
Question: How do I make Lollipop process the share intent in the same way as KitKat?
Here's what I've done:
I notice that the intents sent from the Album have different flags set depending on the OS. (I got these using getIntent() and looking at mFlags.)
Kitkat: 0x80001 (524289): FLAG_GRANT_READ_URI_PERMISSION, FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
Lollipop: 0x18080001 (403177473): FLAG_GRANT_READ_URI_PERMISSION, FLAG_ACTIVITY_MULTIPLE_TASK, FLAG_ACTIVITY_NEW_DOCUMENT, FLAG_ACTIVITY_NEW_TASK
From reading http://developer.android.com/reference/android/content/Intent.html, it seems that these last three flags are causing the problem. Specifically
When paired with FLAG_ACTIVITY_MULTIPLE_TASK both of these behaviors (FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK) are modified to skip the search for a matching task and unconditionally start a new task.
I’ve been attempting to “override” these flags by specifying android:launchMode and android:documentLaunchMode in the activity in AndroidManifest.xml without success.
From http://developer.android.com/reference/android/R.attr.html#documentLaunchMode, using documentLaunchMode “never” seems promising, since
This activity will not be launched into a new document even if the Intent contains Intent.FLAG_ACTIVITY_NEW_DOCUMENT. This gives the activity writer ultimate control over how their activity is used.
but this didn't work.
I also considered android:taskAffinity, but there doesn’t seem to be a way to say “please prefer whatever task launched you”.
Afraid you can't do anything about this. It isn't under your control. This is a change in the way the "Album" app is launching its "share" Intent. If it doesn't want your Activity in its task, you can't force it in there.
If you have issues with having multiple instances of your "share" activity, you could declare your "share" activity as launchMode="singleTask" or launchMode="singleInstance" (depending on your needs. This may, however, break other things.

interrupting link to my app

I have a problem. I'm using the below code to interrupt links to my app as
<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="http" android:host="twitter.com"/>
<data android:scheme="http" android:host="facebook.com"/>
</intent-filter>
But the problem is that I need to set data scheme and host at runtime i.e. I can add or delete the host at runtime. How to set the value of data scheme and host at runtime? I am using below code but it is not working
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.VIEW");
filter.addCategory("android.intent.category.DEFAULT");
filter.addCategory("android.intent.category.BROWSABLE");
filter.addDataScheme("http");
filter.addDataAuthority("www.facebook.com", null);
RecieveBroadcaster receiver = new RecieveBroadcaster();
registerReceiver(receiver, filter);
Strictly speaking, the string corresponding to ACTION_VIEW is an activity action by convention; the fact that you place it into the intent-filter element of an activity in your manifest, makes it an activity action! The system listens for these on your application's behalf, which is basically why you don't (can't) listen for them yourself. The Context.startActivity() method generates these Intents.
The rules of intent resolution actually determine whether a particular Intent matches any IntentFilters. For activity intents, there may be multiple matches, and that usually displays the "Chooser" interface, so the user can select a target.
There are three Intent "streams" that never cross: startActivity(), sendBroadcast() and startService(). These are all initiated via methods in Context and each has a specific target Activity, BroadcastReceiver and Service respectively.
It is a simple matter to set up a BroadcastReceiver (not ReceiveBroadcaster did you even try that code?) to get the events you are interested in, and then use Context.startActivity() with the Intent you want. You can even use a custom action, so you know it was triggered by the receiver, and not the user.
The only question is: is there a broadcast event you can arrange to receive? There may be a system event you can register for, or you may be able to generate a custom event yourself, via Context.sendBroadcast().
Remember you can inspect the incoming Intent your activity was started with, and "forward" the same or a modified Intent if it doesn't exactly match what you are looking for. As you correctly determined, you cannot dynamically alter an activity's set of IntentFilters, so you will have to inspect the host of every request.
Remember you can also register receivers in your manifest as well, and have that implementation called automatically by the system.

What does "category" in the manifest mean?

The documentation says you can specify a custom category.
When, why and how would you do it?
What would be the use of it?
The way I understand it, categories are public directives to the android operating system(and other apps) that represent different categories that your app should be a part of.
Example
When the launcher icon is tapped on the home screen, the home application looks through every installed app's manifest for the HOME category -- and if so it displays it in the app drawer.
However, there's more. You can specify categories in your applications manifest that lets the system know that you application can handle the intent category. For example, by putting a ALTERNATIVE category, other apps in the system know that your app can handle that category without specifically knowing the action name! In the following example, custom intent categories are passed through this intent, which is filtered and the corresponding object gets edited(taken from the Notes example app):
<intent-filter android:label="#string/resolve_title">
<action android:name="com.android.notepad.action.EDIT_TITLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
By registering this intent filter in an <activity /> tag, you can edit a "note". The intent data would contain the note, and the intent would get routed to the activity that this filter is registered in.
In Conclusion:
There isn't really a reason you'd use a custom category. They are for Android, and thus don't really make sense in application use. But, if you choose to use them, they can be used in the methods described above. "They provide some specific semantic rules, and if those rules are useful to you then feel free to use them"(Hackbod).
http://developer.android.com/guide/topics/intents/intents-filters.html
Scroll down a bit and you should see a section under "Intent Objects"
They basically describe certain special properties of an activity. for example, adding
<category android:name="android.intent.category.HOME" />
means that the app can be started on the phone's bootup
I'm kinda a noob to Android still, although I have programming experience otherwise.. It says a custom category in your own namespace. I'm guessing that if you are programming multiple apps and you want one app to run another app, you could use a custom category for your intent to force the phone to find your other app to catch the intent with?
When you do not want to use the default category then use the custom category.
Custom categories should use the package name as a prefix, to ensure that they are unique.
Some information is provided on below link:
http://developer.android.com/guide/topics/manifest/category-element.html
Check the below link it has somewhat same question:
Android custom categories

Android: Understanding Intent-Filters

I would like to create an Intent-Filter, so that certain links will trigger the start of my application (see this stackoverflow-thread for example: How to register some URL namespace (myapp://app.start/) for accessing your program by calling a URL in browser in Android OS? )
While trying, I figured out, that I dont quite understand how Intents and Intent-Filters (defined in the Manifest.xml) actually work. What is the difference between the following:
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
or the following:
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MAIN" />
And what is actually the difference between category and action Intent-Filters. I read this page http://developer.android.com/reference/android/content/Intent.html but I still missing a basic understanding.
Instead of looking at it from your app's point of view, flip it around and look at it from the Intent side.
When an Intent is created, the creator has no idea what apps are on the system to handle that Intent. But the creator does know what it wants to do (e.g., an app might want to let the user pick out a contact from somewhere on the device), and needs to reach out to other apps on the system to ask for what's desired.
To do this, Intents have several pieces of information attached to them. Among them are actions and categories.
The actions define in a general way the action the Intent wants to do, like VIEW a contact, PICK an image from the Gallery, etc.
The category is an additional piece of information that gives the Intent another way to differentiate itself. For example, when a link in the browser is clicked, the Intent that is created has the BROWSABLE category attached to it.
So, when the OS resolves the Intent, it will look for registered Activities or BroadcastReceivers that have an intent filter that includes all of pieces of information. If the Intent specifies the PICK action, Activities that do not have an intent-filter with the PICK action will be discarded from the list of candidates to handle the Intent.
In this way, the combined set of action, categories, type, and (possibly) scheme associated with an Intent serve to pinpoint the set of Activities that can handle the Intent. When you set up your intent-filter in your manifest, you are telling the OS which class of Intents you can handle.
I had to examine the code of android.content.IntentFilter.matchCategories(Set<String> categories) to understand the matching of categories:
Successful match, if your IntentFilter has categories and the Intent doesn't provide Categories
Successful match, if your IntentFilter has all categories of the Intent. The filter also can have additional categories.
No match, if your IntentFilter has no categories and the Intent has categories
No match, if your IntentFilter has not the categories the Intent has
Especially #1 and #3 aren't obvious.

Categories

Resources