Related
I'm trying to develop an android app for the SDK version 30 that (when a button is clicked) starts listening to what apps are opened on the phone. If it detects the user opening Whatsapp, it is supposed to show a LockScreen activity over Whatsapp that makes you answer a math question before being able to use Whatsapp.
I know this can be done as their are apps like QualityTime or Forest that have similar features to restrict you from using certain apps, but I am a newbie when it comes to programming (probably obvious from my code) and feel totally stuck.
I have already figured out how to detect what app the user opened in the last second with code from stack overflow:
public String getCurrentApp() {
String topPackageName = "None";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService("usagestats");
long time = System.currentTimeMillis();
List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1, time);
// Sort the stats by the last time used
if (stats != null) {
SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (!mySortedMap.isEmpty())
{
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
}
return topPackageName;
}
I have another function that is started when the user clicks the button in my app to "activate" the listening process. This function keeps checking if the user opens Whatsapp and is then supposed to display the Lockscreen activity on top:
public void startListening(View view)
{
System.out.println("Lock activated.");
while (activated) {
String currentlyRunningApp;
currentlyRunningApp = getCurrentApp();
if (currentlyRunningApp.equals("com.whatsapp"))
{
System.out.println("Whatsapp detected. Showing Lockscreen...");
Intent i = new Intent(this,LockScreen.class);
startActivity(i);
}
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(All of the code I have shown is in my MainActivity btw.)
I have the following permissions granted to my app:
android.permission.PACKAGE_USAGE_STATS (for the getCurrentApp() function)
android.permission.SYSTEM_ALERT_WINDOW (as suggested here)
android.permission.ACTION_MANAGE_OVERLAY_PERMISSION (although I am not sure I even need this one)
My problem is, that instead of showing the Lockscreen activity I created, it only shows a blackscreen for the user. The Lockscreen activity itself works fine if I let the user open it through a button on the mainActivity, so the issue seems to really be that I can not properly show an activity if my app is running in the background and I want to display it on top of Whatsapp.
I have tried to look through similar questions, but all of the posts on here with similar use cases seem to be very old and outdated (i.e. this or this), as the newer versions seem to have way tighter security restrictions.
I also tried to do it with a screen overlay instead of an activity (using this source), but this doesn't even give me a blackscreen - just does nothing...
I am also aware that there are probably better ways to program the whole "listening and checking for whatsapp" part - i.e. with a service instead of a while-loop or something, but I only found out about services while researching this problem and I'd like to fix the blackscreen issue first.
After lots of trial and error I figured out that the issues was indeed caused by a missing permission, but one that I could not find on any stack overflow answer related to black screen problems. On top of that, I believe it's an issue that only occurred because I used a Xiaomi device for testing.
There are currently two separate permissions for displaying screens over other apps that you will need to grant:
Display over other apps, also called Display pop-up window. This is the android.permission.ACTION_MANAGE_OVERLAY_PERMISSION that I wasn't sure was even needed. So to emphasize, I definetly do need this permission.
Display pop-up windows while running in the background. This is the permission I was missing.
After I allowed them both (which you can do under Settings > Apps > Manage Apps > Your App > Other Permissions) everything worked fine.
To direct the user directly to the settings menu where they can allow these permissions, I used the code from this stack overflow answer. This is also where I got the info that it's a xiaomi-specific "issue".
I am stuck with a functionality of the Firebase SDK (Auth package) regarding the Scenes and it's integration. Here's how they work:
1st: Loading Scene
Here, I just added the FirebaseInit code EXACTLY as suggested by Patrick, which it's only function is to call the next scene (Login/Register) once everything loads correctly.
2nd: Login/Register Scene
Here I do all the Login AND ALSO the register logic. I set up a button that alternates between the two (Activating the respective parent gameObject within the Canvas). Once the user log's in, the 3rd scene comes into play.
3rd: App's Main Screen Scene
Main Screen of the app, where the user can LOGOUT and return to the Login Scene.
Problem
I added the 'LoadSceneWhenUserAuthenticated.cs' in the 2nd Scene, and it works (kind of).
It actually does what it is supposed to. If I log in, quit the game without loging out, and open it again, it does come back directly to the 3rd scene. BUT some things are happening and they aren't supposed to.
First
When I Sign Up a user, I call the method 'CreateUserWithEmailAndPasswordAsync()'. Once it completes, it should activate the login screen and stay there, waiting for the user to fill in the password, but the 'FirebaseAuth.DefaultInstance.StateChanged' comes into play and forces the 3rd screen to be loaded, skipping several other steps that should be taken (email registration for example).
Second
As I mentioned in the end of number 1 above, if I try to log in to an account that does not have it's email verified, it works! (due to the 'LoadSceneWhenUserAuthenticated.cs' which is added in the scene). Code:
var LoginTask = auth.SignInWithEmailAndPasswordAsync(_email, _password);
LoginTask.ContinueWithOnMainThread(task =>
{
if (task.IsCanceled || task.IsFaulted)
{
Firebase.FirebaseException e =
task.Exception.Flatten().InnerExceptions[0] as Firebase.FirebaseException;
GetErrorMessage((AuthError)e.ErrorCode, warningLoginText);
return;
}
if (task.IsCompleted)
{
User = LoginTask.Result;
if (User.IsEmailVerified == true)
{
UIControllerLogin.instance.MainScreenScene();
}
else
{
warningLoginText.text = Lean.Localization.LeanLocalization.GetTranslationText($"Login/VerifyEmail");
}
I know that it's possible to fix this issue by adding an extra scene just before the login scene (as Patrick does in the youtube video) but it doesn't make any sense in my app. It would actually only harm the UX of it.
Patrick's Video:
https://www.youtube.com/watch?v=52yUcKLMKX0&t=264s
I'm glad my video helped!
My architecture won't work for every game, and I tried to boil it down to the bare minimum to get folks started. You may be able to get the functionality you want by adding an additional check in HandleAuthStateChanged:
private void HandleAuthStateChanged(object sender, EventArgs e)
{
if (_auth.CurrentUser != null && !_auth.CurrentUser.IsAnonymous && _auth.CurrentUser.IsEmailVerified)
{
SceneManager.LoadScene(_sceneToLoad);
}
}
but it does sound like, at this point, you'll want to build out a more robust registration/sign in flow that fits your use case.
If you need more help, I might suggest re-posting on the community mailing list or the subreddit. Those resources may be more better suited to discussing various pros/cons of different architectures or spitballing ideas (and feel free to link to any new posts in a comment so myself or others interested can follow along).
I am trying to use Assist api inside my application, i followed most of the tutorials, but could not find a proper tutorial which will completely tell how it should be implemented. i have added this to the activity. is there anything else to be done in manifest or anywhere in the project. When debugged this below method got called but nothing
#Override
public void onProvideAssistContent(AssistContent outContent) {
super.onProvideAssistContent(outContent);
outContent.setWebUri(Uri.parse("https://commonsware.com"));
try {
String structuredJson = new JSONObject()
.put("#type", "Book")
.put("#author", "https://commonsware.com/mmurphy")
.put("publisher", "CommonsWare, LLC")
.put("name", "The Busy Coder's Guide to Android Development")
.toString();
outContent.setStructuredData(structuredJson);
}catch(JSONException jsonEx){
Log.e(getClass().getSimpleName(), "What happend", jsonEx);
}
}
i am seeing, it always shows NOTHING FOUND ON THE SCREEN when i long tapped the home button
i want to simply open a url through assist api from my application by long tap on home button
That is not your decision to make. You can offer a URL to the assistant. What the assistant does with that URL, if anything, is up to the developers of the assistant.
In my tests when the Assist API came out, I concluded that the then-current implementation of Google's Now on Tap ignored onProvideAssistContent(), but that the onProvideAssistContent()-supplied data was available if assistants wanted it.
what i need to modify
To force the assistant to do something with onProvideAssistContent(), you would need to write your own assistant, then convince the user to switch to your assistant.
I've built an Android app which is now on Play Market. From time to time, I make updates to it, and I'd like to let users know that a new version is available.
How can I send an update notification to the users of the app?
You do not need to do anything specific for this. Since you mentioned that you are using Google Play, the update notification is taken care of by Google Play.
You just need to update the APK with a higher versionCode and Google Play should do the rest.
Update 2020: now you can use in-app updates mechanism
Docs: https://developer.android.com/guide/playcore/in-app-updates
You can do this in a lot of ways, depending on when you want the user to be able to see that there is an update available.
If you want the user to know about the update when the app is started, just create a utility method (inside the onCreate method of your main/first Activity) that checks if a newer version is available in Google Play. If it does, display an alert dialog with a relevant message and an Intent which opens your app in Google Play when the user clicks on the positive button of the alert dialog.
If you are updating the app regularly, the user will keep getting this alert dialog every time the app is started and hence, may get irritated. Thus, this is not the best approach.
If you want the user to get a notification on the phone (and not when the user starts the app), you can use the AlarmManager class to schedule a background service which checks for an update at regular intervals. If the service finds that an upgrade is actually available, publish a notification with an intent that opens your app in Google Play.
Of course, another approach is to leave it to the OS itself. If the user has not set the "Automatically update" preference for your app, the user will get a notification regularly about an update available for your, as well as any other apps.
But not all users enable background data on their devices, so this is not completely reliable.
In the end, you must respect the users preferences. If the user does not want to automatically update the app, or does not want to see a nagging dialog box whenever he/she starts your app, don't alert the user about the update.
In my opinion, you should create a PreferenceActivity that has a preference like "Check for updates regularly", which can be set from within your app. If it is set, do the needful in your own service. May be even give the user an option to select the period after which the service will check for an update.
I hope this helps!
It is up to each phone owner if she wants to be notified on new versions by google play, and it's up to each phone's manufacturer if this is to be enabled by default.
If you however are in a situation where you "require" the user to update to the new version to be compatible with some form of protocol or you have a similar similar use case where you have a server component somewhere, you might want to notify the user of a potential version conflict in the UI based on information about what is the latest version.
This information can be grabbed directrly from google play, however as #Yahel pointed out in this question google play is a closed system with no official API, and you might need to rely on unpredictable undocumented API. There is an unofficial API library here.
This leaves only one option, which is to keep this information on your own server. If you allready have a serverside this might be trivial. Simply put the latest version in an XML file and retreive that at regular intervals from your code. If the version code is outdated, trigger the notification in your UI. Here is an example implementation for doing that.
I hope this was helpful :-)
I know this is an old question but still if people are coming here to check this question, Google is now providing official support for in-app notification for application update the full documentation can be found here
Use this : https://www.push-link.com/
Google Play will notify your users that the app has an update via the notification bar.
If you set up a notification system yourself, the likely result would be that, although the user is notified of an update sooner, when he/she goes to Google Play to install the update it will not yet be available. This is because there is a lag from the time you "publish" an app/update and the time until it appears on Play. Telling your users that there is an update when the update is unavailable would only lead to confusion and frustration.
My advice: stick with Google's update notification system and don't worry about trying to get users an update 15 minutes sooner.
Some people use Android Cloud-to-Device Messaging (C2DM) to notify their users of updates. I don't think I'd bother, since I think Google Play does a pretty good job of notifying me of updates already, and implementing C2DM adds a whole new dimension to writing an app (because it requires a server component). But maybe you want to offer your users a richer update notification than you get from Google Play.
#Davek804's answer above is wrong. android:versionCode is an integer value that represents the version of the application code, relative to other versions, so using "1.5b" there is incorrect. Use "15" (or "150") instead
Found a nice solution for your problem:
Let´s say you want to check for version updates manually on app start and notify your users for the new Update.
Step 1: Download android-market-api (not the .jar file, the full project!)
Step 2: After importing it to eclipse, write in your activity the following code:
MarketService ms = new MarketService(activity);
ms.level(MarketService.REVISION).checkVersion();
now, we need to modify MarketService.java, because it seems to be broken.
Step 3: rewrite callback method and add the following methods
protected void callback(String url, JSONObject jo, AjaxStatus status){
if(jo == null) return;
String googlePlayversion = jo.optString("version", "0");
String smartphone_version = "";
PackageInfo pInfo;
try {
pInfo = act.getPackageManager().getPackageInfo(act.getPackageName(), 0);
smartphone_version = pInfo.versionName;
} catch (NameNotFoundException e) {}
boolean new_version_avaible = compare(smartphone_version, googlePlayversion);
if(new_version_avaible){
showUpdateDialog(jo);
}
}
private static boolean compare(String v1, String v2) {
String s1 = normalisedVersion(v1);
String s2 = normalisedVersion(v2);
int cmp = s1.compareTo(s2);
String cmpStr = cmp < 0 ? "<" : cmp > 0 ? ">" : "==";
System.out.printf("result: "+"'%s' %s '%s'%n", v1, cmpStr, v2);
if(cmpStr.contains("<")){
return true;
}
if(cmpStr.contains(">")||cmpStr.contains("==")){
return false;
}
return false;
}
public static String normalisedVersion(String version) {
return normalisedVersion(version, ".", 4);
}
public static String normalisedVersion(String version, String sep, int maxWidth) {
String[] split = Pattern.compile(sep, Pattern.LITERAL).split(version);
StringBuilder sb = new StringBuilder();
for (String s : split) {
sb.append(String.format("%" + maxWidth + 's', s));
}
return sb.toString();
}
If you want to test it, modify googlePlayversion string to a higher version than your local one.
The source comparison method I used is from How do you compare two version Strings in Java?
There is also a very good approach for checking version and give user in app notification or when you want to forcefully update the application if you can decide the first connection of your app with the server.In the response of the first request you can send the current version of app stored on your server and then on client end you can take the appropriate action.
Advantages of this approach-:
1-No extra request for version no.
2-It is also applicable if you are downloading the app other than the google playstore.
3-you can also use this idea if you want to check the version at particular operation of your app ex- transaction(if you add a new payment gateway.)
Don't know if you want to walk extra miles. You can try out google appengine, which serve version number for your app and let you android app check the appengine to see if there is a new version when the application is launched. That way, it does not matter if your app is in google play market nor amazon app store nor if it is installed on the phone without those two via sideloading. It is not very hard to setup appengine just for serving your application version in json. Replace "Hello World" string with your app version name ...
This can be using a simple webservice just this is one of the way to acheive.
i.e., when ever the app launch hit that webservice with the current version of the user app and on the server you need to check whether any new version is available or not(Must maintain the newest version of the app) and send the corresponding response to the user. If any newer version is available prompt the user to download the newest version of the application and if no newest version is available then allow the user to continue.
Hope so atleast something must be useful to you.
There are two models that are basically used to tackle the issue.
Pull Based
Push Based
Its depends on the architecture or design of particular system that determines whether pull based or push mechanism is used.
For pull based model you just make one http request to concerned server regarding the new version of application. The current application version no can be saved in SQLLite in android application. This can be given to server and new version can be checked against it at the server.
For push mechanism you can use C2DM push notification service.. details of which are given at http://code.google.com/android/c2dm/
Generally when you upload a new application to Google play most users get a notification about an update, some will have the app automatically downloaded to their device, depending on the settings they have.
If you seriously want to make a notification from your app to ask them to update (so that everyone gets the notification, whatever their Google play settings are, then you will have to make a web service which returns the number of the newest version. You can then compare that inside your app and post a notification. You could use Google App Engine ( https://developers.google.com/appengine/) because that works with eclipse and java, which you probably already have.
I would not recommend this approach as it creates a lot of work for you to provide something that most users have already got.
i think this is too late but it can be help some one
public enum AppVersionUpgradeNotifier {
INSTANCE;
private static final String TAG = "AppVersionUpdateManager";
private static final String PREFERENCES_APP_VERSION = "pref_app_version_upgrade";
private static final String KEY_LAST_VERSION = "last_version";
private SharedPreferences sharedPreferences;
private VersionUpdateListener versionUpdateListener;
private boolean isInitialized;
public static synchronized void init(Context context, VersionUpdateListener versionUpdateListener) {
if (context == null || versionUpdateListener == null) {
throw new IllegalArgumentException(TAG + " : Context or VersionUpdateListener is null");
}
if (!INSTANCE.isInitialized) {
INSTANCE.initInternal(context, versionUpdateListener);
} else {
Log.w(TAG, "Init called twice, ignoring...");
}
}
private void initInternal(Context context, VersionUpdateListener versionUpdateListener) {
this.sharedPreferences = context.getSharedPreferences(PREFERENCES_APP_VERSION, Context.MODE_PRIVATE);
this.versionUpdateListener = versionUpdateListener;
this.isInitialized = true;
checkVersionUpdate();
}
private void checkVersionUpdate() {
int lastVersion = getLastVersion();
int currentVersion = getCurrentVersion();
if (lastVersion < currentVersion) {
if (versionUpdateListener.onVersionUpdate(currentVersion, lastVersion)) {
upgradeLastVersionToCurrent();
}
}
}
private int getLastVersion() {
return sharedPreferences.getInt(KEY_LAST_VERSION, 0);
}
private int getCurrentVersion() {
return BuildConfig.VERSION_CODE;
}
public void upgradeLastVersionToCurrent() {
sharedPreferences.edit().putInt(KEY_LAST_VERSION, getCurrentVersion()).apply();
}
public interface VersionUpdateListener {
boolean onVersionUpdate(int newVersion, int oldVersion);
}
}
use it on
public class MyApplication extends Application implements AppVersionUpgradeNotifier.VersionUpdateListener {
#Override
public void onCreate() {
super.onCreate();
AppVersionUpgradeNotifier.init(this,this);
}
#Override
public boolean onVersionUpdate(int newVersion, int oldVersion) {
//do what you want
return true;
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1.5b"
android:versionName="1.5b">
When you re-upload your app to Google Play, if these two attributes have been changed from the previous upload, Google Play will automatically send notifications to users who have installed your app. This is the AndroidManifest file.
One of my users let the cat out of the bag and told me they were using one of my free apps, which is monetized by ads, but they were blocking the ads with an ad blocker. They told me this mockingly, as if I can't do anything about it.
Can I do something about it? Is there a way to detect that ads are being blocked?
I am aware of one way that ad blocking works (on any computer really), they edit the hosts file to point to localhost for all known ad servers. For android this is located in the "etc/hosts" file.
For example, I use admob ads and a host file that I have taken from custom rom lists the folowing admob entries:
127.0.0.1 analytics.admob.com
127.0.0.1 mmv.admob.com
127.0.0.1 mm.admob.com
127.0.0.1 admob.com
127.0.0.1 a.admob.com
127.0.0.1 jp.admob.com
127.0.0.1 c.admob.com
127.0.0.1 p.admob.com
127.0.0.1 mm1.vip.sc1.admob.com
127.0.0.1 media.admob.com
127.0.0.1 e.admob.com
Now anytime a process tries to resolve the above addresses they are routed to the address listed to the left of them (localhost) in this case.
What I do in my apps is check this host file and look for any admob entries, if I find any I notify the user that I've detected ad blocking and tell them to remove admob entries from there and do't allow them use of the app.
After all what good does it do me if they're not seeing ads? No point in letting them use the app for free.
Here is a code snippet of how I achieve that:
BufferedReader in = null;
try
{
in = new BufferedReader(new InputStreamReader(
new FileInputStream("/etc/hosts")));
String line;
while ((line = in.readLine()) != null)
{
if (line.contains("admob"))
{
result = false;
break;
}
}
}
I vow that all ad supported apps should check this file. You do not need to be root in order to access it, but writing to it might be a different story.
Also, not sure if there is any other files that act the same on a linux based OS, but at any rate we can always check all of those files.
Any suggestions on improving this are welcome.
Also the app called "Ad Free android" needs root access, meaning that it most likely changes the hosts file in order to achieve its goal.
My code for this issue is thusly: -
try {
if (InetAddress.getByName("a.admob.com").getHostAddress().equals("127.0.0.1") ||
InetAddress.getByName("mm.admob.com").getHostAddress().equals("127.0.0.1") ||
InetAddress.getByName("p.admob.com").getHostAddress().equals("127.0.0.1") ||
InetAddress.getByName("r.admob.com").getHostAddress().equals("127.0.0.1")) {
//Naughty Boy - Punishing code goes here.
// In my case its a dialog which goes to the pay-for version
// of my application in the market once the dialog is closed.
}
} catch (UnknownHostException e) { } //no internet
Hope that helps.
As developers, we need to do the difficult job of empathizing with the users and find a middle ground between punishing the few who try to take advantage and the many who play by the rules. Mobile advertising is a reasonable way to allow someone to use a functional piece of software for free. The users who employ ad blocking techniques could be considered lost revenue, but if you take a look at the big picture, can also be those who spread the word about your application if they like it. A more gentle approach to running on systems with ads blocked is to display your own "house" ad. Create one or more banner images and display them in the same spot as your normal ad with an ImageView of the same height (e.g. 50dp). If you successfully receive an ad, then set your ImageView's visibility to View.GONE. You can even create a timer to cycle through several house ads to get the user's attention. Clicking on your ad can take the user to the market page to buy the full version.
Can you check to see if the ad loaded in your app?
Ad blockers work by preventing your app from downloading data. You could check the content length of the data in your ad frame to make sure there is data there.
If there is no data throw up a message and exit or warn you with an email.
It might not be as big an issue as you think since only a small percentage of people block ads.
The top two answers help you with only a particular (if, probably, the most popular) method of blocking ads. Root users can also block ads with a firewall on the device. WiFi users can block ads with an upstream firewall.
I suggest:
Don't reward ad-blocking users. Ensure that your layout reserves part of the display for an ad even if one can't be loaded. Or if you have a full-screen ad that plays for a bit, ensure that your app waits for a bit even if the ad can't be played. If you use notifications as adverts (you scum), notify the user when you fail to get such an advert. This could be read as "annoy all of your users", but your normal users know what they're getting, and your ad-blocking 'users' aren't wanted.
Ask ad-blockers to stop. The less proftable an industry that supplies what a user wants, the less that industry will supply what the user had wanted. An individual developer will find that he makes more money serving other users. You know this, and your users will think it obvious after you tell them, but it's still an economic argument - it's not intuitive. Have a backup ad that says something like, "This is my job. If you don't pay me, I'll get another one, and you won't get more apps like this from me."
There is nothing you can do that your users can't do better.
The only thing that comes to mind as remotely effective is to make the ads an inextricable part of the program, so that if they're blocked the user cannot make sense of/interact with the application.
Rather than checking for individual software installed or modified hosts file, my approach is using an AdListener like this and, if the ad fails to load due to NETWORK_ERROR, I just fetch some random always-online page (for the kicks, apple.com) and check if the pages loads successfully.
If so, boom goes the app.
To add some code, listener class would be something like:
public abstract class AdBlockerListener implements AdListener {
#Override
public void onFailedToReceiveAd(Ad arg0, ErrorCode arg1) {
if (arg1.equals(ErrorCode.NETWORK_ERROR)) {
try {
URL url = new URL("http://www.apple.com/");
URLConnection conn = url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
reader.readLine();
onAdBlocked();
} catch (IOException e) {}
}
}
public abstract void onAdBlocked();
}
And then each activity with an adView would do something like:
AdView adView = (AdView) findViewById(R.id.adView);
adView.setAdListener(new AdBlockerListener() {
#Override
public void onAdBlocked() {
AlertDialog ad = new AlertDialog.Builder(CalendarView.this)
.setMessage("nono")
.setCancelable(false)
.setNegativeButton("OK", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
System.exit(1);
}
})
.show();
}
});
I think it depends on the content provider for the ads. I know the AdMob SDK provides a callback when an ad request fails. I suspect that you might be able to register for this, then check for a connection in the callback - if there is a connection and you did not receive an ad - take note, if it happens more than once or twice, chances are likely your ads are being blocked. I have not worked with the AdSense for Mobile toolset from Google but it wouldn't surprise me if there was a similar callback mechanism.
There are two ways for a user to by pass a advertisement:
1) Use app without internet on.
2) With rooted phone and modified host file.
I made two tools that you can implement, see code below.
checkifonline(); is for problem 1:
public void checkifonline() {
boolean haveConnectedWifi = false;
boolean haveConnectedMobile = false;
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] netInfo = cm.getAllNetworkInfo();
for (NetworkInfo ni : netInfo) {
if (ni.getTypeName().equalsIgnoreCase("WIFI"))
if (ni.isConnected())
haveConnectedWifi = true;
if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
if (ni.isConnected())
haveConnectedMobile = true;
}
if(haveConnectedWifi==false && haveConnectedMobile==false){
// TODO (could make massage and than finish();
}
}
adblockcheck(); is for problem 2
private void adblockcheck() {
BufferedReader in = null;
boolean result = true;
try
{
in = new BufferedReader(new InputStreamReader(
new FileInputStream("/etc/hosts")));
String line;
while ((line = in.readLine()) != null)
{
if (line.contains("admob"))
{
result = false;
break;
}
}
} catch (UnknownHostException e) { }
catch (IOException e) {e.printStackTrace();}
if(result==false){
// TODO (could make massage and than finish();
}
}
This is an extension of a previous answer. The user has informed me that the app they are using is called AdFree Android. It can be found on the market. The app says it works by "nullifying requests to known hostnames serving ads."
I suggest that if you monetize any of your apps with ads, you check at startup for this program and give the user a nasty message, then terminate your app.
First, let me say that I believe that Ad Blocking, when it comes to applications, is actually a form of piracy. These apps are supported by the ads, and sometimes, a "paid license" to turn off ads and/or add features. By blocking ads, users are stealing potential revenue from the developer that took the time to create the app that you are using.
Anyhow, I want to add a way to help prevent the use of Ad Blockers. I use this method and I do not allow users to use the app if I detect an ad blocker. People get very angry and will give you poor ratings for it. But I also state very clearly in my applications descriptions that you will not be able to use the app if you have an adblocker.
I use the package manager to check if a specific package is installed. While this will not get all of the adblockers, if you keep "up to date" on some of the popular ones, you can get most of them.
PackageManager pm = activity.getPackageManager ();
Intent intent = pm.getLaunchIntentForPackage ( "de.ub0r.android.adBlock" );
if ( Reflection.isPackageInstalled ( activity, intent ) ) {
// they have adblock installed
}
Give your users a way to use the app without the ads. I personally find ads one of the most annoying things that could possibly happen on my computer, and I will gladly pay for an application if it spares me the insult of having ads thrown into my face. And I'm sure I'm not the only one.
I'm sure this answer won't be entirely popular with certain segments of developers, however consider if you fall into this category that perhaps your app doesn't deserve to exist on the app store. Please note that these are all implementable as code changes, no hackery or spyware like behavior required.
Basically, change the economics of your app. The User is Always Right - this is the attitude taken by one of the most successful advertising companies ever (Google). If your ads are being blocked by users, its because you suck, not because ads or ad-blockers suck.
http://books.google.com/books/about/The_User_is_Always_Right.html?id=gLjPMUjVvs0C
Make ads less annoying and in-your-face. Users react to poor/annoying advertisement, and the seedier your app looks and becomes, the more likely they are to ditch it anyways. I don't mind apps with ads in them as long as they aren't significantly impeding the functionality, and even better I like ads which are relevant to me. (http://www.nngroup.com/articles/most-hated-advertising-techniques/)
To detect that ads aren't being loaded, its not necessary to implement the spyware like activities mentioned by previous posters. Load an ad that has a confirmation code, and every once in awhile, insert a prompt asking for the confirmation code. The code doesn't have to be long or annoying, in fact it'd be enough to implement a captcha service with 3 or 4 letters/numbers.
(http://textcaptcha.com/api)
In addition to detecting failure of ads to load, make better ads. Instead of using an API like mobads (Do you even realize how seedy that sounds? Mobs? Really? Are we developers, the Russian Mafia?), enter a partnership with an ad company that allows you to embed ads directly from your app. It will make your overall app larger to install, and no, you can't guard against manual modification, but the changes suggested above don't guard against that either. And this will better support any paid versions of your app, which will be much more lightweight (and faster).
Thoroughly vet the ads you are displaying to the user, be open and transparent about your ad policies, and even allow users to inspect your ads and ad sources. The primary reason I'm ever concerned about ads is not because I hate ads, but because I worry that the poor quality developer responsible for this app is letting in viruses or other malware as well. Ask that an exception be made to the installed adblocker. Team up with ad blockers like AdBlock to get on their exceptions list. If you are a legit application, this shouldn't be a problem.
(http://www.cio.com/article/699970/6_Ways_to_Defend_Against_Drive_by_Downloads?page=1&taxonomyId=3089)
I re-iterate: all of the above changes are things you can legitimately do in code to prevent anti-ad behaviors. Ads are blocked for security reasons and visceral reactions, primarily, and sometimes bandwidth and performance, so make sure your ads don't invoke any of these problems, at the code level.
Finally I did want to touch on what Borealid said, which I re-iterated above; in the end it is a 'cat and mouse' game, because the user has ultimate authority and responsibility, both legally and morally, over their own property. A user can do whatever, including directly modify code on the fly. Of course, there are restrictions you can implement etc. but there are always ways to get around the problem. This is the ultimate problem (technically) with DRM (which is what you're trying to do). Rather than waste time and effort on this game, it is better to encourage users to keep ads around; they'll become your best, smartest anti-ad-blockers, for free.
For the case when there is no internet connection, I have followed this
tutorial
and I've build a "network state listener" like so:
private BroadcastReceiver mConnReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (noConnectivity == true)
{
Log.d(TAG, "No internet connection");
image.setVisibility(View.VISIBLE);
}
else
{
Log.d(TAG, "Interet connection is UP");
image.setVisibility(View.GONE);
add.loadAd(new AdRequest());
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
//other stuff
private ImageView image = (ImageView) findViewById(R.id.banner_main);
private AdView add = (AdView) findViewById(R.id.ad_main);
add.setAdListener(new AdListener());
}
#Override
protected void onResume()
{
registerReceiver(mConnReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
super.onResume();
}
#Override
protected void onPause()
{
unregisterReceiver(mConnReceiver);
super.onPause();
}
registerReceiver and unregisterReceiver have to be called in onResume and onPause respectively, as described here.
In your layout xml set up the AdView and an ImageView of your own choice, like so:
<com.google.ads.AdView xmlns:googleads="http://schemas.android.com/apk/lib/com.google.ads"
android:layout_alignParentBottom="true"
android:id="#+id/ad_main"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
googleads:adSize="BANNER"
googleads:adUnitId="#string/admob_id" />
<ImageView
android:id="#+id/banner_main"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"
android:layout_width="379dp"
android:layout_height="50dp"
android:visibility="gone"
android:background="#drawable/banner_en_final" />
Now, whenever the internet connection is available the ad will display and when its off the ImageView will pop-up, and vice-versa. This must be done in every activity in which you want ads to display.
As well as checking if admob can be resolved, what I do is present a page that basically advises that I have detected an adblocker, state that i understand the possible reasons why, then show some inbuilt ads of my own apps and ask for their kind support for continued development. :)