LVL licensing in a Live Wallpaper? - android

Has anybody had success integrating the Licensing Verification Library (LVL) with a Live Wallpaper? If it were just running an Activity, it'd be crystal clear to just extend my Activity from the Licensing Activity, which in turn extends Activity. But Live Wallpapers are a Service, and I'm not sure how the two are intended to interact.
I'm using code derived from this: http://www.droidforums.net/forum/android-app-developers/69899-market-license-easy-implementation-protect-your-apps.html which seems to be the code that nearly everything I can find on the web refers to.
I notice that wallpaper settings are an activity, and I have those working properly, but for some reason I can't grok the Licensing stuff...

It's actually really quite simple, you don't need to use any Activity class to implement licensing into a WallpaperService.
Make sure you've followed the directions carefully at http://developer.android.com/guide/publishing/licensing.html
Here's how I did it:
Your extended Engine class should include something similar to the following... (code not essential to your question has been removed)
class startYourEngines extends Engine {
public startYourEngines() {
super();
licenseStatus(); //custom license check method (for modularity)
//the rest of your engine would go here
}
public void onDestroy() {
super.onDestroy();
licenseChecker.onDestroy(); //we call this to close IPC connections
}
//prep work
private static final String BASE64_PUBLIC_KEY = //OMITTED//;
private LicenseCheckerCallback licenseCallback;
private LicenseChecker licenseChecker;
private byte[] salt = "rAnd0mStr!ng".getBytes();
private AESObfuscator aes;
private String deviceId;
//our custom license check method
private void licenseStatus() {
deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
aes = new AESObfuscator(salt, getPackageName(), deviceId);
licenseCallback = new licenseVerification();
licenseChecker = new LicenseChecker(context, new ServerManagedPolicy(context, aes), BASE64_PUBLIC_KEY);
licenseChecker.checkAccess(licenseCallback);
}
//our callback method
private class licenseVerification implements LicenseCheckerCallback {
#Override
public void allow() {
//allow full app use
}
#Override
public void dontAllow() {
//prevent or limit app use
}
#Override
public void applicationError(ApplicationErrorCode errorCode) {
//error handling here
}
}
}
Licensing on the Android platform was created with versatility in mind. Just be sure to read through the documentation, and you shouldn't have any issues.

I have only written applications that start activities, but looking at my source code, it seems that the only reason that you would have to have an Activity do the license check is to show dialogs.
In all of the examples available on line, the LicenseCheckerCallback implementation always shows a dialog in the allow() and dontAllow() methods. Why not just show a toast in dontAllow() and exit your wallpaper service (call stopSelf(YourService.this))?
Let me know if you want more information, because I dont think you are limited to only using an activity for license checking. As an aside, make sure that you dont keep whole strings, etc in your app or in the preferences. Anyone with root access can access your preferences and if your app is decompiled, your strings are visible...

I think I've actually got it working now. I'm extending LicenseCheckActivity to my own Activity class that I'm calling in the manifest file with the usual MAIN action and LAUNCH category. I instantiate my class, do the license check, and then either allow the wallpaper to function or not based on that result (though the best way to do that is still something I need to sort out).
It almost seems too easy that I think I must be missing something. I'd appreciate anybody with experience with selling a licensed live wallpaper on the Android Market to share whatever wisdom they care to.

Related

Wait until permisison request result received in Android

I've seen SO question Can you request permissions synchronously in Android Marshmallow (API 23)'s runtime permissions model?. The answer is no.
Hence, I added a code as below (simplified version):
public class MyActivity ... {
private boolean hasGotPermissionRequestResult = false;
#Override
public void onCreate(...) {
if (ContextCompat.checkSelfPermission(...) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermission(...);
while (!hasGotPermissionRequestResult) {}
}
}
#Override
public void onRequestPermissionResult(...) {
// whether granted or not
hasGotPermissionRequestResult = true;
}
}
However, I am not sure whether my approach is nice, safe and efficient.
Well, what you trying to achieve simply ain't possible, however there are several ways to overcome this:
Only trigger the method you wanna call when the permission is granted.
If you'd like to make the User only uses your app because that particular permission is so important that your app will not function without it, then use an educated screen to tell the users why you would want to use this permission in an intro screen kinda way.
I've created a library just for this kind of scenario where the library simplify the Permissions for you, it can be also used as a stand Alone Activity that has an Intro to your permission. you could check it out in Github PermissionHelper Github

