Wednesday, April 17, 2013

My Ordeal with Samsung S2 JB Upgrade (Has happy ending)

I have been waiting for the JB upgrade for my GT-I9100G for quite sometime. It is phone bought in India and the update has been rolling out gradually in the past weeks for S2 s in India. I was clicking on the "Check for updates" button everyday, in the hopes of getting the update even though I had enabled automatic update check.

Last Friday, I was very happy to see my screen popup with the information that the update has been found and downloaded and prompted me to install or later. Usually I make sure that the battery power is almost full and then initiate the update. But, this time my excitement overtook my caution and I clicked on "Install". I immediately plugged in my phone into the power socket and waiting for the update to complete. It seemed to be running fine, but suddenly after the automatic reboot, it had got stuck in the boot screen. I waited for quite sometime before I realized that my phone has been "soft-bricked".

I had also not backed up some of my data in my excitement and my ordeal began. My tasks were to:
1. Get the data from the internal SD out
2. Update to JB

I tried entering into the Android recovery mode  (Volume up + Power + Home) hoping it to be helpful. It did not help much with respect to getting the update work. Then after searching the net for a while I could get the required tools for data recovery and update. All the information is out there, but, I felt they were are not in a single place.

The first step was to get to a better recovery mode of ClockWorkMod. To install this, I did the following steps:

1. Odin307.zip  - http://forum.xda-developers.com/showthread.php?t=1738841
2. Installed CWM for recovery mode -
a. GT-I9100G_Blazing_Kernel_v3_CWM5.Tar from http://www.androidfilehost.com/?fid=9390288116658474142
       b. Used Odin to install this Kernel. The instructions are commonly available:


  1. Turn off you phone and enter Download or Odin mode: press and hold Volume Down + Home + Power buttons together for a few seconds.
  2. You will  see a screen asking you to press the Volume Up button. Press it and you will enter the download mode.
  3. Launch Odin
  4. Connect your phone to the computer via USB cable and wait till Odin detects your device. A successful connection is indicated by the ID:COM port turning blue and “Added!!” text at the message box below.
  5. Make sure that only the “Auto Reboot” and “F Reset Time” options are checked on Odin. 
3. Launched the CWM recovery mode by using volume up+ power + home buttons. 
4. Used CWM backup to SD card to create back of phone's system storage. - This back up contains phone logs, SMS and contacts.
5. Use the CWM mounts menu item to mount internal storage (sometimes referred as internal SD) of the phone. It was called as emmc for me. (Some people have mentioned that their internal storage was called as sdcard and external as emmc)
6. Connect the USB cable and use "adb pull" (Android developer tools) get the files in emmc 
7. The contacts will be available in data\data\com.android.providers.contacts\databases directory of data.ext4 zip file in the CWM back up created in step 4. Use the script from https://github.com/stachre/dump-contacts2db to convert contacts2.db to VCF which could be imported into Android. I used a Ubuntu running on a Sun VirtualBox to execute the script. Use the following command in Ubuntu to install required dependencies for the script. 
sudo apt-get install sqlite3 libsqlite3-dev.
8. SMS are available in data\data\com.android.providers.telephony\databases\mmssms.db. Used yaffs-mmssmsdb-calls-extractor.zip to get the SMS from backup to the XML  format used by the "SMS back & restore" android application, which could be imported. The application can directly work on mmssms.db. 
9. Now the back ups are complete. The next is to install the JB. The official Samsung JB build is available from http://www.sammobile.com/firmwares/1/?model=GT-I9100G&pcode=INU#firmware for India model of GT-I9100G. 
10. Then use Odin to write the firmware
11. Restore contacts and SMS. Use import menu in contacts to restore VCF. Use SMS back &  restore for importing back the SMS.  



At last the S2 was back in business.

Thursday, April 11, 2013

File download page using Spring


