package com.mopub.common.util;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.mopub.common.Preconditions;
import com.mopub.common.logging.MoPubLog;
import com.mopub.exceptions.IntentNotResolvableException;
import com.mopub.exceptions.UrlParseException;
import java.util.List;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
public class Intents {
private static final String TWITTER_APPLICATION_DEEPLINK_URL = "twitter://timeline";
private static final String PLAY_GOOGLE_COM = "play.google.com";
private static final String MARKET_ANDROID_COM = "market.android.com";
private static final String MARKET = "market";
private static final String HTTP = "http";
private static final String HTTPS = "https";
private Intents() {}
public static void startActivity(@NonNull final Context context, @NonNull final Intent intent)
throws IntentNotResolvableException {
Preconditions.checkNotNull(context);
Preconditions.checkNotNull(intent);
if (!(context instanceof Activity)) {
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
}
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
throw new IntentNotResolvableException(e);
}
}
/**
* Adding FLAG_ACTIVITY_NEW_TASK with startActivityForResult will always result in a
* RESULT_CANCELED, so don't use it for Activity contexts.
*/
public static Intent getStartActivityIntent(@NonNull final Context context,
@NonNull final Class clazz, @Nullable final Bundle extras) {
final Intent intent = new Intent(context, clazz);
if (!(context instanceof Activity)) {
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
}
if (extras != null) {
intent.putExtras(extras);
}
return intent;
}
public static boolean deviceCanHandleIntent(@NonNull final Context context,
@NonNull final Intent intent) {
try {
final PackageManager packageManager = context.getPackageManager();
final List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
return !activities.isEmpty();
} catch (NullPointerException e) {
return false;
}
}
public static boolean isHttpUrl(final String url) {
if (url == null) {
return false;
}
final String scheme = Uri.parse(url).getScheme();
return (HTTP.equals(scheme) || HTTPS.equals(scheme));
}
private static boolean isAppStoreUrl(final String url) {
if (url == null) {
return false;
}
final Uri uri = Uri.parse(url);
final String scheme = uri.getScheme();
final String host = uri.getHost();
if (PLAY_GOOGLE_COM.equals(host) || MARKET_ANDROID_COM.equals(host)) {
return true;
}
if (MARKET.equals(scheme)) {
return true;
}
return false;
}
public static boolean isDeepLink(final String url) {
return isAppStoreUrl(url) || !isHttpUrl(url);
}
public static boolean canHandleTwitterUrl(final Context context) {
return canHandleApplicationUrl(context, TWITTER_APPLICATION_DEEPLINK_URL, false);
}
public static boolean canHandleApplicationUrl(final Context context, final String url) {
return canHandleApplicationUrl(context, url, true);
}
public static boolean canHandleApplicationUrl(final Context context, final String url,
final boolean logError) {
// Determine which activities can handle the intent
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
// If there are no relevant activities, don't follow the link
if (!Intents.deviceCanHandleIntent(context, intent)) {
if (logError) {
MoPubLog.w("Could not handle application specific action: " + url + ". " +
"You may be running in the emulator or another device which does not " +
"have the required application.");
}
return false;
}
return true;
}
public static boolean isNativeBrowserScheme(@NonNull final String url) {
return url.startsWith("mopubnativebrowser://");
}
/**
* Native Browser Scheme URLs provide a means for advertisers to include links that click out to
* an external browser, rather than the MoPub in-app browser. Properly formatted native browser
* URLs take the form of "mopubnativebrowser://navigate?url=http%3A%2F%2Fwww.mopub.com".
*
* @param url
* @return An Intent that will open an app-external browser taking the user to a page specified
* in the query parameter of the passed-in url
* @throws UrlParseException if the provided url has an invalid format or is non-hierarchical
*/
public static Intent intentForNativeBrowserScheme(@NonNull final String url)
throws UrlParseException {
Preconditions.checkNotNull(url);
if (!isNativeBrowserScheme(url)) {
throw new UrlParseException("URL does not have mopubnativebrowser:// scheme.");
}
final Uri uri = Uri.parse(url);
if (!"navigate".equals(uri.getHost())) {
throw new UrlParseException("URL missing 'navigate' host parameter.");
}
final String urlToOpenInNativeBrowser;
try {
urlToOpenInNativeBrowser = uri.getQueryParameter("url");
} catch (UnsupportedOperationException e) {
// Accessing query parameters only makes sense for hierarchical URIs as per:
// http://developer.android.com/reference/android/net/Uri.html#getQueryParameter(java.lang.String)
MoPubLog.w("Could not handle url: " + url);
throw new UrlParseException("Passed-in URL did not create a hierarchical URI.");
}
if (urlToOpenInNativeBrowser == null) {
throw new UrlParseException("URL missing 'url' query parameter.");
}
final Uri intentUri = Uri.parse(urlToOpenInNativeBrowser);
return new Intent(Intent.ACTION_VIEW, intentUri);
}
}