Friday, March 3, 2017

Using CKEditor in WebView on Android

CKEditor is a powerful rich text editor for web applications.  This post shows how to integrate the editor into an Android application and load a sample page into a WebView.

  1. Download CKEditor.
  2. Unpack Zip file and move ckeditor folder to $project.projectDir/src/main/assets folder.
  3. Create a WebView in your layout file.
  4. After inflating the layout file, find WebView and enable JavaScript: webView.getSettings().setJavaScriptEnabled(true);
  5. Load sample app into the WebView: webView.loadUrl("file:///android_asset/ckeditor/samples/index.html");
When the application is launched, it'll look something like this:




Thursday, March 2, 2017

Loading WebView from a resource file on Android

This pattern worked for me:

final Uri uri = Uri.parse("file:///android_res/raw/maptest");
webView.loadUrl(uri.toString());

where maptest.html is a file in res/raw folder.  Replacing maptest with maptest.html also works.

The following works to load a file from assets directory:

final Uri uri = Uri.parse("file:///android_asset/maptest.html");
webView.loadUrl(uri.toString());

Note the use of .html extension when loading from assets directory.  When the extension is removed from the URI, the file won't load.

Tuesday, February 28, 2017

Antlr4, gradle, -package, outputDirectory

First, we enabled antlr4 in IntelliJ/gradle. Next we need to find a location for antlr4 files and correctly place its output files.  There is a couple of ways to configure antlr4 output directory in gradle.

The simplest way is specify package name in @header:

@header {
  package com.example.parser;
}

Then, if we place our grammar files to "$project.projectDir/src/main/antlr/com/example/parser", antlr4 will place its output files to "$project.buildDir/generated-src/antlr/main/com/example/parser".

The problem with specifying package name in the @header is that it ties the grammar to the target language.  There is another way to configure output directory.

First, we remove @header from grammar file to untie the grammar from the target language.
Second, we add the following to build.gradle:

generateGrammarSource {
    outputDirectory file("${project.buildDir}/generated-src/antlr/main/com/example/parser")
    arguments << '-package' << 'com.example.parser'
}

An optional step is to move the grammar files from "$project.projectDir/src/main/antlr/com/example/parser" to "$project.projectDir/src/main/antlr" so that we don't have to look for the files deep down the directory hierarchy.

When all this is setup, antlr4 will place its output files into the same directory as in the first example.

Sunday, February 26, 2017

Testing Content Providers

ProviderTestCase2 and Testing Your Content Provider documents seems not complete.  I followed them and getMockContentResolver() always returned null. The reason for null resolver is that setUp() method is not called when tests run.  Adding the following method to my sub-class of ProviderTestCase2 fixed the problem.

@Before
public void mySetUp() throws Exception {
    setUp();
}

I'm not sure if this is the best solution though.

Sunday, January 29, 2017

Using antlr4 in IntelliJ



Earlier I wrote about configuring JavaCC in Android Studio / IntelliJ. Since I'm migrating from JavaCC to antlr4, I'll show how to integrate antlr4 to IntellJ.

It's actually less work than configuring JavaCC. All you have to do is to add 2 lines:

plugins {
  // ...
  id "antlr"
}

// ...

dependencies {
  antlr "org.antlr:antlr4:4.6"
  // ...
}

One might ask why switching from one LL(*) parser generator to another LL(*)?  There are many reasons, I'll comment on this later.  One note: antlr4 is not exactly LL(*), it is ALL(*), where A stands for Adaptive.  This difference by itself is a big improvement over JavaCC, where Adaptive part requires careful management by hand.

Tuesday, December 27, 2016

Precedence Climbing in JavaCC

Precedence Climbing is described in Parsing Expressions by Recursive Descent.  Here we look at how to implement the highlighted part in JavaCC, namely, how to exit the loop.

Exp( p ) is
    var t : Tree
    t := P
    while next is a binary operator and prec(binary(next)) >= p
       const op := binary(next)
       consume
       const q := case associativity(op)
                  of Right: prec( op )
                     Left:  1+prec( op )
       const t1 := Exp( q )
       t := mkNode( op, t, t1)
    return t

Semantic lookahead looks like a nice solution.  Below is a sample implementation:

public ExprNode Expr(int p) :
{
    ExprNode expr, expr1;
    OpBinary op;
}
{
    (
        expr = ExprPrefix()
        (
            LOOKAHEAD({ nextBinaryOp() != null && 
                nextBinaryOp().getPrecedence() >= p })
            op = BinOp()
            expr1 = Expr(op.getAssoc() == OpBinary.Assoc.RIGHT ?
                op.getPrecedence() : op.getPrecedence() + 1)
            { expr = new ASTExprBinary(op, expr,  expr1); }
        )*
    )
    { return expr; }
} 

()* construct corresponds to the while loop.  Since this construct is a choice point, the false expression value in the LOOKAHEAD simply exits the loop.

We define nextBinaryOp() in the parser class as follows:

private OpBinary nextBinaryOp()
{
    return OpBinary.fromCode(getToken(1).kind);
}

getToken(1) does not modify the input stream and is equivalent to next in the original algorithm.

Definitions of ExprNode, OpBinary, ExprPrefix, BinOp and ASTExprBinary are omitted for brevity.

Friday, November 11, 2016

Formatter/encoder widgets from Bing

These are quite useful when you need to quickly format/encode some strings.