package com.njtransit.service; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.Timer; import java.util.TimerTask; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.json.JSONObject; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import com.njtransit.Root; import com.njtransit.rail.R; public class UpdaterService extends Service { public class LocalBinder extends Binder { UpdaterService getService() { return UpdaterService.this; } } private final IBinder mBinder = new LocalBinder(); private DefaultHttpClient client; private Timer timer; public IBinder onBind(Intent arg0) { return mBinder; } @Override public void onCreate() { super.onCreate(); timer = new Timer(false); timer.schedule(new TimerTask() { public void run() { Context ctx = getApplicationContext(); int lastVersion = Root.getDatabaseVersion(ctx); int version = Root.getVersion(ctx); Date lastChecked = Root.getLastChecked(ctx); if (lastChecked != null) { long now = System.currentTimeMillis(); Long updateThreshold = Long.parseLong(getResources() .getString(R.string.update_threshold)); if (now - lastChecked.getTime() < updateThreshold) { UpdaterService.this.stopSelf(); return; } } HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, "utf-8"); params.setBooleanParameter("http.protocol.expect-continue", false); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80)); ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager( params, registry); HttpConnectionParams.setConnectionTimeout(params, 2000); HttpConnectionParams.setSoTimeout(params, 2000); client = new DefaultHttpClient(manager, params); String postUrl = getResources().getString(R.string.update_url); HttpPost post = new HttpPost(postUrl); try { HttpResponse response = client.execute(post); int status = response.getStatusLine().getStatusCode(); if (status >= 200 && status < 300) { String updateString = read(response.getEntity() .getContent()); JSONObject update = new JSONObject(updateString); Integer newestVersion = update.getInt("version"); String sha = update.getString("sha"); Long length = update.getLong("length"); if (newestVersion > version && newestVersion > lastVersion) { String url = update.getString("url"); HttpGet get = new HttpGet(url); File fileDir = ctx.getFilesDir(); File downloads = new File(fileDir, "downloads"); downloads.mkdirs(); for (File file : downloads.listFiles()) { if (!file.getName().endsWith( newestVersion + ".tmp")) { file.delete(); } } File newDB = new File(downloads, newestVersion + ".tmp"); Long newDBLength = newDB.length(); boolean resume = false; if (newDB.exists()) { if (length.equals(newDBLength)) { String newSha = SHA1(newDB); if (newSha.equals(sha)) { Root.saveDatabaseVersion(ctx, newestVersion); Root.setMoveOnRestart(ctx, "downloads/" + newDB.getName()); Root.setLastChecked(ctx, System.currentTimeMillis()); } } else { if (newDBLength > length) { newDB.delete(); } else { resume = true; get.addHeader("Range", "bytes=" + newDB.length() + "-"); } } } response = client.execute(get); status = response.getStatusLine().getStatusCode(); if (status >= 200 && status < 300) { byte[] buffer = new byte[1024 * 5]; InputStream in = response.getEntity() .getContent(); int read; FileOutputStream fos = null; newDB.createNewFile(); try { fos = new FileOutputStream(newDB, resume); while ((read = in.read(buffer)) != -1) { fos.write(buffer, 0, read); } fos.flush(); fos.close(); String newDBSha = SHA1(newDB); if (sha.equals(newDBSha)) { Root.saveDatabaseVersion(ctx, newestVersion); Root.setMoveOnRestart(ctx, "downloads/" + newDB.getName()); Root.setLastChecked(ctx, System.currentTimeMillis()); } else { newDB.delete(); } } catch (Exception e) { } finally { if (fos != null) { fos.flush(); fos.close(); } } } } else { Root.setLastChecked(ctx, System.currentTimeMillis()); } } } catch (Exception e) { e.printStackTrace(); } finally { } } }, 30000); } private static String convertToHex(byte[] data) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < data.length; i++) { int halfbyte = (data[i] >>> 4) & 0x0F; int two_halfs = 0; do { if ((0 <= halfbyte) && (halfbyte <= 9)) buf.append((char) ('0' + halfbyte)); else buf.append((char) ('a' + (halfbyte - 10))); halfbyte = data[i] & 0x0F; } while (two_halfs++ < 1); } return buf.toString(); } public static String SHA1(File file) throws NoSuchAlgorithmException, FileNotFoundException { FileInputStream fis = new FileInputStream(file); return SHA1(fis); } public static String SHA1(InputStream is) throws NoSuchAlgorithmException { MessageDigest md; md = MessageDigest.getInstance("SHA-1"); byte[] sha1hash = new byte[40]; int read = 0; byte[] buffer = new byte[1024 * 5]; try { while ((read = is.read(buffer)) != -1) { md.update(buffer, 0, read); } } catch (Exception e) { throw new RuntimeException(e); } finally { try { is.close(); } catch (Exception e) { } } sha1hash = md.digest(); return convertToHex(sha1hash); } public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } private static String read(InputStream in) throws IOException { StringBuilder sb = new StringBuilder(); BufferedReader r = new BufferedReader(new InputStreamReader(in), 1000); for (String line = r.readLine(); line != null; line = r.readLine()) { sb.append(line); } in.close(); return sb.toString(); } }