Sometimes in AOSP sources I see private static final boolean debug flag with false as ïts value. And there are debug output if this flag is true. Something like this:
private static final boolean DEBUG_DRAW = false;
private static final Paint DEBUG_DRAW_PAINT;
static {
DEBUG_DRAW_PAINT = DEBUG_DRAW ? new Paint() : null;
if (DEBUG_DRAW_PAINT != null) {
DEBUG_DRAW_PAINT.setAntiAlias(true);
DEBUG_DRAW_PAINT.setColor(Color.MAGENTA);
}
}
Who and how uses it? Is it possible to switch this flag somehow and take debug output of AOSP classes?
Everything is possible with Java and Reflection
Pros:
I don't think there is anything more powerfull than that
Cons:
This technique will be executed at runtime so any code executed before this (e.g. classes loading)... well, is already executed. So you won't see the effects
Slow at runtime
Dangerous. Use it carefully
You can modify any value using this:
Class<?> klass = ...
Field field = klass.getDeclaredField("DEBUG_DRAW");
field.setAccesible(true);
field.set(
null, // as this is an static attribute we don't need anything here...
true // set true as new value
);
As I stated before reflection is a dangerous technique so that snipped will throw several exceptions if used wrong so you will have to handle them
Related
My target is to mock Build.Version.SDK_INT with Mockito. Already tried:
final Build.VERSION buildVersion = Mockito.mock(Build.VERSION.class);
doReturn(buildVersion.getClass()).when(buildVersion).getClass();
doReturn(16).when(buildVersion.SDK_INT);
Problem is that: when requires method after mock, and .SDK_INT is not a method.
So far from other questions similar to this one it looks like you have to use reflection.
Stub value of Build.VERSION.SDK_INT in Local Unit Test
How to mock a static final variable using JUnit, EasyMock or PowerMock
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
...and then in this case use it like this...
setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16);
Another way around would be to create a class that accesses/wraps the field in a method that can be later mocked
public interface BuildVersionAccessor {
int getSDK_INT();
}
and then mocking that class/interface
BuildVersionAccessor buildVersion = mock(BuildVersionAccessor.class);
when(buildVersion.getSDK_INT()).thenReturn(16);
This works for me while using PowerMockito.
Whitebox.setInternalState(Build.VERSION.class, "SDK_INT", 16);
Don't forget to type
#PrepareForTest({Build.VERSION.class})
In case of java.lang.ExceptionInInitializerError , use 'SuppressStaticInitializationFor' to suppress any static blocks in the class. Usable example as follows:
#SuppressStaticInitializationFor({ "android.os.Build$VERSION", "SampleClassName" )}
Be careful inner class must use $ instead of Dot .
I want to use an android internal class, com.android.internal.widget.LockPatternUtils .
I searched for examples and I got this:
LockPatternUtils lpu = new LockPatternUtils(this.getContentResolver());
However, i cant import, autimport does not appear and manually doing
import com.android.internal.widget.LockPatternUtils
doesnt work.
How is this handled? I think there was something about creating an interface but not sure about it
EDIT: I got this:
boolean patternLocked = android.provider.Settings.System.getInt(
getContentResolver(),Settings.System.LOCK_PATTERN_ENABLED, 0)==1;
That works for the pattern lock, but i cant know about the pin or password lock
Use reflection to access the internal Android method getActivePasswordQuality (line 350 of LockPatternUtils.java) and compare the int it returns to the int for any of the DevicePolicyManager Constants:
protected boolean isSecure() {
String LOCK_PATTERN_UTILS = "com.android.internal.widget.LockPatternUtils";
try {
Class<?> lockPatternUtilsClass = Class.forName(LOCK_PATTERN_UTILS);
Object lockPatternUtils = lockPatternUtilsClass.getConstructor(Context.class).newInstance(this);
Method method = lockPatternUtilsClass.getMethod("getActivePasswordQuality");
int lockProtectionLevel = Integer.valueOf(String.valueOf(method.invoke(lockPatternUtils)));
// Then check if lockProtectionLevel == DevicePolicyManager.TheConstantForWhicheverLevelOfProtectionYouWantToEnforce, and return true if the check passes, false if it fails
}
catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
How is this handled?
Those classes are only available as part of full firmware builds, not from Android SDK apps.
You can not use Android internal classes, they do not come with the public SDK.
You can build your own SDK exposing them more or less as they do here How do I build the Android SDK with hidden and internal APIs available?
This is not recommended because you will have no guarantees.
I want to make development easier by implementing a configuration parameter that determines whether the app should be run in 'DEV' mode or 'PROD' mode.
I want this parameter to be accessible from any file (based on this parameter different chunks of code will be executed).
What's the most practical way to store this parameter (which isn't accessible or changeable by the user)?
How can I access it from within the application?
Starting with ADT 17 (IIRC), you have this automatically as part of the auto generated BuildConfig class.
The DEBUG field is always true when developing, but when you export a signed or unsigned apk, it is set to false. You can use it as:
if(BuildConfig.DEBUG) {
//Debug mode
}
Or the other way around:
if(!BuildConfig.DEBUG) {
//Release mode
}
You can use an enum:
public enum BuildType {
Release, Pilot, Debug;
}
And assign it to a global variable:
public static final BuildType BUILD_TYPE = BuildType.Debug;
You can even create some methods in the enum that allow you
switch over very specific parts of your application.
Now you can do stuff like this:
if (MyApplication.BUILD_TYPE != BuildType.Release) {
// some code that does not go in the release
}
A static field in one of your Activity ? Or I am missing something ?
public static boolean isDev = true;
You can set it in the onCreate of your main activity.
You can create a new class and add your variable there.
Also you can add some methods which will display some details about your app in dev mode.
public class Console{
public final static boolean isDev = true;
public static error(String tag, String msg){
if(isDev){
Log.e(TAG, msg);
}
}
}
is it safe to write such compatible code on Android?
if (Build.os.SDK_INT >= 11) {
newClass instance = new newClass();
....
}
else {
oldClass instance = new oldClass();
....
}
one of my colleagues argue with me that ClassNotFoundException might be thrown up when running the above code since ClassLoader is attempting to load newClass on an android os device which is below android 11. But I've tried couple times, and didn't see this happen.
After googling around for couple hours, I didn't find any information on how and when android default classLoader loads a specific class.
You should check the compatability like the following... It gives you more accurate than the above:
private static int currentApi = 0;
public static int getApiLevel() {
if (currentApi > 0) {
return currentApi;
}
if (android.os.Build.VERSION.SDK.equalsIgnoreCase("3")) {
currentApi = 3;
} else {
try {
Field f = android.os.Build.VERSION.class.getDeclaredField("SDK_INT");
currentApi = (Integer) f.get(null);
} catch (Exception e) {
return 0;
}
}
return currentApi;
}
you can alway use reflection to check if the class exists:
try {
Class.forName("yourclass")
} catch (ClassNotFoundExecption) {
oldClass instance = new oldClass();
}
Yes, this is safe to do on recent versions of Android. I want to say froyo and above, but it may have been even earlier than that. I don't recall for sure.
What happens is that dalvik performs a verification pass on the dex file at install time. For any classes/methods/fields that it can't resolve, it replaces those accesses with an instruction that throws a VerifyError.
In your example, if that code got loaded on, e.g. api 10, newClass instance = new newClass() would conceptually be replaced with throw new VerifYError(). So as long as that branch never gets executed at runtime, everything is good.
Short answer - don't do it.
Most VMs only load a class when it is absolutely needed. However a class loader is allowed to cache binary representation of classes beforehand[1].
Class loaders are allowed to cache binary representations of types,
load types early in anticipation of eventual use, or load types
together in related groups.
[1] - http://www.artima.com/insidejvm/ed2/lifetype2.html
[2] - http://developer.android.com/tools/extras/support-library.html
Edit - Have you checked if the class you need is available as part of the android support package ? [2]
I know In-App billing is new in Android and I would like to use it, but the version requirements make me think twice whether it's worth the effort. I would appreciate any input from those who have implemented or worked with In App Billing in detail.
I still have 10% 1.5 users. In app billing requires at least 1.6 to work. Does that mean 1.5 users will crash immediately? If not, at what point does it fail? I don't want to write a bunch of hacky code to stay compatible with 1.5 users.
If user reinstalls the app, are their app purchases remembered?
At what point does it fail if you don't have the required Market version?
Thanks.
Regarding version support, you'll have write some extra code to detect the device OS version (see android.os.Build.VERSION) so make sure it will run on 1.5 devices. I strongly suggest isolating that code in its own class, and only instantiate that class after your version check. That way your code stays clean (not "hacky") and you don't accidentally reference a 1.6+ class from a class field. In my code, I have version test classes that look like this:
public class Android8 {
private static final String TAG = "Android8";
// public test variables
public static final boolean IS_V8;
public static final boolean AT_LEAST_V8;
private static final Object pimpl;
static {
int sdk_int = 0;
try {
Field field = Build.VERSION.class.getField( "SDK" );
String sdk_str = (String)field.get( null );
sdk_int = Integer.parseInt( sdk_str );
} catch( Throwable e ) {
}
IS_V8 = (sdk_int==8);
AT_LEAST_V8 = (sdk_int>=8);
if( AT_LEAST_V8 ) {
pimpl = new Implementation();
} else {
pimpl = null;
}
}
// Version safe interface
public static void Camera_setDisplayOrientation( Camera camera, int degrees ) {
if( AT_LEAST_V8 )
((Implementation)pimpl).Camera_setDisplayOrientation( camera, degrees );
}
// Will cause a verify error if loaded in a pre Android8 environment
private static final class Implementation {
public static void Camera_setDisplayOrientation( Camera camera, int degrees ) {
camera.setDisplayOrientation( degrees );
}
}
}
Question 2: NO, if items are UNMANAGED. Yes if they are.
That's the point with managed items, let's the Google's servers manage (remenber) the purchased items for this sort of cases.
(The "manage by user account" purchase type is useful if you are selling items such as game levels or application features. These items are not transient and usually need to be restored whenever a user reinstalls your application, wipes the data on their device, or installs your application on a new device.)
from: http://developer.android.com/guide/market/billing/billing_admin.html#billing-purchase-type