Sunday, October 14, 2012

Conversion to Dalvik format failed with error 1 (Dx local variable type mismatch)

Recently I got infamous "Conversion to Dalvik format failed with error 1" message while I was trying to import my own (obfuscated and optimized) JAR to one of my projects. The full message is quoted bellow:

EXCEPTION FROM SIMULATION:
[2012-10-09 18:50:04 - AnotherTest] Dx local variable type mismatch: attempt to set or access a value of type java.lang.Object using a local variable of type int. This is symptomatic of .class transformation tools that ignore local variable information.

[2012-10-09 18:50:04 - AnotherTest] Dx ...at bytecode offset 00000019
locals[0000]: Lbiz/binarysolutions/signature/CaptureBase;
locals[0001]: I
locals[0002]: Landroid/view/KeyEvent;
stack[0002]: Lbiz/binarysolutions/signature/CaptureBase;
stack[0001]: Lbiz/binarysolutions/signature/CaptureBase;
stack[top0]: Lbiz/binarysolutions/signature/CaptureBase;
...while working on block 0016
...while working on method onKeyDown:(ILandroid/view/KeyEvent;)Z
...while processing onKeyDown (ILandroid/view/KeyEvent;)Z
...while processing biz/binarysolutions/signature/CaptureBase.class

[2012-10-09 18:50:04 - AnotherTest] Dx 1 error; aborting
[2012-10-09 18:50:04 - AnotherTest] Conversion to Dalvik format failed with error 1
[2012-10-09 18:50:04 - AnotherTest] Dx 

Obviously, it was ProGuard's fault since importing the original JAR file went without any problems. Although the message (quoted part marked in bold) was cryptic at first, the clue that it happened in my onKeyDown method (also marked in bold) was enough to start digging.

So the original onKeyDown looked as following:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
  if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
    if (signatureView.isModified()) {
 Toast.makeText(this, getToastMessageID(), Toast.LENGTH_LONG)
          .show();
 return true;
    }
  }
return super.onKeyDown(keyCode, event);
}

I took the problematic JAR file processed by ProGuard, decompiled the CaptureBase.class file and took a look at onKeyDown again:
public boolean onKeyDown(int keyCode, KeyEvent event)
  {
    if ((keyCode == 4) && (event.getRepeatCount() == 0) && 
      (this.a.isModified())) {
      keyCode = this; 
      Toast.makeText(this, getResources().getIdentifier(
        "biz_binarysolutions_signature_ToastMessage", "string", 
        keyCode.getPackageName()), 1).show();
      return true;
    }
    return super.onKeyDown(keyCode, event);
  }
Well, now it all makes sense - for some 'optimization' reason, ProGuard assigned this (android.app.Activity) to keyCode (local variable of type int) and used it in getPackageName() call. Dalvik does not like it.

The fix would be the following: you need to add !code/allocation/variable string to your -optimizations command in ProGuard config file. Mine looks like the following:

-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable

And that should be it!

Thursday, September 20, 2012

IntentService and inter-process communication

Most likely you are familiar with Android's AsyncTask and you use it whenever you have some work that needs to be done in a background. This way the main thread that is responsible for user interface is not kept busy and our application looks snappy.

In case you want to expose your background task to other applications, you will create a Service. Yes, you could expose your Activity that wraps around the AsyncTask, but there is no point doing that since the work needs to be done in background anyways.

We have two options now: our service could extend either Service or IntentService class.

If you decide to extend the Service class be aware that your service when started will still run on your application's main thread, i.e. it will block your user interface. So your service has to create a new thread that will do all the work. Also be aware that your service might receive a new request while the old one is still running (you are exposing your service to the outside world so you have no control over the frequency of calls to it). In that case you have to take care that your threads do not run over each other, meaning - you will be extra careful with the data that is shared between the threads or you will implement some kind of working queue. This is becoming painful already ...

However, when our service extends IntentService class a lot of dirty work is done for us. Our work will be executed on a worker thread and not on a main one, all requests will be queued and served on at the time, and finally our service will shut itself when all requests have been handled. Nice!

Now let's say that our service really has a work to do and that we would like to provide some kind of progress bar in our activity that started the service. For that kind of thing we need some kind of communication between the activity and the service. The usual way to achieve that is using Bound Services. Bound services are started with bindService and not with startService call, when the service is bound you can get a messenger back that is used for activity-to-service communication and your activity can send back to service another messenger that is used for service-to-activity communication. Everything is great except that IntentService does not support the binding.

Well, the story is not over. We can solve this by passing the messenger to the service as Intent's extra. Here is the code sample, together with message handler:


private static class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
	System.out.println("Message received!");
    }
}
	
private void startIntentService() {
    Messenger messenger = new Messenger(new IncomingHandler());
    Intent intent = new Intent("com.example.service.ExampleService");
    intent.putExtra("com.example.service.Messenger", messenger);
    startService(intent);
}	

And here is (almost) the full source code of simple service that just sleeps for 25 seconds and each 5 seconds sends the message back:

public class ExampleService extends IntentService {
	
public ExampleService() {
    super("ExampleService");
}
	
@Override
protected void onHandleIntent(Intent intent) {
		
    Messenger outMessenger = 
	intent.getParcelableExtra("com.example.service.Messenger");

    for (int i = 0; i < 5; i++) {
	SystemClock.sleep(5000);
	if (outMessenger != null) {
	    try {
		outMessenger.send(Message.obtain());
	    } catch (RemoteException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	    }
	}
    }
}
}

