is there a way to disable hardware acceleration only for android 4.0.3?
Asked Answered
H

4

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.

Hughes answered 12/12, 2012 at 23:9 Comment(3)
There is a way to disable 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.Plumy
@Plumy 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?Hughes
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 type in the xml.Plumy
A
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

Alysiaalyson answered 13/12, 2012 at 0:13 Comment(2)
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.Hughes
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.Alysiaalyson
K
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

Kirwan answered 9/5, 2013 at 18:52 Comment(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."Broadleaf
K
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>
Klondike answered 25/3, 2014 at 18:50 Comment(2)
Is there a way to set "android:layerType" within the layout XML file, so that it will set the correct value using this method?Epos
How the system knows that isNotIceCreamSandwich version code?Madly
A
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

Alysiaalyson answered 13/12, 2012 at 0:13 Comment(2)
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.Hughes
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.Alysiaalyson
N
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!

Naga answered 8/6, 2013 at 17:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.