129

I have this method so far , but it came up like something is missing

for example I have a file /sdcard/sound.3ga that returns false ( like there is no activity that can handle this type of file ) , But when I open it from the file manager it opens with the media player with no problem

I think this intent is not complete and I need to to something more to make my self sure that the handlerExists variable will be false ONLY if there is no activity that can handle this intent

PackageManager pm = getPackageManager();
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uriString)).toString());
String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
intent.setDataAndType(Uri.fromFile(new File(uriString)),mimetype);
boolean handlerExists = intent.resolveActivity(pm) != null;
Ziem
  • 6,579
  • 8
  • 53
  • 86
Lukap
  • 31,523
  • 64
  • 157
  • 244

9 Answers9

164

edwardxu's solution works perfectly for me.

Just to clarify a bit:

PackageManager packageManager = getActivity().getPackageManager();
if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent);
} else {
    Log.d(TAG, "No Intent available to handle action");
}
Ziem
  • 6,579
  • 8
  • 53
  • 86
Sparky1
  • 3,335
  • 6
  • 26
  • 29
  • 8
    well, with android api 30+, it doesn't always work now) – user924 Jun 24 '20 at 14:30
  • 1
    if targeting api 30+ check this: https://stackoverflow.com/a/62856745/4565796 – Saeed Arianmanesh Oct 19 '20 at 09:01
  • this gives me "null" when I try to show map. even though there is map installed, and if I continue to call stratActivity, it works fine. so, in short, this doesn't work correct for geo intents – Adem Jun 15 '22 at 00:27
87
PackageManager manager = context.getPackageManager();
List<ResolveInfo> infos = manager.queryIntentActivities(intent, 0);
if (infos.size() > 0) {
    //Then there is an Application(s) can handle your intent
} else {
    //No Application can handle your intent
}

Have you tried this intent?

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.fromFile(yourFileHere));
Mohammad Ersan
  • 12,304
  • 8
  • 54
  • 77
56
if (intent.resolveActivity(getPackageManager()) == null) {
    // No Activity found that can handle this intent. 
}
else{
    // There is an activity which can handle this intent. 
}
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
xuxu
  • 6,374
  • 1
  • 17
  • 11
  • Note that this doesn't always work: resolveActivity can return an intent that can't be handled. The queryIntentActivities approach works better for me. – Glenn Maynard Dec 19 '19 at 03:35
  • 4
    well, with android api 30+, it doesn't always work now) – user924 Jun 24 '20 at 14:30
  • @user924 what is the solution to open a URL on any browser available on device? Because "if(intent.resolveActivity(packageManager) != null)" is always giving null even if chrome available on device. – Kishan Solanki Jul 11 '22 at 07:12
4

The Clear Answer to solve this problem

if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}
2

You can use:

public static boolean isAvailable(Context ctx, Intent intent) {
   final PackageManager mgr = ctx.getPackageManager();
   List<ResolveInfo> list =
      mgr.queryIntentActivities(intent, 
         PackageManager.MATCH_DEFAULT_ONLY);
   return list.size() > 0;
}
Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
1

Using Kotlin If you need to do something when intent is not available,

fun isIntentAvailable(context: Context, action: String?): Boolean {
    val packageManager = context.packageManager
    val intent = Intent(action)
    val resolveInfo: List<*> = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
    return resolveInfo.isNotEmpty()
}

Implement this method as

private const val SAMPLE_INTENT = "com.realwear.barcodereader.intent.action.SCAN_BARCODE"

if(isIntentAvailable(this,SAMPLE_INTENT)){
    //Do Stuff
}

If you don't have anything to do,

Intent(SAMPLE_INTENT).also { barcodeReaderIntent ->
    barcodeReaderIntent.resolveActivity(packageManager)?.also {
        barcodeReaderIntent.putExtra(EXTRA_CODE_128, false)
        startActivityForResult(barcodeReaderIntent, BARCODE_REQUEST_CODE)
    }
}
Community
  • 1
  • 1
Varun Chandran
  • 647
  • 9
  • 23
  • What do you mean by “If you don’t have anything to do” and the code below it. The code below it sounds like it’s for if the intent is available, but maybe i am wrong. – Sakiboy Nov 26 '20 at 23:04
1

Small update for one looking for something similar in 2021 :) Since Android 11 it is not desired to call the package manager, so extra efforts are needed. So why don't you just wrap startActivity() in try-catch? Or even better - use Rx beautiful error handing:

....
.flatMapCompletable { 
      doSomethingThrowable()
          .onErrorResumeNext { completableCallbackIfNotResolvable() }
}
.subscribe()
Vadim
  • 141
  • 4
1

Here you are another Kotlin solution. It works perfectly even for Android 30+. First include this in you app manifest:

<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="choose-scheme-goes-here" />
    </intent>
</queries>

Then you can check if an intent can be handled with this function:

private fun isIntentAvailable(intent: Intent): Boolean {
    val manager = requireContext().packageManager
    val info = manager.queryIntentActivities(intent, 0)
    return info.size > 0
}
Mariusz Wiazowski
  • 2,118
  • 1
  • 16
  • 17
0

Another approach using kotlin extension

 fun Context.isIntentAvailable(intent: Intent): Boolean {
    val resolveInfo: List<*> = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
    return resolveInfo.isNotEmpty()
 }

Usage inside fragment

val available = requireContext().isIntentAvailable(this)

Usage inside activity

val available = this.isIntentAvailable(this)
  • 1
    you should use `PackageManager` for your extension fun instead of `Context` and avoid `PackageManager.MATCH_DEFAULT_ONLY` – user924 Jun 24 '20 at 14:34
  • `this.isIntentAvailable(this)` is unnecessarily verbose. Just use `isIntentAvailable()` – Zun Jul 10 '20 at 14:18