Design application using more confuse code?

Recently I had opened some real apps by using this
So I'm getting the source code from that. In those source code, I found that most of the code is designed like this
public class LockActivity extends Activity {
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
if (GlobalDataHolder.m9617e()) {
bm.m8771b(getApplicationContext(), getPackageManager());
finish();
}
}
protected void onResume() {
super.onResume();
if (GlobalDataHolder.m9617e()||this.f4719a.m9124j()) {
bm.m8771b(getApplicationContext(), getPackageManager());
finish();
return;
}
startActivity(new Intent(getApplicationContext(), LaunchActivity.class));
}
public void onPause() {
super.onPause();
}
public void onDestroy() {
super.onDestroy();
}
}
And also the java file named by Garbled text such as
aa.java
bh.java
cj.java
My question is
1) Why those developer create the function named 'm8771b','m9617e'
2) Why most of apps is designed like that?
3) Is this more secure for avoid other to copy their code?
4) Should we also design the application like that?
5) How they can remember where they put the function?
People don't write code like that... unless they are either a savant or inexperienced. Using seemingly random strings of methods/class names is something called Obfuscation, which means to hide the real meaning of something in order to make it difficult to read.
Obfuscation Wiki as it pertains to software development
There are programs out there, like ProGuard which do this for us. Its purpose is to both compact and obscure code. That way it is difficult for someone to decompile and reconstruct the project without pouring over what it does (depending on complexity) endlessly.
Since Java always compiles into bytecode, it is predictable in the way in which it can be decompiled and much more standard that a write-once compile-anywhere language. ProGuard helps protect intellectual property or proprietary software and keep people from just stealing code.

Is DexGuard tamper and Environment detection helpful?

I am very new to DexGuard and Proguard. I was going through their documentation and sample examples. They have dexguard_util which helps you detect if the application is tampered with and also helps in detecting if it is running in the environment it is supposed to run. The document suggests that this tamper and environment detection be encrypted using the following code is dexgaurd-project.txt.
-encryptclasses A$D
-encryptstrings A$D
follwing is the activity
public class A extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
new D().c();
}
private class D
{
public void c()
{
//some code to which detects the tampering and environment and takes action accordingly
}
}
}
What if a hacker inject this line of code.
public class A extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//code commented by hacker
//new D().c();
}
private class D
{
public void c()
{
//some code to which detects the tampering and environment and takes action accordingly
}
}
}
Then my application will run without running those tests which I think is a big problem. Is my understanding of how reverse engineering works wrong or there are better ways of doing this. Please share better methods of doing this if they exist. Thanks in advance. Note that public class A cannot be encrypted as it is an entry point and is kept using this command in progaurd-project.txt
-keep class somepackage.A
When it comes to anti-tampering, it is important to keep in mind that their goal is not to stop any and all potential tampering efforts, but, rather, it's just a matter of raising the security bar of the target high enough to dissuade most attackers.
With that said, the
A bit of a tangent:
The document suggests that this tamper and environment detection be encrypted using the following code is dexgaurd-project.txt.
Class encryption does prevent basic static analysis of the application package, e.g. simply unzipping the package and loading it in jd-gui. However, as this answer shows, it's trivial to circumvent: one only has to hook into the static method that decrypts the apk on load, and dump it. But this allows the security bar to be raised.
Now back to your original question:
What if a hacker inject this line of code.
As an attacker, that would be the next step. However, that would require repackaging the app, and signing it with the hacker's signing key. Therefore, it is necessary to combine Dexguard's anti-tampering measures like checking the apk signature.
Is DexGuard tamper and Environment detection helpful?
In summary, yes, it is helpful in as far as it raises the bar above the vast majority of apps out there. But it's no silver bullet.

Check for access to notifications using NotificationListenerService

