Sunday, October 30, 2011

WifiAlive Android App released

WifiAlive is a very simple and low resource application aimed at maintenance of a Wifi connection. A connection is periodically (every 5 seconds) checked by trying to contact the gateway, as well as IP addresses or domain names which you can enter via the UI. WifiAlive tests each of these addresses by icmp and http head. If one of these tests succeeds, Wifi is considered up. If not, Wifi is reset (that is deactivated and activated). After Wifi (re-)activation Android on its own tries to establish a connection to an access point in reach. On a failed connection check, WifiAlive will only wait 20 seconds for a reset, scan and successful connection until the connection is reset again. Considering the time needed for a Wifi reset and a scan to complete, it can be said, that, as soon as a known network is available, there is a worst-case of roughly 30 seconds for the connection to be established. WifiAlive is thus much more simple then many of its competitors. The popular WifiFixer for example conveys about 6000 lines of code whereas WifiAlive has only around 500.

The code of WifiFixer is publicly available on github. I have checked those parts of the code which seemed important in respect of a problem I believed to have with WifiFixer 0.8.0.6. I was rather stunned by the complexity of the program, since I had in mind the solution I have just proposed. WifiFixer almost replaces the Wifi Settings Tab in Android and will continue this approach in upcoming versions. In some cases, settings from the Android Wifi Settings Tab can be overridden, it does its own management of known networks and behind the scenes does scans for networks in reach, matches them to known networks and harbours a small collection of hacks for devices that have to be dealt with in a special way - for example the Google Nexus One. WifiFixer is a great application. It helps many people with their Wifi troubles. But after I had seen its complexity and, in addition, found a bug in its matching of known to found networks on a scan, I decided that this was not the solution to my problem, as, additionally, a lot of code seemed to do things that Android normally does on its own. No offence David, I've learned a lot from looking at your code.

There are other applications, like Advanced Wifi Lock. But I couldn't get access to their code and very often the free (limited) versions did not seem to cover all aspects of Wifi maintenance that I wanted to ensure. Moreover I am already beyond trusting a random application from the market without knowing its code. The Advanced Wifi Lock application (a bare Wifi lock, if it does what the name suggests) does not solve my problems, as it sometimes takes Android a bit too much of time to re-establish a connection when re-entering the area of an access point or on walking from one access point to another. In my experience this could take up to two minutes, which was just too long for my purpose. These experiences may be better on other devices, still it feels very good to know, that as soon as a known network is in reach, there is a rough 30 second worst-case until you have a connection.

On some devices there also seem to be problems with the supplied Wifi drivers. These drivers may enter an undetermined state or cause wpa supplicant to run in endless loops. I have not delved into these problems. But it seemed to me, that, if at all, they can be resolved by doing a Wifi reset.

To sum up, I think that some applications aimed at taking care of your Wifi connection may be too complicated and question is, why such an application should do things like scanning for access points, as Android usually does a pretty good at this. Others may be doing the things I had in mind, yet there was no way for me to be sure.

That's, why I wrote WifiAlive. I hope you like it.

Feel Free to browse the code at http://darcs.factisresearch.com/pub/WifiAlive or just install the app from the android market.

Sunday, April 26, 2009

Some Java Fun becoming a major pain

Ich hab mal wieder mit GWT rumgespielt und etwas Java programmiert. Da ich ohne map, fold und filter nicht mehr auskomme und Java ja endlich Generics hat, hab ich mir eine kleine Fun Library geschrieben, damit ich z.B. sowas machen kann...

Set<String> strSet = Fun.mapS(intSet, new Fun<String,Integer>() {
  public Integer eval(String s) { return Integer.parseInt(s); }
});

Das funktioniert auch ganz gut, auch wenn die Syntax alles andere als angenehm ist. Ich hab also eine abstrakte Klasse

abstract class Fun<A,B> {
  public abstract B eval(A x);

mit Hilfsfunktionen wie

public static <A, B> Set<B> mapS(Collection<A> src, Fun<A,B> fun) {
  // ...
}

Wenn man eine Mapping-Funktion mehrfach braucht muss man sie auch nicht immer inline-definierien, sondern kann eine Konstante draus machen, also z.B. im Beispiel oben

Fun<String,Integer> STR_TO_INT = new Fun<String,Integer>() {
  public Integer eval(String s) { return Integer.parseInt(s); }
};

und dann braucht man nur noch

Set<String> strSet = Fun.mapS(intSet, STR_TO_INT)

schreiben. Alles wunderbar... nur dann brauchte ich eine Funktion um aus Map.Entrys die erste Komponente zu extrahieren (map.entrySet() ging in dem Fall nicht). Also

Fun<Map.Entry<String, Integer>, Integer> ENTRYKEY =
  new Fun<Map.Entry<String, Integer>, Integer>() {
    public Integer eval(Map.Entry<String,Integer> e) {
      return e.getKey();
    }
  };

und das funktioniert auch noch gut. Aber dann brauchte ich die Funktion für andere Typparameter. Na, kein Problem, kann man doch sicher generalisieren:

public static <A,B> Fun<Entry<A,B>, A> ENTRY_KEY_1 = new Fun<Entry<A, B>, A>() {
  @Override
  public A eval(Entry<A, B> x) {
    return x.getKey();
  }

Nur leider kompiliert das nicht. Polymorphe Werte scheint Java nicht zu unterstützen. (Oder hab ich's nur falsch gemacht?!) Okay, also eine Dummy-Funktion....

public static <A> Fun<Entry<A>, A> ENTRY_KEY_2() {
  return new Fun<Entry<A>, A>() {
    @Override
      public A eval(Entry<A> x) {
      return x.getKey();
    }
  };
};

Die kann man definieren, aber leider nicht aufrufen!

Pain.java:38: <A>mapS(java.util.Collection<A>,Fun<A>) in Fun cannot
be applied to
(java.util.Set<java.util.Map.Entry>,Fun<java.util.Map.Entry,java.lang.Object>)

Wahrscheinlich weil nur anhand der Parameter die richtige Belegung ausgewählt werden kann. Also muss man einen Phantom-Parameter einführen...

public static <A> Fun<Entry<A>, A> ENTRY_KEY_3(Entry<A> phantom) {
  return new Fun<Entry<A>, A>() {
    @Override
      public A eval(Entry<A> x) {
      return x.getKey();
    }
  };
};

und dann beim Aufruf

Set keys = Fun.mapS(map.entrySet(), ENTRY_KEY_3((Entry) null));

Oh.... das tut weh!

Weiss jemand wie das mit Generics in C++ und C# ist? In Scala geht das sicher, oder?

Schade, dass GWT Java SourceCode nach JavaScript kompiliert und nicht, wie ich dachte, Java ByteCode. Damit man mit GWT in den Genuss von Scala kommt muss man wahrscheinlich erst Scala nach ByteCode komilieren und dann mit einem Dekomiler aus dem ByteCode wieder JavaCode machen und den dann mit GWT kompilieren. Oder man hackt gleich getyptes JavaScript in Haskell aber Dmitry Golubovsky ist nicht Google und Version 0.1 ist wohl eher ein Proof of concept. Wahrscheinlich sollte ich halt doch einfach schön imperativ in Java programmieren und Generics nur verwenden um ein paar Casts zu sparen. :-/

Autor: David Leuschner