Intents & Deep Linking Quiz
ANDROID › Components
You need to start a bound Service in your own app. Which approach is correct and safe on modern Android?
- Use an implicit intent with a custom action so other apps can also bind
- Use an explicit intent that names the Service class
- Use a PendingIntent.getBroadcast() with FLAG_MUTABLE
- Use an implicit intent and rely on CATEGORY_DEFAULT
Answer: Use an explicit intent that names the Service class
Services must be started with explicit intents; since Android 5.0, bindService() with an implicit intent throws an exception, so naming the Service class is the correct, secure approach.
An implicit intent carries categories A and B. An activity's intent filter declares categories A, B, and DEFAULT. Does the category test pass?
- No, the filter must declare exactly the same categories as the intent
- No, an intent with two categories can never match
- Yes, every category in the intent is present in the filter
- Only if the intent also lists DEFAULT explicitly
Answer: Yes, every category in the intent is present in the filter
The category test requires every category in the intent to be present in the filter; the filter may declare additional categories (like DEFAULT) without breaking the match.
On Android 12 (API 31) and higher, what happens if you create a PendingIntent without specifying FLAG_IMMUTABLE or FLAG_MUTABLE?
- It silently defaults to FLAG_MUTABLE
- The app crashes with an IllegalArgumentException
- It works but logs a StrictMode warning only
- The PendingIntent is created as immutable automatically
Answer: The app crashes with an IllegalArgumentException
Starting with Android 12, you must explicitly pass a mutability flag; omitting both throws an IllegalArgumentException at PendingIntent creation.
Which set of intent-filter elements is required so a web URL clicked in a browser opens your activity as a deep link?
- ACTION_MAIN, CATEGORY_LAUNCHER, and a data scheme, without a BROWSABLE category
- ACTION_SEND, CATEGORY_DEFAULT, and a matching mimeType value
- ACTION_VIEW, CATEGORY_DEFAULT, CATEGORY_BROWSABLE, and a data scheme/host
- ACTION_VIEW, CATEGORY_LAUNCHER, plus a data scheme and host
Answer: ACTION_VIEW, CATEGORY_DEFAULT, CATEGORY_BROWSABLE, and a data scheme/host
Browser-launchable deep links need action VIEW, category DEFAULT (to receive implicit intents) and category BROWSABLE (to be reachable from a browser), plus a data element specifying the scheme and host.
For Android App Links to verify automatically and skip the disambiguation dialog, what must be true?
- The filter sets android:autoVerify=true and serves assetlinks.json at /.well-known/
- The app declares android:exported=false on the deep-link target activity
- The user manually selects your app as the default web-link handler in the system settings
- The <data> element uses a custom app scheme instead of plain https
Answer: The filter sets android:autoVerify=true and serves assetlinks.json at /.well-known/
App Links verification requires android:autoVerify="true" on the http/https intent filter and a Digital Asset Links file at https://domain/.well-known/assetlinks.json whose certificate fingerprint matches the app's signing key.
Inside an activity launched by a deep link, how do you read the URI that triggered it?
- intent.getStringExtra("uri"), if the link passed it as an extra
- intent.data, the Uri from getIntent().getData()
- intent.getCategories().first(), since categories identify the link
- intent.component.className, because it tells you which activity ran
Answer: intent.data, the Uri from getIntent().getData()
The triggering URI is delivered as the intent's data, retrieved via getIntent().getData() (intent.data in Kotlin); the action is in intent.action.
Why does Google recommend FLAG_IMMUTABLE and explicit intents inside a PendingIntent?
- Immutable PendingIntents are delivered a bit faster by the system
- Mutable PendingIntents are unsupported on Android 13 and later
- It stops a malicious holder from filling blanks and retargeting it
- Explicit intents are needed for the PendingIntent to show in a notification
Answer: It stops a malicious holder from filling blanks and retargeting it
An immutable PendingIntent wrapping an explicit intent cannot have its blank fields (component, action, data) populated by the holder, closing a hijacking vector where the intent could be redirected to an attacker-chosen component.
On Android 12 (API 31) and higher, what does the build/install require for an activity, service, or broadcast receiver that declares an intent filter?
- Nothing changed; android:exported still defaults to true with filters
- The component is forced to android:exported=false no matter the filter
- You must set android:exported; omitting it causes install failure
- android:exported is required only for activities, not services or receivers
Answer: You must set android:exported; omitting it causes install failure
Since Android 12, any component that declares an intent filter must explicitly set android:exported; omitting it is a build/install error precisely because the old implicit default of true was a security footgun.
You call startActivity() with an Activity intent from a Service or the application Context (not from an Activity). What is required to avoid a runtime exception?
- Add FLAG_ACTIVITY_NEW_TASK to the intent
- Add CATEGORY_LAUNCHER to the intent
- Wrap the intent in a PendingIntent.getService()
- Set FLAG_IMMUTABLE on the intent
Answer: Add FLAG_ACTIVITY_NEW_TASK to the intent
Launching an activity from a non-Activity context has no existing task to attach to, so you must add FLAG_ACTIVITY_NEW_TASK; otherwise the system throws AndroidRuntimeException about calling startActivity() outside of an Activity context.
You call PendingIntent.getActivity() twice with the same requestCode and an intent that is equal by filterEquals(), using FLAG_UPDATE_CURRENT. What happens on the second call?
- A new, separate PendingIntent is always created from scratch
- An IllegalStateException is thrown because the request code repeats
- The first PendingIntent is cancelled, and null is returned instead
- The same PendingIntent token is returned, with extras updated
Answer: The same PendingIntent token is returned, with extras updated
PendingIntents are matched by requestCode plus Intent.filterEquals (action, data, type, category, component, not extras); FLAG_UPDATE_CURRENT keeps the existing token but overwrites its extras with those of the new intent.
You build an intent and call setData(uri), then later call setType(mimeType) on the same intent. What is the effect?
- Both the data URI and the MIME type are kept and fully retained together on the intent object
- setType nulls the data URI (and setData nulls the type); use setDataAndType for both
- setType throws an exception because a data URI is already set on it
- The MIME type is simply appended onto the URI as a query parameter
Answer: setType nulls the data URI (and setData nulls the type); use setDataAndType for both
By design setData() and setType() each null out the other field, so calling them in sequence loses the first value; to specify a URI and an explicit MIME type together you must call setDataAndType().
On Android 11 (API 30) and higher, intent.resolveActivity(packageManager) returns null for an implicit intent even though the user has an app that can handle it. What is the most likely cause?
- resolveActivity was removed from PackageManager in API 30, so it always fails
- Implicit intents are no longer allowed on Android 11, even when an app can handle them
- Package visibility filtering: add a matching <queries> entry or QUERY_ALL_PACKAGES
- resolveActivity must now run on a background thread, or it returns null on API 30
Answer: Package visibility filtering: add a matching <queries> entry or QUERY_ALL_PACKAGES
Android 11 introduced package visibility restrictions; unless your manifest declares a <queries> entry matching the intent (or you hold QUERY_ALL_PACKAGES), other apps are invisible and resolveActivity/queryIntentActivities returns null despite a real handler existing.
A singleTop activity is already at the top of its task and receives a new matching intent. Which callback delivers it, and what should you do?
- onNewIntent(intent) fires; call setIntent(intent) so getIntent() returns it
- onCreate runs again automatically, receiving the new intent as its extra
- onResume is re-invoked and receives the new intent as a parameter
- The new intent is quietly discarded; only the original launching intent is ever used
Answer: onNewIntent(intent) fires; call setIntent(intent) so getIntent() returns it
For an existing singleTop (or singleTask/singleInstance) instance the system calls onNewIntent() instead of recreating the activity, and getIntent() still returns the original intent unless you call setIntent() to update it.