diff --git a/README.md b/README.md index 4ffaf7e..932b659 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,6 @@ dependencies { ``` ## Usage -Add **CHECK_LICENSE** permission to your app's Manifest: -```xml - -``` ### Verify Google Play Licensing (LVL) Google Play offers a licensing service that lets you enforce licensing policies for applications that you publish on Google Play. With Google Play Licensing, your application can query Google Play to obtain the licensing status for the current user. @@ -88,6 +84,58 @@ new PiracyChecker(this) **BE CAREFUL!!** This is a really restrictive technique since it will block your app from being installed using another market or directly installing the .apk on the device. It isn't recommended for most cases. +### Verify the use of certain pirate apps +If you want to check if user has pirate apps installed, you can use this code. +It will check for: Lucky Patcher, Freedom and CreeHack. + +```Java +new PiracyChecker(this) + .enableLPFCheck(true) + .start(); +``` + +If you want to check if user has third-party store apps installed, you can use this code. +It will check for: Aptoide, BlackMart, Mobogenie, 1Mobile, GetApk, GetJar and SlideMe. + +```Java +new PiracyChecker(this) + .enableStoresCheck(true) + .start(); +``` + +### Verify if app is a debug build. +```Java +new PiracyChecker(this) + .enableDebugCheck(true) + .start(); +``` + +### Verify if app is being run in an emulator +```Java +new PiracyChecker(this) + .enableEmulatorCheck(true) + .start(); +``` + +### Save the result of the license check in `SharedPreferences` + +There are two ways to do this: + +Define the `SharedPreferences` and the name of the preference where you want to save the result. +```Java +new PiracyChecker(this) + .saveResultToSharedPreferences(preferences, "valid_license"); + .start(); +``` + +Define the `SharedPreferences` name and the name of the preference where you want to save the result. +```Java +new PiracyChecker(this) + .saveResultToSharedPreferences("my_app_preferences", "valid_license"); + .start(); +``` + + ## Customizations Adding a callback to the builder allows you to customize what will happen when the license has been checked and manage the license check errors if the user is not allowed to use the app. Keep in mind that when using this method **you must be aware of blocking the app from unauthorized users**. @@ -103,13 +151,18 @@ Use the builder and add following: } @Override - public void dontAllow(PiracyCheckerError error) { + public void dontAllow(@NonNull PiracyCheckerError error, @Nullable PirateApp app) { // You can either do something specific when the user is not allowed to use the app // Or manage the error, using the 'error' parameter, yourself (Check errors at {@link PiracyCheckerError}). + + // Additionally, if you enabled the check of pirate apps and/or third-party stores, the 'app' param + // is the app that has been detected on device. App can be null, and when null, it means no pirate app or store was found, + // or you disabled the check for those apps. + // This allows you to let users know the possible reasons why license is been invalid. } @Override - public void onError(PiracyCheckerError error) { + public void onError(@NonNull PiracyCheckerError error) { // This method is not required to be implemented/overriden but... // You can either do something specific when an error occurs while checking the license, // Or manage the error, using the 'error' parameter, yourself (Check errors at {@link PiracyCheckerError}). @@ -119,10 +172,8 @@ Use the builder and add following: ## ProGuard ``` --keep class com.google.** --keep class autovalue.shaded.com.google.** --dontwarn com.google.** --dontwarn autovalue.shaded.com.google.** +-keep class com.github.javiersantos.** +-dontwarn com.github.javiersantos.** -keep public class com.android.vending.licensing.ILicensingService ``` @@ -134,11 +185,13 @@ Sure. You can use as many validation methods in the builder as you want. For exa new PiracyChecker(this) .enableGooglePlayLicensing("BASE_64_LICENSE_KEY") .enableSigningCertificate("YOUR_APK_SIGNATURE") + .enableLPFCheck(true) + .saveResultToSharedPreferences("my_app_preferences", "valid_license"); .start(); ``` ## License - Copyright 2016 Javier Santos + Copyright 2017 Javier Santos Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 76cd8df..666a125 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,8 +3,6 @@ xmlns:tools="http://schemas.android.com/tools" package="com.github.javiersantos.piracychecker.demo"> - - - \ No newline at end of file + diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro index 0f6fb84..cac4167 100644 --- a/library/proguard-rules.pro +++ b/library/proguard-rules.pro @@ -16,5 +16,8 @@ # public *; #} +# Lib +-keep class com.github.javiersantos.** +-dontwarn com.github.javiersantos.** # LVL -keep public class com.android.vending.licensing.ILicensingService \ No newline at end of file diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index c619089..6aed1ae 100644 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ - - + + + \ No newline at end of file diff --git a/library/src/main/java/com/github/javiersantos/piracychecker/LibraryUtils.java b/library/src/main/java/com/github/javiersantos/piracychecker/LibraryUtils.java index 46b6cda..6bf1932 100644 --- a/library/src/main/java/com/github/javiersantos/piracychecker/LibraryUtils.java +++ b/library/src/main/java/com/github/javiersantos/piracychecker/LibraryUtils.java @@ -4,15 +4,19 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; +import android.os.Environment; import android.support.v7.app.AlertDialog; import android.util.Base64; -import com.github.javiersantos.piracychecker.R; import com.github.javiersantos.piracychecker.enums.InstallerID; +import com.github.javiersantos.piracychecker.enums.PirateApp; +import java.io.File; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -45,7 +49,6 @@ public void onClick(DialogInterface dialogInterface, int i) { static String getCurrentSignature(Context context) { String res = ""; - try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context .getPackageName(), PackageManager.GET_SIGNATURES); @@ -56,7 +59,6 @@ static String getCurrentSignature(Context context) { } } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException ignored) { } - return res.trim(); } @@ -76,4 +78,70 @@ static boolean verifyInstallerId(Context context, List installerID) return installer != null && validInstallers.contains(installer); } -} + @SuppressLint("SdCardPath") + static PirateApp getPirateApp(Context context, boolean lpf, boolean stores) { + if (!lpf && !stores) return null; + for (PirateApp app : PiracyCheckerUtils.getApps()) { + if ((lpf && app.isLPF()) || (stores && !app.isLPF())) { + StringBuilder builder = new StringBuilder(); + for (String s : app.getPack()) { + builder.append(s); + } + String pack = builder.toString(); + PackageManager pm = context.getPackageManager(); + try { + PackageInfo info = pm.getPackageInfo(pack, PackageManager.GET_META_DATA); + if (info != null) return app; + } catch (PackageManager.NameNotFoundException ignored1) { + try { + Intent intent = pm.getLaunchIntentForPackage(pack); + if (PiracyCheckerUtils.isIntentAvailable(context, intent)) { + return app; + } + } catch (Exception ignored2) { + try { + if (PiracyCheckerUtils.hasPermissions(context)) { + File file1 = new File("/data/app/" + pack + "-1/base.apk"); + File file2 = new File("/data/app/" + pack + "-2/base.apk"); + File file3 = new File("/data/app/" + pack + ".apk"); + File file4 = new File("/data/data/" + pack + ".apk"); + File file5 = new File("/data/data/" + pack); + File file6 = new File(context.getFilesDir().getPath() + pack + + ".apk"); + File file7 = new File(context.getFilesDir().getPath() + pack); + File file8 = new File(Environment.getExternalStorageDirectory() + + "/Android/data/" + pack); + if (file1.exists() || file2.exists() || file3.exists() || + file4.exists() || file5.exists() || file6.exists() || + file7.exists() || file8.exists()) { + return app; + } + } + } catch (Exception ignored3) { + } + } + } + } + } + return null; + } + + static boolean isInEmulator() { + try { + boolean goldfish = PiracyCheckerUtils.getSystemProperty("ro.hardware") + .contains("goldfish"); + boolean emu = PiracyCheckerUtils.getSystemProperty("ro.kernel.qemu").length() > 0; + boolean sdk = PiracyCheckerUtils.getSystemProperty("ro.product.model").equals("sdk"); + if (emu || goldfish || sdk) { + return true; + } + } catch (Exception ignored) { + } + return false; + } + + static boolean isDebug(Context context) { + return ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + } + +} \ No newline at end of file diff --git a/library/src/main/java/com/github/javiersantos/piracychecker/PiracyChecker.java b/library/src/main/java/com/github/javiersantos/piracychecker/PiracyChecker.java index aa05c02..2582ee5 100644 --- a/library/src/main/java/com/github/javiersantos/piracychecker/PiracyChecker.java +++ b/library/src/main/java/com/github/javiersantos/piracychecker/PiracyChecker.java @@ -1,18 +1,23 @@ package com.github.javiersantos.piracychecker; -import com.github.javiersantos.licensing.AESObfuscator; -import com.github.javiersantos.licensing.LibraryChecker; -import com.github.javiersantos.licensing.LibraryCheckerCallback; -import com.github.javiersantos.licensing.ServerManagedPolicy; - import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; +import android.content.SharedPreferences; import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.StringRes; +import android.util.Log; +import com.github.javiersantos.licensing.AESObfuscator; +import com.github.javiersantos.licensing.LibraryChecker; +import com.github.javiersantos.licensing.LibraryCheckerCallback; +import com.github.javiersantos.licensing.ServerManagedPolicy; import com.github.javiersantos.piracychecker.enums.InstallerID; import com.github.javiersantos.piracychecker.enums.PiracyCheckerCallback; import com.github.javiersantos.piracychecker.enums.PiracyCheckerError; +import com.github.javiersantos.piracychecker.enums.PirateApp; import java.util.ArrayList; import java.util.List; @@ -20,12 +25,22 @@ @SuppressLint("HardwareIds") public class PiracyChecker { + // TODO: Rename if needed + protected static final String LIBRARY_PREFERENCES_NAME = "license_check"; + protected Context context; protected String unlicensedDialogTitle; protected String unlicensedDialogDescription; protected boolean enableLVL; protected boolean enableSigningCertificate; protected boolean enableInstallerId; + protected boolean enableLPFCheck; + protected boolean enableStoresCheck; + protected boolean enableEmulatorCheck; + protected boolean enableDebugCheck; + protected boolean saveToSharedPreferences; + protected SharedPreferences preferences; + protected String preferenceName; protected String licenseBase64; protected String signature; protected List installerIDs; @@ -67,6 +82,60 @@ public PiracyChecker enableInstallerId(InstallerID installerID) { return this; } + public PiracyChecker enableLPFCheck(boolean enable) { + this.enableLPFCheck = enable; + return this; + } + + public PiracyChecker enableStoresCheck(boolean enable) { + this.enableStoresCheck = enable; + return this; + } + + public PiracyChecker enableDebugCheck(boolean enable) { + this.enableDebugCheck = enable; + return this; + } + + public PiracyChecker enableEmulatorCheck(boolean enable) { + this.enableEmulatorCheck = enable; + return this; + } + + public PiracyChecker saveResultToSharedPreferences(SharedPreferences preferences, + @NonNull String preferenceName) { + this.saveToSharedPreferences = true; + this.preferenceName = preferenceName; + if (preferences != null) { + this.preferences = preferences; + } else { + try { + this.preferences = ((Activity) context).getPreferences(Context.MODE_PRIVATE); + } catch (Exception e) { + this.preferences = context.getSharedPreferences(LIBRARY_PREFERENCES_NAME, + Context.MODE_PRIVATE); + } + } + return this; + } + + public PiracyChecker saveResultToSharedPreferences(String preferencesName, + @NonNull String preferenceName) { + this.saveToSharedPreferences = true; + this.preferenceName = preferenceName; + if (preferencesName != null) { + this.preferences = context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE); + } else { + try { + this.preferences = ((Activity) context).getPreferences(Context.MODE_PRIVATE); + } catch (Exception e) { + this.preferences = context.getSharedPreferences(LIBRARY_PREFERENCES_NAME, + Context.MODE_PRIVATE); + } + } + return this; + } + public PiracyChecker callback(PiracyCheckerCallback callback) { this.callback = callback; return this; @@ -82,9 +151,14 @@ public void allow() { } @Override - public void dontAllow(PiracyCheckerError error) { + public void dontAllow(@NonNull PiracyCheckerError error, @Nullable PirateApp app) { + String dialogContent = unlicensedDialogDescription; + if (app != null) { + dialogContent = context.getString(R.string.pirate_app_found, app + .getName()); + } LibraryUtils.buildUnlicensedDialog(context, unlicensedDialogTitle, - unlicensedDialogDescription).show(); + dialogContent).show(); } }; verify(callback); @@ -95,9 +169,9 @@ protected void verify(final PiracyCheckerCallback verifyCallback) { // Library will check first the non-LVL methods since LVL is asynchronous and could take // some seconds to give a result if (!verifySigningCertificate()) { - verifyCallback.dontAllow(PiracyCheckerError.SIGNATURE_NOT_VALID); + verifyCallback.dontAllow(PiracyCheckerError.SIGNATURE_NOT_VALID, null); } else if (!verifyInstallerId()) { - verifyCallback.dontAllow(PiracyCheckerError.INVALID_INSTALLER_ID); + verifyCallback.dontAllow(PiracyCheckerError.INVALID_INSTALLER_ID, null); } else { if (enableLVL) { String deviceId = Settings.Secure.getString(context.getContentResolver(), @@ -108,12 +182,12 @@ protected void verify(final PiracyCheckerCallback verifyCallback) { libraryChecker.checkAccess(new LibraryCheckerCallback() { @Override public void allow(int reason) { - verifyCallback.allow(); + doExtraVerification(verifyCallback, true); } @Override public void dontAllow(int reason) { - verifyCallback.dontAllow(PiracyCheckerError.NOT_LICENSED); + doExtraVerification(verifyCallback, false); } @Override @@ -150,4 +224,40 @@ protected boolean verifyInstallerId() { return false; } -} + protected void doExtraVerification(final PiracyCheckerCallback verifyCallback, boolean + possibleSuccess) { + PirateApp app = LibraryUtils.getPirateApp(context, enableLPFCheck, enableStoresCheck); + if (possibleSuccess) { + if (enableDebugCheck && LibraryUtils.isDebug(context)) { + if (preferences != null && saveToSharedPreferences) + preferences.edit().putBoolean(preferenceName, false).apply(); + verifyCallback.dontAllow(PiracyCheckerError.USING_DEBUG_APP, null); + } else if (enableEmulatorCheck && LibraryUtils.isInEmulator()) { + if (preferences != null && saveToSharedPreferences) + preferences.edit().putBoolean(preferenceName, false).apply(); + verifyCallback.dontAllow(PiracyCheckerError.USING_APP_IN_EMULATOR, null); + } else if (app != null) { + if (preferences != null && saveToSharedPreferences) + preferences.edit().putBoolean(preferenceName, false).apply(); + verifyCallback.dontAllow(app.isLPF() ? PiracyCheckerError.PIRATE_APP_INSTALLED : + PiracyCheckerError.THIRD_PARTY_STORE_INSTALLED, app); + } else { + if (preferences != null && saveToSharedPreferences) + preferences.edit().putBoolean(preferenceName, true).apply(); + verifyCallback.allow(); + } + } else { + if (app != null) { + if (preferences != null && saveToSharedPreferences) + preferences.edit().putBoolean(preferenceName, false).apply(); + verifyCallback.dontAllow(app.isLPF() ? PiracyCheckerError.PIRATE_APP_INSTALLED : + PiracyCheckerError.THIRD_PARTY_STORE_INSTALLED, app); + } else { + if (preferences != null && saveToSharedPreferences) + preferences.edit().putBoolean(preferenceName, true).apply(); + verifyCallback.dontAllow(PiracyCheckerError.NOT_LICENSED, null); + } + } + } + +} \ No newline at end of file diff --git a/library/src/main/java/com/github/javiersantos/piracychecker/PiracyCheckerUtils.java b/library/src/main/java/com/github/javiersantos/piracychecker/PiracyCheckerUtils.java index 475494d..04bb946 100644 --- a/library/src/main/java/com/github/javiersantos/piracychecker/PiracyCheckerUtils.java +++ b/library/src/main/java/com/github/javiersantos/piracychecker/PiracyCheckerUtils.java @@ -1,16 +1,30 @@ package com.github.javiersantos.piracychecker; +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Build; +import android.support.v4.app.ActivityCompat; import com.github.javiersantos.piracychecker.enums.PiracyCheckerError; +import com.github.javiersantos.piracychecker.enums.PirateApp; +import java.util.ArrayList; +import java.util.List; + +@SuppressLint("StaticFieldLeak") +@SuppressWarnings("unchecked") public class PiracyCheckerUtils { public static String getAPKSignature(Context context) { return LibraryUtils.getCurrentSignature(context); } - public static PiracyCheckerError getCheckerErrorFromCode(int errorCode) { + static PiracyCheckerError getCheckerErrorFromCode(int errorCode) { switch (errorCode) { case 1: return PiracyCheckerError.INVALID_PACKAGE_NAME; @@ -29,4 +43,88 @@ public static PiracyCheckerError getCheckerErrorFromCode(int errorCode) { } } + static ArrayList getApps() { + ArrayList apps = new ArrayList<>(); + apps.add(new PirateApp("Lucky Patcher", new String[]{"c", "o", "m", ".", "c", "h", "e", + "l", "p", "u", "s", ".", "l", "a", "c", "k", "y", "p", "a", "t", "c", "h"})); + apps.add(new PirateApp("Lucky Patcher", new String[]{"c", "o", "m", ".", "d", "i", "m", + "o", "n", "v", "i", "d", "e", "o", ".", "l", "u", "c", "k", "y", "p", "a", "t", + "c", "h", "e", "r"})); + apps.add(new PirateApp("Lucky Patcher", new String[]{"c", "o", "m", ".", "f", "o", "r", + "p", "d", "a", ".", "l", "p"})); + apps.add(new PirateApp("Lucky Patcher", new String[]{"c", "o", "m", ".", "a", "n", "d", + "r", "o", "i", "d", ".", "v", "e", "n", "d", "i", "n", "g", ".", "b", "i", "l", + "l", "i", "n", "g", ".", "I", "n", "A", "p", "p", "B", "i", "l", "l", "i", "n", + "g", "S", "e", "r", "v", "i", "c", "e", ".", "L", "U", "C", "K"})); + apps.add(new PirateApp("Lucky Patcher", new String[]{"c", "o", "m", ".", "a", "n", "d", + "r", "o", "i", "d", ".", "v", "e", "n", "d", "i", "n", "g", ".", "b", "i", "l", + "l", "i", "n", "g", ".", "I", "n", "A", "p", "p", "B", "i", "l", "l", "i", "n", + "g", "S", "e", "r", "v", "i", "c", "e", ".", "L", "O", "C", "K"})); + apps.add(new PirateApp("Lucky Patcher", new String[]{"c", "o", "m", ".", "a", "n", "d", + "r", "o", "i", "d", ".", "v", "e", "n", "d", "i", "n", "g", ".", "b", "i", "l", + "l", "i", "n", "g", ".", "I", "n", "A", "p", "p", "B", "i", "l", "l", "i", "n", + "g", "S", "e", "r", "v", "i", "c", "e", ".", "L", "A", "C", "K"})); + apps.add(new PirateApp("Lucky Patcher", new String[]{"u", "r", "e", "t", ".", "j", "a", + "s", "i", "2", "1", "6", "9", ".", "p", "a", "t", "c", "h", "e", "r"})); + apps.add(new PirateApp("Freedom", new String[]{"c", "c", ".", "m", "a", "d", "k", "i", + "t", "e", ".", "f", "r", "e", "e", "d", "o", "m"})); + apps.add(new PirateApp("Freedom", new String[]{"c", "c", ".", "c", "z", ".", "m", "a", + "d", "k", "i", "t", "e", ".", "f", "r", "e", "e", "d", "o", "m"})); + apps.add(new PirateApp("CreeHack", new String[]{"o", "r", "g", ".", "c", "r", "e", "e", + "p", "l", "a", "y", "s", ".", "h", "a", "c", "k"})); + apps.add(new PirateApp("Aptoide", new String[]{"c", "m", ".", "a", "p", "t", "o", "i", + "d", "e", ".", "p", "t"})); + apps.add(new PirateApp("BlackMart", new String[]{"o", "r", "g", ".", "b", "l", "a", "c", + "k", "m", "a", "r", "t", ".", "m", "a", "r", "k", "e", "t"})); + apps.add(new PirateApp("Mobogenie", new String[]{"c", "o", "m", ".", "m", "o", "b", "o", + "g", "e", "n", "i", "e"})); + apps.add(new PirateApp("1Mobile", new String[]{"m", "e", ".", "o", "n", "e", "m", "o", + "b", "i", "l", "e", ".", "a", "n", "d", "r", "o", "i", "d"})); + apps.add(new PirateApp("GetApk", new String[]{"c", "o", "m", ".", "r", "e", "p", "o", + "d", "r", "o", "i", "d", ".", "a", "p", "p"})); + apps.add(new PirateApp("GetJar", new String[]{"c", "o", "m", ".", "g", "e", "t", "j", + "a", "r", ".", "r", "e", "w", "a", "r", "d", "s"})); + apps.add(new PirateApp("SlideMe", new String[]{"c", "o", "m", ".", "s", "l", "i", "d", + "e", "m", "e", ".", "s", "a", "m", ".", "m", "a", "n", "a", "g", "e", "r"})); + return apps; + } + + static boolean isIntentAvailable(Context ctx, Intent intent) { + final PackageManager mgr = ctx.getPackageManager(); + List list = mgr.queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY); + return list.size() > 0; + } + + static boolean hasPermissions(Context context) { + try { + return Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN || + !shouldAskPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) || + (!(ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, + Manifest.permission.READ_EXTERNAL_STORAGE))); + } catch (Exception e) { + return false; + } + } + + private static boolean shouldAskPermission() { + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M); + } + + private static boolean shouldAskPermission(Context context, String permission) { + if (shouldAskPermission()) { + int permissionResult = ActivityCompat.checkSelfPermission(context, permission); + if (permissionResult != PackageManager.PERMISSION_GRANTED) { + return true; + } + } + return false; + } + + static String getSystemProperty(String name) throws Exception { + Class systemPropertyClazz = Class.forName("android.os.SystemProperties"); + return (String) systemPropertyClazz.getMethod("get", new Class[]{String.class}).invoke + (systemPropertyClazz, name); + } + } \ No newline at end of file diff --git a/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerCallback.java b/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerCallback.java index 933df8f..527e391 100644 --- a/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerCallback.java +++ b/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerCallback.java @@ -1,5 +1,8 @@ package com.github.javiersantos.piracychecker.enums; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + public abstract class PiracyCheckerCallback { /** @@ -13,8 +16,11 @@ public abstract class PiracyCheckerCallback { * * @param error PiracyCheckerError.NOT_LICENSED, PiracyCheckerError.SIGNATURE_NOT_VALID or * PiracyCheckerError.INVALID_INSTALLER_ID + * @param app The {@link PirateApp} that has been detected on device. Returns null in no app + * was found. */ - public abstract void dontAllow(PiracyCheckerError error); + public abstract void dontAllow(@NonNull PiracyCheckerError error, @Nullable PirateApp app); + /** * Called if an error with the license check occurs. Check errors at {@link @@ -25,7 +31,7 @@ public abstract class PiracyCheckerCallback { * PiracyCheckerError.INVALID_PUBLIC_KEY, PiracyCheckerError.MISSING_PERMISSION or * PiracyCheckerError.UNKNOWN */ - public void onError(PiracyCheckerError error) { + public void onError(@NonNull PiracyCheckerError error) { } } \ No newline at end of file diff --git a/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerError.java b/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerError.java index 258981b..3f25dc2 100644 --- a/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerError.java +++ b/library/src/main/java/com/github/javiersantos/piracychecker/enums/PiracyCheckerError.java @@ -4,13 +4,18 @@ public enum PiracyCheckerError { NOT_LICENSED("This user is not using a licensed application from Google Play."), SIGNATURE_NOT_VALID("This app is using another signature. The original APK has been modified."), INVALID_INSTALLER_ID("This app has been installed from a non-allowed source."), + USING_DEBUG_APP("This is a debug build."), + USING_APP_IN_EMULATOR("This app is being used in an emulator."), + PIRATE_APP_INSTALLED("At least one pirate app has been detected on device."), + THIRD_PARTY_STORE_INSTALLED("At least one third-party store has been detected on device."), // Other errors + NO_CONNECTION_FOUND("Error contacting licensing server."), INVALID_PACKAGE_NAME("Application package name is invalid."), - NON_MATCHING_UID("Application UID doesn't match."), + NON_MATCHING_UID("Application UID doesn\'t match."), NOT_MARKET_MANAGED("Not market managed error."), CHECK_IN_PROGRESS("License check is in progress."), INVALID_PUBLIC_KEY("Application public key is invalid."), - MISSING_PERMISSION("Application misses the 'com.android.vending.CHECK_LICENSE' " + + MISSING_PERMISSION("Application misses the \'com.android.vending.CHECK_LICENSE\' " + "permission."), UNKNOWN("Unknown error."); diff --git a/library/src/main/java/com/github/javiersantos/piracychecker/enums/PirateApp.java b/library/src/main/java/com/github/javiersantos/piracychecker/enums/PirateApp.java new file mode 100644 index 0000000..76c41e6 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/piracychecker/enums/PirateApp.java @@ -0,0 +1,29 @@ +package com.github.javiersantos.piracychecker.enums; + +public class PirateApp { + private String name; + private String[] pack; + + public PirateApp(String name, String[] pack) { + this.name = name; + this.pack = pack; + } + + public void setPack(String[] pack) { + this.pack = pack; + } + + public String getName() { + return name; + } + + public String[] getPack() { + return pack; + } + + public boolean isLPF() { + return (name.equalsIgnoreCase("Lucky Patcher") || name.equalsIgnoreCase("Freedom") || + name.equalsIgnoreCase("CreeHack")); + } + +} \ No newline at end of file diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index 326daee..0481f10 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ This app is not licensed This application is not licensed nor valid. Please download the app from a trusted source. + License is invalid because we have found you have %1$s app installed on your device. Close - + \ No newline at end of file