Tuesday, January 15, 2013

Create your own Malayalam flip font for Android

Certain Samsung devices allow you to change system font by installing flip font (font apk). Your device should have Settings -> Display -> Font Style option for this to work. Not all Samsung devices have this option.

Creating a flip font is an easy task. You can find many posts about this on the net (mainly in xda forums) but creating a Malayalam font apk is little tricky. Steps mentioned in other places will not work for Malayalam font as the process will not copy GSUB tables correctly to the digitally signed font.

Tools needed:

  1. Windows machine
  2. Fontforge (http://sourceforge.net/projects/fontforge/files/latest/download?source=files)
  3. Apk Manager v4.9 (http://goo.gl/GKBHM)
  4. A working flip font (http://goo.gl/cfTJU)
  5. A blank digitally signed font BlankSigned.ttf (http://goo.gl/Gefuf)
  6. A font that you want to convert to flip font
Steps:

Create signed font
  1. Install Fontforge
  2. Download BlankSigned.ttf to local disk
  3. Run Fontforge
  4. Open Font -> Browse and select your font (ex: MyFont.ttf)
  5. File -> Open -> Browse and select BlankSigned.ttf
  6. Element -> Merge Fonts ... (Make sure you select this option from BlankSigned.ttf font window)
  7. Click OK. This will merge your font with BlankSigned.ttf font.
  8. File -> Generate Fonts ... -> Select TrueType for font type -> Enter a name for the font (ex: MyFont.ttf) -> Save. Try to use a font name without special chars or numbers to make things easier.
  9. If you get Errors detected window, just click Save
  10. Now you have a digitally signed font that you can include it in font apk
Create font apk
  1. Download Apk Manager v4.9 and unzip to local disk
  2. Copy working flip font (Kaumudi.apk) to apk_manager_4.9\place-apk-here-for-modding folder
  3. Open cmd window and cd to apk_manager_4.9
  4. Run "Script.bat"
  5. Press any key to continue on adb warning
  6. Type 22 and hit enter
  7. Type 1 to select Kaumudi.apk. If you see multiple apks, type the number corresponding to Kaumudi.apk
  8. Type 9 and hit enter to decompile apk. Don't close cmd window. We need it for later.
  9. Now you will see apk_manager_4.9\projects\Kaumudi.apk folder in file system
  10. Replace Kaumudi.ttf in apk_manager_4.9\projects\Kaumudi.apk\assets\fonts with your signed font (ex: MyFont.ttf). I'm going to use MyFont as the name of new font for rest of the steps. Change it to your actual font name. Also rest of the steps are for the files/folders in apk_manager_4.9\projects\Kaumudi.apk folder
  11. Rename assets/xml/Kaumudi.xml file to assets/xml/MyFont.xml
  12. Rename smali/com/monotype/android/font/Kaumudi folder to smali/com/monotype/android/font/MyFont
  13. Open each xml, yml, smali files in apk_manager_4.9\projects\Kaumudi.apk folder and sub folders in a text editor and replace Kaumudi with MyFont
  14. Switch back to cmd window
  15. Type 11 and hit enter to compile apk
  16. Type n for system apk and hit enter
  17. Type 12 and hit enter to sign apk
  18. Now you will see signedKaumudi.apk in apk_manager_4.9\place-apk-here-for-modding folder. Rename it to MyFont.apk. That's your flip font.
  19. If you have followed instructions correctly, you now have a flip font that you can install on your device.
Let me know if you find any errors in my instructions.

Saturday, August 25, 2012

Jellybean (4.1) - Fixing Malayalam rendering in non-browser apps

Finally, Jellybean (Android 4.1) ships with default Malayalam font and font included in 4.1 is AnjaliNewLipi-light.ttf. All browser based apps (like Facebook, Chrome browser, Gmail, etc.) render Malayalam content properly expect one "Ra" issue.

But, all non-browser apps have rendering issue. Complex text layout is not rendered properly. Interestingly, if you build a non-browser based app and force the text widgets to use /system/fonts/AnjaliNewLipi-light.ttf, they get same rendering as the browser. With the support of many people in G+, we filed a ticket with Google and Google confirmed it as a known issue they are working on. We hope Google will fix it soon.

As we don't know how long Google will take to fix the issue, we have an interim option to fix the rendering issue if you are already rooted your Jellybean device (or planning to root your device). I'm not encouraging anybody to root your device and I do not take any responsibility for anything you do to your phone, whether be brick, break, or somehow mess it up :)

This is how you can fix the rendering issue (Note: this will work only on devices with Jellybean and not anything else)

Warning: If you make below change, AnjaliNewLipi-light will be the default font of the device. So English text might not look as nicer as before when default font is Roboto-Regular/Bold/Italic/BoldItalic.ttf.
  1. Install Issue35996.apk and check if second line is displayed properly. If yes, continue.
  2. Root your device running Jellybean
  3. Install ES File Explorer from Google Play
  4. Open ES File Explorer and enable Root Explorer, Mount File System options in settings
  5. Copy /system/etc/system_fonts.xml to your computer
  6. Open system_fonts.xml in text editor and add the following right after <familyset>. It must be the first entry after <familyset> tag.
        <family>
            <nameset>
                <name>anjali</name>
            </nameset>
            <fileset>
                <file>AnjaliNewLipi-light.ttf</file>
            </fileset>
        </family>
  7. Copy modified system_fonts.xml to /system/etc/system_fonts.xml
  8. Make sure /system/etc/system_fonts.xml has read permission for owner, group and user (rw-r--r--). You can check this using ES File Explorer by long pressing on the file and selecting Properties.
  9. Restart device
Before fix:

After fix:


Screenshot of Issue35996.apk in step #1:



Wednesday, June 15, 2011

java.io.FileNotFoundException: http://www.opensymphony.com/osworkflow/workflow_2_8.dtd

Have you started seeing the following error recently in your application that uses open symphony's osworkflow-2.8.0.jar?
Caused by: java.io.FileNotFoundException: http://www.opensymphony.com/osworkflow/workflow_2_8.dtd
 at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
 at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
 at org.apache.xerces.impl.XMLEntityManager.startEntity(Unknown Source)
 at org.apache.xerces.impl.XMLEntityManager.startDTDEntity(Unknown Source)
 at org.apache.xerces.impl.XMLDTDScannerImpl.setInputSource(Unknown Source)
 at org.apache.xerces.impl.XMLDocumentScannerImpl$DTDDispatcher.dispatch(Unknown Source)
 at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
 at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
 at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
 at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
 at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
 at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
 at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
Reason for the above error is clear from http://www.opensymphony.com
Looking for an OpenSymphony project? Unfortunately, OpenSymphony has seen it's final days.
All the URLs to www.opensymphony.com including the URL for the DTD is now pointed to the home page. So the XML parser cannot retrieve the DTD to validate the workflow xml file. If you have a production app that uses osworkflow jar, what do you do to get the app working again?

There are couple of options:

1. You can copy the DTD bundled inside osworkflow-2.8.0.jar to your website with a static IP address under /osworkflow path, edit /etc/hosts (or C:\Windows\system32\drivers\etc\host in windows) to point www.osworkflow.com to your IP address. This will make your app to find the DTD on your server.

2. The right way to fix the issue is in your code. The place where you parse the workflow XML file.

for example:
// Load the workflow xml
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
File file = new File(workflowXmlFilename);
Document docWorkflow = builder.parse(file);
where workflowXmlFilename is your workflow xml file with the DTD pointing to http://www.opensymphony.com/osworkflow/workflow_2_8.dtd.

To resolve the DTD inside the osworkflow-2.8.0.jar, you need to set the EntityResolver of DocumentBuilder to the one provided by open symphony. Otherwise XML parser will use the default resolving mechanism.
// Load the workflow xml
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(new DTDEntityResolver());
File file = new File(workflowXmlFilename);
Document docWorkflow = builder.parse(file);
The above code
builder.setEntityResolver(new DTDEntityResolver());
tells the parser to use com.opensymphony.workflow.loader.DTDEntityResolver that has the special logic to reference the DTD inside the jar. Here is the relevant part of the DTDEntityResolver.java
URL url = new URL(systemId);
String file = url.getFile();

if ((file != null) && (file.indexOf('/') > -1)) {
  file = file.substring(file.lastIndexOf('/') + 1);
}
if ("www.opensymphony.com".equals(url.getHost()) && systemId.endsWith(".dtd")) {
  InputStream is = getClass().getResourceAsStream("/META-INF/" + file);

  if (is == null) {
    is = getClass().getResourceAsStream('/' + file);
  }

  if (is != null) {
    return new InputSource(is);
  }
}
You can get the source code of osworkflow-2.8.0.jar from https://maven.atlassian.com/content/repositories/atlassian-3rdparty/opensymphony/osworkflow/2.8.0/osworkflow-2.8.0-sources.jar.

Long live Open Source !!

Wednesday, May 18, 2011

PL/SQL - REST Call and XML Parsing

Looking for an example to make a REST API call in PL/SQL and parse the xml response from the call? Here is one way to do it.
DECLARE
 req     utl_http.req;
 resp    utl_http.resp;
 line    VARCHAR2(1024);
 url     VARCHAR2(1024);
 content VARCHAR2(1024);

 p       xmlparser.Parser;
 doc     xmldom.DOMDocument;
 element    xmldom.DOMElement;
 nodeList xmldom.DOMNodeList;
 node     xmldom.DOMNode;
BEGIN
 dbms_output.enable(1000000);

 url := utl_url.escape('http://host:port/app/rest/something');

 -- example xml response:
 --<?xml version="1.0" encoding="UTF-8"?><something><name>Joe</name><age>40</age></something>

 req := utl_http.begin_request(url);
 utl_http.set_header(req, 'User-Agent', 'Mozilla/4.0');
 resp := utl_http.get_response(req);
 content := '';
 BEGIN
     LOOP
       utl_http.read_line(resp, line, TRUE);
       content := content || line;
     END LOOP;
     utl_http.end_response(resp);
     EXCEPTION
         WHEN utl_http.end_of_body THEN
           utl_http.end_response(resp);
 END;

 dbms_output.put_line(content);

 p := xmlparser.newParser;
 xmlparser.setValidationMode(p, FALSE);
 xmlparser.parseBuffer(p, content);
 doc  := xmlparser.getDocument(p);

 element := xmldom.getDocumentElement(doc);

 nodeList := xmldom.getElementsByTagName(element, 'name');
 node := xmldom.item(nodeList, 0);
 node := xmldom.getFirstChild(node);
 dbms_output.put_line('name: ' || xmldom.getNodeValue(node));

 nodeList := xmldom.getElementsByTagName(element, 'age');
 node := xmldom.item(nodeList, 0);
 node := xmldom.getFirstChild(node);
 dbms_output.put_line('age: ' || xmldom.getNodeValue(node));
END;

Monday, May 16, 2011

Ever stuck in eclipse splash screen?

There have been times my Spring Source Tool Suite (based on eclipse) won't start after a crash or machine restart after automatic windows update when IDE was running. It mainly get stuck in the splash screen after selecting the workspace. One way to get the IDE started is to remove .snap file from
.metadata\.plugins\org.eclipse.core.resources
under your workspace folder and start IDE again.

Monday, March 29, 2010

JSTL madness

I was working on a Java webapp that uses JSTL v1.2 when I hit this JSTL issue. It took me some time to find a work around. Here is the issue: I had a bean that exposes a property called "name". When I tried to output name in jsp using <c:out value="${myBean.name}" /> I always get my webapp context name. Then I came across this article where I saw "The expression language unifies the treatment of dot (.) and bracket ([]) operators. Therefore, ${customer.name} is equivalent to ${customer["name"]}." I tried <c:out value="${myBean["name"]}" /> and got the correct value in jsp. Still not sure why ${myBean.name} didn't work and ${myBean["name"]} worked.

Friday, January 16, 2009

Authenticode signing of windows binary from non-windows platform

After I switched OS for my development from Windows to Mac, I always try to find options that minimize the need for starting Windows on VirtualBox. I had to use Windows for digitally signing exes and dlls. Today I found osslsigncode to sign windows binaries on non-windows platform. One less reason to boot Windows and it is much quicker than on Windows :) Here is how I did it on Mac: 1. Download source zip, unzip, compile and install osslsigncode from http://sourceforge.net/projects/osslsigncode/
cd osslsigncode-1.3 ./configure make make install
2. Generate spc and private key files in DER format from .p12 file
openssl pkcs12 -in CodeSigning.p12 -nokeys -clcerts -out CodeSigning-CL.crt.pem openssl pkcs12 -in CodeSigning.p12 -nokeys -cacerts -out CodeSigning-CA.crt.pem openssl pkcs12 -in CodeSigning.p12 -nocerts -nodes -out CodeSigning-CL.key.pem openssl crl2pkcs7 -certfile CodeSigning-CL.crt.pem -certfile CodeSigning-CA.crt.pem -nocrl -outform DER -out CodeSigning-CL.spc.der openssl rsa -in CodeSigning-CL.key.pem -outform DER -out CodeSigning-CL.key.der
3. Now sign the binary
osslsigncode -spc CodeSigning-CL.spc.der -key CodeSigning-CL.key.der -n "Description" -i "http://www.mydomain.com" -in file.dll -out signed-file.dll