Frege on Android

After a weekend of clicking through forums and reading about previous attempts I’ve finally gotten Frege to work on Android. The implementation can be found here

The implementation is quite hacky but I have faith in its extensibility. I think it’s a matter of getting a better grasp of the Android build system. To run the build on your machine you’ll need to download Frege 3.24.100.1-jdk7, open it with an archive manager like 7-zip, delete the run8 folder (Android studio won’t be able to parse Java 8), add the modified Frege as a source dependency in your app’s gradle module, then copy the gradle settings in my build.gradle to your build.gradle. The implementation borrows heavily from ppelleti with some adjustments to execute with a newer version of Frege.

The code calls the Frege compiler to compile FregeActivity without creating class files and then places it where Android would have expected to find Java files. The gradle options can be copied almost verbatim with some adjustments to the path i.e including where your “custom” Frege compiler is located.

Let’s talk about the code.

We want to extend the Activity class and then define some methods corresponding to the activity lifecycle. In a fashion similar to my previous post, we have a data declaration for FregeActivity and we extend the Activity class as follows:

data FregeActivity = native android.app.Activity
native module type FregeActivity where {
	super.onCreate(savedInstanceState);
    android.widget.TextView tv = new android.widget.TextView(this);
    tv.setText("Hello, Android - Love, Frege");
    setContentView(tv);

This will programatically create a TextView and place the text “Hello, Android - Love, Frege” in a TextView at the top of the screen. But we want to move the code to FregeLand so we aren’t just wrapping java code in a single Frege module. Again, similar to last blog post, we can make onCreate call a Frege Function. We don’t, however, have to pass this function into the code through some method, we can refer to it by its Frege name since the “native” part is hoisted to the top of the compiled Java. Let’s call our FregeVersion of onCreate onCreateF and give it as an argument, the Activity class so we can manipulate the context.

onCreateF :: MutableIO FregeActivity -> IO ()
onCreateF !this = ...

The reference must be strict so the method call in our native portion can take as an argument the reference this instead of wrapping the argument in the Lazy type. After defining some boilerplate and placing all the onCreate code in FregeLand we have:

module io.github.mchav.fregeandroid.FregeActivity where
data Bundle = native android.os.Bundle

data Context = native android.content.Context

data FregeActivity = native android.app.Activity where
	native getApplicationContext :: MutableIO FregeActivity -> IO (MutableIO Context)
	native setContentView :: MutableIO FregeActivity -> MutableIO TextView -> IO ()

data TextView = native android.widget.TextView where
	native new :: MutableIO Context -> STMutable RealWorld TextView
	native setText :: MutableIO TextView -> String -> IO ()

onCreateF :: MutableIO FregeActivity -> IO ()
onCreateF !this = do
	context <- this.getApplicationContext
	tv <- TextView.new context
	tv.setText "Hello, Android - Love, Frege"
	this.setContentView tv

native module type FregeActivity where {
	@Override
    public void onCreate(android.os.Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final frege.run7.Func.U<Object,Short> res = RunTM.<frege.run7.Func.U<Object,Short>>cast(onCreateF(this)).call();
		frege.prelude.PreludeBase.TST.run(res).call();
    }
}

Halala! A complete implementation of an Android activity in Frege. I hope to continue work on Frege in Android to make the process a little less hacky and less boilerplaty. Any help and ideas are appreciated.

Written on November 27, 2016