As simple as that. Just do not forget to declare your service in it's manifest file like this:

<application ...>
...
<service android:name=".ExampleService">
    <intent-filter>
	<action android:name="com.example.service.ExampleService" />
    </intent-filter>
</service>
</application>

Wednesday, July 25, 2012

Računalno programiranje i obveza plaćanja članarine turističkoj zajednici

Edit:

Od od 1. siječnja 2020. godine djelatnosti iz kategorije 62 (Računalno programiranje, savjetovanje i djelatnosti povezane s njima) više nisu obveznici obveznici plaćanja članarine turističkim zajednicama. Više o tome ovdje.


Originalni post:

Imate firmu/obrt registriranu za obavljanje računalnog programiranja, savjetovanja i djelatnosti povezanih sa njima? Makar mislili da nemate apsolutno ništa sa turizmom, obveznik ste plaćanja članarine lokalnoj turističkoj zajednici.

Prema važećem zakonu (ZAKON O ČLANARINAMA U TURISTIČKIM ZAJEDNICAMA - pročišćeni tekst, NN br.152/2008 i 88/2010), Članak 4., djelatnost računalnog programiranja (šifra nacionalne klasifikacije djelatnosti - 62) nalazi se u 'trećoj skupini' obveznika plaćanja članarine.

Zakonom propisana stopa, primjerice za grad Split, iznosi 0.12 i primjenjuje se na ukupan prihod (kod obveznika poreza na dobit) tj. ukupne primitke (kod obveznika poreza na dohodak).

Predujam članarine plaća se mjesečno (do posljednjeg dana u mjesecu za tekući mjesec) i iznosi jednu dvanestinu osnovice po obračunu poslovnog rezultata za prethodnu godinu. Uplate idu na račun općine ili grada u kojem firma ima sjedište, poziv na broj je 67, zatim OIB. I ne zaboravite poreznoj zajedno sa prijavom predati i Obrazac TZ.

Do sljedećeg posta ...

Friday, February 17, 2012

Airpush.com - Spam might be coming soon to your Android too

Having moderately successful application on Android Market (a few hundred thousand downloads or more) changes the rules of the game. Instead of knocking on their doors, you get invited to closed app stores owned by smartphone manufactures or carriers. Very same way you get invited to join all those ad networks that are supposed to bring you in some revenue.

Ads found within mobile apps are OK. In a perfect world, they would not exist but in this one they are acceptable. In most cases, ads are the only way for application developers to monetize their efforts; and there is nothing wrong in efforts being monetized. Out of the 10 apps that we have published through Android Market, 6 of them contain AdMob banner ads, placed at the bottom of the screen. The revenue from these ads does cover some of our expenses but once the app sales start building up, the ads are out. Anyway, back to the story.

Recently a sales representative from Airpush - the 'next-gen mobile ad network for Android apps' - contacted us. They were not shy about broadcasting their offer and, as you can see from their web site, they guarantee 10 to 30 times more ad revenue. This sounded more than interesting and it deserved a closer look. Just how were they able to promise such high CPMs? Read on ...


Airpush ads come in three different flavors: Push Notification Ads, Icon Ads and Signup Ads. The last one (though currently in a closed beta) is the standard ad screen that is displayed when the application launches or is triggered by the developer later during the app session, so I do not find it that interesting and innovative. However, the first two flavors, the Push Notification Ads and Icon Ads, they are the real refreshment in mobile ad industry.

    Push Notification Ads

    Our lovely Android notification tray. With all that icons like battery status, signal strength, and all those important notifications regarding received SMS and email messages, etc. Well ... why have the developers been waiting until now? Let the ads march in! Ads are important, and we should be notified about them. The very same way we are notified about our missed calls.

    Image (C) by Airpush.com

    Icon Ads

    Clean smartphone desktops are overrated. Who needs order within those small screens anyway? We need more shortcuts, shortcuts that would 'link to valuable user content such as mobile search and daily deals'.


    All joking aside, this is a serious issue. It would be sad if this ever catches on. Just imagine what kind of user experience you would have with gadgets of such a personal nature such are smartphones! So here is what we think about it and what we said in response to the Airpush sales representative:
    We find your ads too invasive. They are more like spam. We would uninstall the app that introduced them on our device and we would give it a low rating accompanied with a raging comment. So, we are not interested and please do not contact us again.
    Ads are already here, and let's keep them inside the apps themselves. Let's not allow them to infest our phones. For all those who would like to see what kind of Airpush horror they might expect to see on their phone, the demo is available here:


    I haven't tried this demo out as it asks for 'Read phone state and identity' permission.

    I should be fair and mention that Airpush offers opt-out options. For Push Notification Ads, you can opt out, ad by ad, by clicking on provided opt-out links. You can opt-out completely as well, by installing Airpush's opt-out application or providing them with your IMEI number on their web page, which ever you prefer. It looks like you can't opt-out from icon ads, but Airpush says that you can remove those easily with one click. Well, we can remove them, shouldn't that make us happy enough? ;-)


    Update: the same goes for LeadBolt.