In web.xml, map directory listing URL to spring dispatcher:


 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>*.html</url-pattern>
 </servlet-mapping>

 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>/download/*</url-pattern>
 </servlet-mapping>

The first one is your existing dispatcher and the second one for download.

In spring security configuration set up appropriate configuration:
<intercept-url pattern="/download/**" access="permitAll" />

In Spring servlet config xml set this up to make path configurable:

 <bean id="appPropertiesBean" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="singleton" value="true" />
  <property name="properties">
   <props>
    <prop key="downloadPath">C:/</prop>
   </props>
  </property>
 </bean>

In your controller for the path property:

    @Value("#{appPropertiesBean.downloadPath}")
    private File downloadPath;

In controller add methods to generate directory listing:

   @RequestMapping(value = "/files/**", method = RequestMethod.GET)

    public ModelAndView archiveDirectoryListing(HttpServletRequest request, HttpServletResponse response) {
        try {
            //String restOfTheUrl=(String)request.getAttribute( HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE );
            //The above line seems to cause issues with filenames 
            // containing semicolon. Use the below line instead
            String restOfTheUrl=request.getPathInfo();
            restOfTheUrl=restOfTheUrl.substring("/files".length());
            File physicalFileRequested=new File(downloadPath,restOfTheUrl);
            System.out.println("Accessing .." + physicalFileRequested);
            if (!physicalFileRequested.getCanonicalPath().startsWith(archivePath.getCanonicalPath())) { //Requester is trying to go above the archive directory
         response.setStatus(HttpServletResponse.SC_FORBIDDEN);
         return;
            }
            if (!physicalFileRequested.exists()) {
         response.setStatus(HttpServletResponse.SC_FORBIDDEN);
         return;       
            }         
            System.out.println("Access allowed " + physicalFileRequested);
            System.out.println("Access allowed " + physicalFileRequested.isFile());
            System.out.println("Access allowed " + physicalFileRequested.isDirectory());
            System.out.println("Rest of url : " + restOfTheUrl);
            if (physicalFileRequested.isFile()) {
         System.out.println("Accessing file:" + physicalFileRequested);
         streamFile(physicalFileRequested,response);
            } else if (physicalFileRequested.isDirectory()){
         if (! restOfTheUrl.endsWith("/")) {
             response.sendRedirect(request.getContextPath() + "/download/files" + restOfTheUrl + "/");
         }
         System.out.println("Accessing dir:" + physicalFileRequested);
         generateDirectoryListing(physicalFileRequested,response);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Error accessing requested file/directory.");
        }
    }

    private void streamFile(File physicalFileRequested, HttpServletResponse response) {
 try {
     response.setContentType("application/pdf");
     // get your file as InputStream
     InputStream is = new FileInputStream(physicalFileRequested);
     // copy it to response's OutputStream
     IOUtils.copy(is, response.getOutputStream());
     response.flushBuffer();
 } catch (IOException ex) {
     throw new RuntimeException("Error accessing requested file/directory.");
 }
    }

    private void generateDirectoryListing(File physicalFileRequested, HttpServletResponse response) {
 try {
     StringBuilder sb=new StringBuilder();
     sb.append("<html>");
     sb.append("<body>");
     sb.append("<a href='..'>..</a><br>");

     File [] childFiles=physicalFileRequested.listFiles();
     for (File childFile:childFiles) {
  String relativePath = childFile.getName();
   sb.append("<a href='"+ URLEncoder.encode(relativePath,"UTF-8")  + "'>" +relativePath+"</a><br>");
     } 
     sb.append("</body>");
     sb.append("</html>");
    response.getWriter().print(sb.toString());
 } catch (Exception e) {
     throw new RuntimeException("Error accessing requested file/directory.");
 }
    }



Download URL will be like:

http://localhost:9090/context/download/files/

Alternatively, the directory listing HTML could be generated using a view, by using the following alternate implementation of the method (Note: wherever null is returned for ModelAndView, Spring assumes that response has already been handled and no view redirection needs to happen):


   @RequestMapping(value = "/files/**", method = RequestMethod.GET)
    public ModelAndView archiveDirectoryListing(HttpServletRequest request, HttpServletResponse response) {
        try {
            String restOfTheUrl=(String)request.getAttribute( HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE );
            restOfTheUrl=restOfTheUrl.substring("/files".length());
            File physicalFileRequested=new File(archivePath,restOfTheUrl);
            System.out.println("Accessing .." + physicalFileRequested);
            if (!physicalFileRequested.getCanonicalPath().startsWith(archivePath.getCanonicalPath())) { //Requester is trying to go above the archive directory
         response.setStatus(HttpServletResponse.SC_FORBIDDEN);
         return null;
            }
            if (!physicalFileRequested.exists()) {
         response.setStatus(HttpServletResponse.SC_NOT_FOUND);
         return null;         
            }           
            if (physicalFileRequested.isFile()) {
         streamFile(physicalFileRequested,response);
         return null;
            } else if (physicalFileRequested.isDirectory()){
         if (! restOfTheUrl.endsWith("/")) {
             response.sendRedirect(request.getContextPath() + "/archive/files" + restOfTheUrl + "/");
         }
         System.out.println("Accessing dir:" + physicalFileRequested);
         ModelAndView modelAndView=new ModelAndView("direcoryListing");
         modelAndView.addObject("fileList", physicalFileRequested.listFiles());
         return modelAndView;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Error accessing requested file/directory.");
        }
 response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 return null;         
    }


And a freemarker view, direcoryListing.ftl:

<html>
<body>
<h1>Welcome to the download page</h1>
<a href='..'>..</a><br>
<#list fileList as file>
<a href='${file.name}'> ${file.name}</a><br>
</#list>
</body>
</html>

Configure freemarker in application context:

<!-- freemarker config -->
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/pages/" />
</bean>           
<!-- View resolvers can also be configured with ResourceBundles or XML files. 
If you need different view resolving based on Locale, you have to use the 
resource bundle resolver. -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
</bean>

Monday, April 8, 2013

Tiles Boardgame

During my college days I was introduced to a board game. We used to play that in the breaks, by drawing the board on paper and using two different pens to differentiate the players' pieces.

The board game is a two player game and like tic-tac-toe, but of a larger size. The board is typically a 7x7 square. The goal is for a player to occupy 4 contiguous boxes in the board, either horizontally, vertically or diagonally.

One day, in my friend Jerine's home, we were test driving VB for the first time and we decided to build this game using VB. In a few hours we had the VB implementation of the game with a very basic computer opponent. It was fun and we did not think about it much after then.

In a sudden rush of nostalgia I thought of implementing that in JS. It is now available in Google code http://tiles-game.googlecode.com Github https://github.com/kkleokrish/tiles-game. The core of the game is in Tiles.js and the HTML files are rudimentary UI on top that, just to visualize the functionality.