Skip to content

Instantly share code, notes, and snippets.

@robUx4
Last active August 29, 2015 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robUx4/9934836 to your computer and use it in GitHub Desktop.
Save robUx4/9934836 to your computer and use it in GitHub Desktop.
Block the Play Store from opening unexpectedly (from dubious ad networks)
package com.levelup.touiteur;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PatternMatcher;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
public abstract class ActivityWith_Ads extends Activity {
private final static String TAG = "AdSafe";
private final static boolean HAS_ADS = true;
/**
* Extra field you should put on your external browser Intents to make sure they're not blocked
*/
public static final String EXTRA_BYPASS_BLOCK = "com.levelup.touiteur.extra.urlbypass";
private static final IntentFilter badIntentFilters[];
/**
* The {@link android.app.Instrumentation Instrumentation} of the process where filters are added
*/
private static Instrumentation mInstrumentation;
/**
* The list of {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} currently registered to block some intents
* for the whole process
*/
private static Instrumentation.ActivityMonitor registeredMonitors[];
/**
* Flag to indicate an ad was clicked so the resulting Intent launched is OK
*/
private static boolean adClicked;
static {
List<IntentFilter> badFilters = new ArrayList<IntentFilter>(12);
// intents from the Play Store manifest
IntentFilter playStoreAssetBrowser = new IntentFilter();
playStoreAssetBrowser.addAction(Intent.ACTION_MAIN);
playStoreAssetBrowser.addAction(Intent.ACTION_SEARCH);
playStoreAssetBrowser.addCategory(Intent.CATEGORY_LAUNCHER);
playStoreAssetBrowser.addCategory("android.intent.category.APP_MARKET"); // Intent.CATEGORY_APP_MARKET
playStoreAssetBrowser.addCategory(Intent.CATEGORY_DEFAULT);
badFilters.add(playStoreAssetBrowser);
IntentFilter playStoreMarket = new IntentFilter();
playStoreMarket.addAction(Intent.ACTION_VIEW);
playStoreMarket.addAction("android.nfc.action.NDEF_DISCOVERED");
playStoreMarket.addAction("com.google.android.finsky.NAVIGATIONAL_SUGGESTION");
playStoreMarket.addCategory(Intent.CATEGORY_BROWSABLE);
playStoreMarket.addCategory(Intent.CATEGORY_DEFAULT);
badFilters.add(filterWithData(playStoreMarket, "market", "search"));
badFilters.add(filterWithData(playStoreMarket, "market", "details"));
badFilters.add(filterWithData(playStoreMarket, "http", "market.android.com", "/", PatternMatcher.PATTERN_LITERAL));
badFilters.add(filterWithData(playStoreMarket, "http", "market.android.com", "/", PatternMatcher.PATTERN_PREFIX));
badFilters.add(filterWithData(playStoreMarket, "https", "market.android.com", "/", PatternMatcher.PATTERN_LITERAL));
badFilters.add(filterWithData(playStoreMarket, "https", "market.android.com", "/", PatternMatcher.PATTERN_PREFIX));
IntentFilter playStoreStore = new IntentFilter();
playStoreStore.addAction(Intent.ACTION_VIEW);
playStoreStore.addAction("android.nfc.action.NDEF_DISCOVERED");
playStoreStore.addCategory(Intent.CATEGORY_BROWSABLE);
playStoreStore.addCategory(Intent.CATEGORY_DEFAULT);
badFilters.add(filterWithData(playStoreStore, "http", "play.google.com", "/store", PatternMatcher.PATTERN_PREFIX));
badFilters.add(filterWithData(playStoreStore, "https", "play.google.com", "/store", PatternMatcher.PATTERN_PREFIX));
badFilters.add(filterWithData(playStoreStore, "http", "play.google.com", "/redeem", PatternMatcher.PATTERN_PREFIX));
badFilters.add(filterWithData(playStoreStore, "https", "play.google.com", "/redeem", PatternMatcher.PATTERN_PREFIX));
IntentFilter playStorePurchase = new IntentFilter();
playStorePurchase.addAction("com.android.vending.billing.PURCHASE");
playStorePurchase.addCategory(Intent.CATEGORY_DEFAULT);
badFilters.add(playStorePurchase);
badIntentFilters = badFilters.toArray(new IntentFilter[]{});
}
private static boolean isBadIntent(Context context, Intent intent) {
if (null != intent.getComponent() && TextUtils.equals(intent.getComponent().getPackageName(), context.getPackageName())) {
// this intent is launching some of our activities
if (TextUtils.equals(intent.getComponent().getClassName(), "com.admarvel.android.ads.AdMarvelActivity")) {
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.addCategory(Intent.CATEGORY_BROWSABLE);
testIntent.setData(Uri.parse(intent.getStringExtra("url")));
intent = testIntent; // fall through to test the target that wasn't clicked
} else if (TextUtils.equals(intent.getComponent().getClassName(), "com.admarvel.android.ads.AdMarvelVideoActivity")) {
// this Intent was launched without the user clicking in the ad area
Log.e(TAG, "AdMarvelVideoActivity launched without click intent:" + intent + " extras:" + intent.getExtras());
} else if (TextUtils.equals(intent.getComponent().getClassName(), "com.google.ads.AdActivity")) {
Bundle adData = intent.getBundleExtra("com.google.ads.AdOpener");
if ("intent".equals(adData.get("action"))) {
Object params = adData.get("params");
if (params instanceof HashMap) {
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.addCategory(Intent.CATEGORY_BROWSABLE);
testIntent.setData(Uri.parse(((HashMap<String, String>) params).get("u")));
intent = testIntent; // fall through to test the target that wasn't clicked
}
}
} else if (TextUtils.equals(intent.getComponent().getClassName(), "com.millennialmedia.android.MMActivity")) {
// this Intent was launched without the user clicking in the ad area
Log.e(TAG, "MMActivity launched without click intent:" + intent + " extras:" + intent.getExtras());
} else if (TextUtils.equals(intent.getComponent().getClassName(), "com.millennialmedia.android.VideoPlayer")) {
// this Intent was launched without the user clicking in the ad area
Log.e(TAG, "VideoPlayer launched without click intent:" + intent + " extras:" + intent.getExtras());
} else {
return false; // all other activities we know about should not be blocked
}
}
ContentResolver resolver = context.getContentResolver();
for (IntentFilter monitor : badIntentFilters) {
if (monitor.match(resolver, intent, true, "IntentBlock") >= 0) {
Log.d(TAG, "bad intent detected intent:" + intent + " extras:" + intent.getExtras());
return true;
}
}
return false;
}
public static boolean isIntentLegal(Context context, Intent intent) {
if (adClicked || intent.hasExtra(EXTRA_BYPASS_BLOCK))
return true;
return !isBadIntent(context, intent);
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// it will be done in the other version otherwise
if (isIntentLegal(this, intent)) {
unregisterIntentBlockers();
}
}
super.startActivityForResult(intent, requestCode);
}
@SuppressLint("NewApi")
@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
if (isIntentLegal(this, intent)) {
unregisterIntentBlockers();
}
super.startActivityForResult(intent, requestCode, options);
}
public static void registerIntentBlockers() {
if (null != mInstrumentation && null == registeredMonitors) {
Log.v(TAG, "register intent blockers in " + mInstrumentation);
registeredMonitors = new Instrumentation.ActivityMonitor[badIntentFilters.length];
for (int i = 0; i < badIntentFilters.length; ++i) {
registeredMonitors[i] = new Instrumentation.ActivityMonitor(badIntentFilters[i], null, true);
mInstrumentation.addMonitor(registeredMonitors[i]);
}
}
}
public static void unregisterIntentBlockers() {
if (null != mInstrumentation && null != registeredMonitors) {
Log.v(TAG, "unregister intent blockers in " + mInstrumentation);
for (int i = 0; i < registeredMonitors.length; ++i) {
mInstrumentation.removeMonitor(registeredMonitors[i]);
}
registeredMonitors = null;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.id.MainLayout);
ViewGroup mAdGroup = (ViewGroup) findViewById(R.id.AdItem);
if (!HAS_ADS) {// || !InvisiblePreferences.getInstance().getBoolean(InvisiblePreferences.Show_Ads)) {
((ViewGroup) mAdGroup.getParent()).removeView(mAdGroup);
mAdGroup = null;
} else {
mAdGroup.setVisibility(View.GONE);
View adClick = mAdGroup.findViewById(R.id.adClick);
adClick.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// ad touched
adClicked = true;
return false;
}
});
}
}
@Override
protected void onStart() {
adClicked = false;
if (HAS_ADS) {
try {
Field instrumentationField = Activity.class.getDeclaredField("mInstrumentation");
instrumentationField.setAccessible(true);
Instrumentation instrumentation = (Instrumentation) instrumentationField.get(this);
Log.v(TAG, this + " Found instrumentation:" + instrumentation);
if (null == mInstrumentation) {
mInstrumentation = instrumentation;
} else if (mInstrumentation != instrumentation) {
Log.d(TAG, this + " different instrumentation:" + instrumentation + " was:" + mInstrumentation);
unregisterIntentBlockers();
mInstrumentation = instrumentation;
}
registerIntentBlockers();
if (null == mInstrumentation) {
Log.d(TAG, "Could not find instrumentation in " + this);
}
} catch (NoSuchFieldException e) {
Log.d(TAG, "Failed to get the activity instrumentation in " + this, e);
} catch (IllegalAccessException e) {
Log.d(TAG, "Failed to get the activity instrumentation in " + this, e);
} catch (IllegalArgumentException e) {
Log.d(TAG, "Failed to get the activity instrumentation in " + this, e);
}
}
super.onStart();
}
private static IntentFilter filterWithData(IntentFilter baseFilter, String scheme, String authority) {
IntentFilter result = new IntentFilter(baseFilter);
result.addDataScheme(scheme);
result.addDataAuthority(authority, null);
return result;
}
private static IntentFilter filterWithData(IntentFilter baseFilter, String scheme, String authority, String path, int type) {
IntentFilter result = filterWithData(baseFilter, scheme, authority);
result.addDataPath(path, type);
return result;
}
@Override
public void setIntent(Intent newIntent) {
if (null == newIntent) {
Log.e(TAG, "Intent blockers are not compatible with an Activity that has no intent set");
newIntent = new Intent();
}
super.setIntent(newIntent);
}
}
Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
launchIntent.putExtra(ActivityWithAds.EXTRA_BYPASS_BLOCK, true); // make sure we're not blocked
launchIntent.addCategory(Intent.CATEGORY_BROWSABLE);
if (null!=referrer)
launchIntent.putExtra("android.intent.extra.REFERRER", referrer);
launchIntent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
activity.startActivity(launchIntent);
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="150dip" >
<com.admarvel.android.ads.AdMarvelView
android:id="@+id/adMarcel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<View
android:id="@+id/adClick"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
package com.levelup.touiteur;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Intent;
import android.os.Bundle;
public class MyApp extends Application {
@Override
public void startActivity(Intent intent) {
if (ActivityWithAds.isIntentLegal(this, intent)) {
ActivityWithAds.unregisterIntentBlockers();
super.startActivity(intent);
}
}
@SuppressLint("NewApi")
@Override
public void startActivity(Intent intent, Bundle options) {
if (ActivityWithAds.isIntentLegal(this, intent)) {
ActivityWithAds.unregisterIntentBlockers();
super.startActivity(intent, options);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment