[CB-10795] Exclude current app from external intent list (#154)
On Android, if the app defines an intent-filter for a given URL, and then tries to use inappbrowser to launch that URL via the _system target, the default handler for that intent is the app itself. That behavior can lead to circular loops, and ultimately is not what the developer wants -- the link should be launched in a browser. Because there is no easy way to find the "default" system browser on a device, this solution will do two things: 1) Check if the app is one of the targets for this intent 2) If so, create a custom chooser with all other targets, excluding the current app. If the app is not a target, then the current (existing) behavior is preserved. The only real "downside" to this approach is that a default handler can no longer be set for these URLs within the app, and a chooser will be shown each time the user taps a link that opens in a new browser. Fixes https://issues.apache.org/jira/browse/CB-10795
This commit is contained in:
parent
cf58b04097
commit
a0783378fc
@ -19,8 +19,12 @@
|
|||||||
package org.apache.cordova.inappbrowser;
|
package org.apache.cordova.inappbrowser;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.provider.Browser;
|
import android.provider.Browser;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -71,6 +75,7 @@ import org.json.JSONObject;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -432,7 +437,8 @@ public class InAppBrowser extends CordovaPlugin {
|
|||||||
intent.setData(uri);
|
intent.setData(uri);
|
||||||
}
|
}
|
||||||
intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName());
|
intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName());
|
||||||
this.cordova.getActivity().startActivity(intent);
|
// CB-10795: Avoid circular loops by preventing it from opening in the current app
|
||||||
|
this.openExternalExcludeCurrentApp(intent);
|
||||||
return "";
|
return "";
|
||||||
// not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
|
// not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
|
||||||
} catch (java.lang.RuntimeException e) {
|
} catch (java.lang.RuntimeException e) {
|
||||||
@ -441,6 +447,46 @@ public class InAppBrowser extends CordovaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the intent, providing a chooser that excludes the current app to avoid
|
||||||
|
* circular loops.
|
||||||
|
*/
|
||||||
|
private void openExternalExcludeCurrentApp(Intent intent) {
|
||||||
|
String currentPackage = cordova.getActivity().getPackageName();
|
||||||
|
boolean hasCurrentPackage = false;
|
||||||
|
|
||||||
|
PackageManager pm = cordova.getActivity().getPackageManager();
|
||||||
|
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
|
||||||
|
ArrayList<Intent> targetIntents = new ArrayList<Intent>();
|
||||||
|
|
||||||
|
for (ResolveInfo ri : activities) {
|
||||||
|
if (!currentPackage.equals(ri.activityInfo.packageName)) {
|
||||||
|
Intent targetIntent = (Intent)intent.clone();
|
||||||
|
targetIntent.setPackage(ri.activityInfo.packageName);
|
||||||
|
targetIntents.add(targetIntent);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hasCurrentPackage = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the current app package isn't a target for this URL, then use
|
||||||
|
// the normal launch behavior
|
||||||
|
if (hasCurrentPackage == false || targetIntents.size() == 0) {
|
||||||
|
this.cordova.getActivity().startActivity(intent);
|
||||||
|
}
|
||||||
|
// If there's only one possible intent, launch it directly
|
||||||
|
else if (targetIntents.size() == 1) {
|
||||||
|
this.cordova.getActivity().startActivity(targetIntents.get(0));
|
||||||
|
}
|
||||||
|
// Otherwise, show a custom chooser without the current app listed
|
||||||
|
else if (targetIntents.size() > 0) {
|
||||||
|
Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size()-1), null);
|
||||||
|
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[] {}));
|
||||||
|
this.cordova.getActivity().startActivity(chooser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the dialog
|
* Closes the dialog
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user