I'm using the >=4.3 NotificationListenerService to access notifications. On the first start, my app takes the user to the "Access Notifications" system panel, but I'd like to take the user there whenever the checkbox for my app in "Access Notifications" is disabled. I haven't found a isNotificationAccessEnabled()-method anywhere, but I definitely know that it's possible because apps like Krome do this, too.
Edit June 15th, 2016
I'm not sure which version of the support library this was added to, but it looks like this functionality is now built in. Simply use:
NotificationManagerCompat.getEnabledListenerPackages(context); (link to docs)
This returns a Set<String> that you can iterate through to find your package name. Note however that I haven't personally tested this. But it looks like it's probably preferred to use this in place of my old solution below.
Old Solution
This code is working for my app:
ContentResolver contentResolver = context.getContentResolver();
String enabledNotificationListeners = Settings.Secure.getString(contentResolver, "enabled_notification_listeners");
String packageName = context.getPackageName();
// check to see if the enabledNotificationListeners String contains our package name
if (enabledNotificationListeners == null || !enabledNotificationListeners.contains(packageName))
{
// in this situation we know that the user has not granted the app the Notification access permission
throw new Exception();
}
else
{
doSomethingThatRequiresNotificationAccessPermission();
}
Typical values that I've seen for the enabledNotificationsListeners String look like this:
User has given none of their apps Notification access permission
null or ""
User has given one app Notification access permission
"com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"
User has given two apps Notification access permission
"com.scootrnova.android/com.scootrnova.android.ListenerService:com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"
This implementation is very straightforward and works great :)
P.S. I got the idea to use the hardcoded "enabled_notification_listeners" String from this answer.
Starting with Android 8.1 (SDK 27) you can call isNotificationListenerAccessGranted on the NotificationManager. This is the correct API to use. Older Android versions should use getEnabledListenerPackages as a second best option. Relying on your listener callbacks can give incorrect results. See explanation below.
Im developer of Krome. What have I done to check if service is enabled is add public static variable that changes to true in onBind method and to false in unbind. That is how this service work.
Edit:
public static boolean isNotificationAccessEnabled = false;
#Override
public void onListenerConnected() {
isNotificationAccessEnabled = true;
}
#Override
public void onListenerDisconnected() {
isNotificationAccessEnabled = false;
}
Works well with slightly modified #Damians answer
public class NotifyListener extends NotificationListenerService{
public static boolean listnerConnected = false;
#Override
public IBinder onBind(Intent intent) {
Log.d(name,"onBind Called");
listnerConnected = true;
return super.onBind(intent);
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.e("destroy", "called");
listnerConnected = false;
}
}
Starting with Android 8.1 (SDK 27) you can call isNotificationListenerAccessGranted on the NotificationManager. This is the correct API to use, not the one of the accepted answer. See explanation below.
Like shai tibber also already said the accepted answer is incorrect.
onListenerConnected() and onListenerDisconnect() can get called even when there is no NotificationListener access granted. So relying on this callbacks to set a boolean will give wrong results. And getEnabledListenerPackages(context‌​) will just return all the packages that have an enabled notification listener defined in there AndroidManifest (android:enabled=true). It's NOT directly related to the user access. The documentation states exactly that:
Get the set of packages that have an enabled notification listener component within them.

android: Is it possible to sell add-ons for apps in the Market?

I would like to distribute my app for free, and then sell extra features that can be added-on later. Is it possible to do this?
If you're talking about in-app payment, you should take a look at PayPal, which offers In-App-Payment for Android:
http://www.x.com
https://www.x.com/community/ppx/sdks
If you want to distribute your app via Android Market, you would need to offer each add-on as an invididual app. Probably not a convenient way.
Yes you can do it. There are addons all over the market for the better keyboard app.
You have different ways you can do this, here are two ways I already tried.
1) You could implement all the features in the app and a key app that unlocks this features.
Here is a simple and insecure implementation, the key app and the main app need to be signed with the same key:
public boolean isPackageAvailable(String packageName) {
int sigMatch = getPackageManager().checkSignatures(getPackageName(), packageName);
return sigMatch == PackageManager.SIGNATURE_MATCH;
}
Check MarketEnabler on market-enabler.googlecode.com to see how I used it (not not a secure way but a starting point).
2) You include the plugin app as intent into a subview so it looks like just one app splitted to multiple apk's.
Check http://speakerproximity.googlecode.com where I used it to include the settings view inside the mainview:
....
public class SpeakerProximity extends ActivityGroup {
....
mainLayout.addView(getViewFromIntent("preferences", new Intent(
this, PreferenceScreen.class)));
....
public View getViewFromIntent(String tag, Intent intent) {
/** start an activity inside an ActivityGroup and get the window handler **/
final Window w = getLocalActivityManager().startActivity(tag, intent);
/** extract the view out of the window handler **/
final View wd = w != null ? w.getDecorView() : null;
return wd;
}
...
Note that I extend ActivityGroup and not Activity ;-)

Categories

Resources