18

I have recently stumbled upon an issue with android 4.0.3, where Im getting the following Exception as soon as the application starts (on other android versions it works fine):

java.lang.NullPointerException
at android.view.GLES20RecordingCanvas.drawPatch(GLES20RecordingCanvas.java:97)
at android.graphics.NinePatch.draw(NinePatch.java:125)
at android.graphics.drawable.NinePatchDrawable.draw(NinePatchDrawable.java:189)
at android.widget.ImageView.onDraw(ImageView.java:892)
at android.view.View.draw(View.java:10978)
at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.ViewGroup.drawChild(ViewGroup.java:2885)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.View.getDisplayList(View.java:10415)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:842)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:1910)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1634)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)

This is related to having hardware acceleration enabled, as soon as I disable it on the manifest the application starts working just fine.

By doing a search I found a log (inside that doc search for "drawPatch") on some conversation of Romain Guy, where he discuss a little bit of what could be causing this, although there is no workaround or fix proposed, I wonder if I should disable hardware acceleration only for this version of android, or if there is a workaround for it?

Thanks for your time.

Aldo Reyes
  • 515
  • 1
  • 4
  • 12
  • 2
    There is a way to [disable](http://developer.android.com/guide/topics/graphics/hardware-accel.html) according to the API. This is the code they provide: `myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);` You're going to need an if statement that checks API version then use the above code. – A--C Dec 12 '12 at 23:13
  • @A--C thanks, that would require to do it for each view, is it possible to change it at the application level using code, I mean outside the AndroidManifest file? – Aldo Reyes Dec 12 '12 at 23:22
  • I don't think so, it seems you can only specify your app is harware accelerated and it's global, no specific API versions. One thing you can do is make a special API layout folder (layout-v13 or whatever 4.03's API is) and set each view's [layer](http://developer.android.com/reference/android/view/View.html#attr_android:layerType) type in the xml. – A--C Dec 12 '12 at 23:26

4 Answers4

25

You currently cannot disable hardware acceleration at the window level by code.

Only enable it. I suggest you to Disable it by default in your manifest:

<application android:hardwareAccelerated="false">
    <activity ... />
    <activity android:hardwareAccelerated="false" />
</application>

and then enable it to all the other versions:

if (Build.VERSION.SDK_INT != Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
            getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
        }

You can disable hardware acceleration for an individual view at runtime with the following code:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

This info is available in Android - Controlling Hardware Acceleration

João M
  • 1,939
  • 21
  • 14
  • 1
    Important: Android Developers says also that: "It is important to remember that this flag (refers to "FLAG_HARDWARE_ACCELERATED") must be set before setting the content view of your activity or dialog." – MBDevelop May 28 '20 at 13:50
18

I like the answer linked by @sgarman because it has minimal impact on the code and is easily maintainable. Just to expand on that link, here's what I did to disable hardware acceleration only for Android v4.0.3 and only for a certain activity and it worked for me (remember to add the xml headers specifying version and encoding to the various bool.xml files, as the wiki editor would not let me paste it in):

AndroidManifest.xml: identify the activity hosting the offending view, and insert this to that activity:

<activity
    android:hardwareAccelerated="@bool/isNotIceCreamSandwich"
    ...
</activity>

file path: res/values/bool.xml:

<resources>
    <bool name="isNotIceCreamSandwich">true</bool>
</resources>

file path: res/values-v14/bool.xml:

<resources>
    <bool name="isNotIceCreamSandwich">false</bool>
</resources>

file path: res/values-v16/bool.xml:

<resources>
    <bool name="isNotIceCreamSandwich">true</bool>
</resources>
Community
  • 1
  • 1
Phileo99
  • 5,581
  • 2
  • 46
  • 54
9

So A-C mentions this in his comment but let me elaborate.

You can create a boolean in a values file and stick it in the correct version folder. In your manifest under

Check out this post: https://plus.google.com/+AndroidDevelopers/posts/DcsFABkyuYM.

Looks like your going to want to target values-v15/bools.xml

http://developer.android.com/reference/android/os/Build.VERSION_CODES.html#ICE_CREAM_SANDWICH_MR1

sgarman
  • 6,152
  • 5
  • 40
  • 44
  • thank you, Ill try this, is this a common issue on 4.0.3? apparently hardware acceleration is not that stable on 4.0.3 for 2d views. – Aldo Reyes Dec 13 '12 at 00:30
  • I'm not sure, perhaps I jumped the gun by solving the question you asked instead of finding the actual solution to the acceleration issue. I would keep investigating before using this solution. – sgarman Dec 14 '12 at 01:37
5

This is a funny bug cause hardware acceleration is working (sometimes). I've been searching for the answer to this for the last couple days. It’s documented in ICS but I have noticed it in one of my test phones a Samsung Galaxy S3 running 4.1.2 Most people suggest turning off hardware acceleration. I didn't want to do that cause hardware acceleration makes my animations so silky smooth. So what I found was if I override draw() try and catch the null pointer exception the hardware accelerated features work (most of the time) and enough for you to never notice they aren't working or throwing the exception. In my case I was doing a custom view and had some custom drawing to do. The simple check for null doesn’t work (canvas==null) which is why this bug is a pain. So what I did was this:

    @Override
public void draw(Canvas canvas) {
    try{
        super.draw(canvas);
        mCanvas=canvas;
    }catch(java.lang.NullPointerException e){
        Log.e("mytag","MyCustomView::draw():"+e);
    }
    if(mCanvas==null)
        return;     
...

then silently try and caught any NPE on individual draw statements. First time I saw this bug I surrounded the entire draw() code in a try and catch. That worked for most phones but on the samsung s3 running 4.1.2 it was causing a flickering. So I used the above method and did silent try catch's on each call to someObject.draw(mCanvas) and that solved the problem entirely removing all flickering (disparity between hardware accelerated view cache and new canvas). Hope this helps! Way better than turning HWA off!