/**
* Copyright (C) 2011, Karsten Priegnitz
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* @author: Karsten Priegnitz
* @see: http://code.google.com/p/android-change-log/
*/
package com.noshufou.android.su.widget;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.preference.PreferenceManager;
import android.util.Log;
import android.webkit.WebView;
import com.noshufou.android.su.R;
public class ChangeLog {
private final Context context;
private int lastVersion, thisVersion;
// this is the key for storing the version name in SharedPreferences
private static final String VERSION_KEY = "pref_version_key";
/**
* Constructor
*
* Retrieves the version names and stores the new version name in
* SharedPreferences
*/
public ChangeLog(Context context) {
this.context = context;
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(context);
// get version numbers
try {
this.lastVersion = sp.getInt(VERSION_KEY, 0);
} catch (ClassCastException e) {
// Coming from the old version of tracking by version name
this.lastVersion = 0;
}
Log.d(TAG, "lastVersion: " + lastVersion);
try {
this.thisVersion = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0).versionCode;
} catch (NameNotFoundException e) {
this.thisVersion = 0;
Log.e(TAG, "could not get version name from manifest!");
e.printStackTrace();
}
Log.d(TAG, "appVersion: " + this.thisVersion);
// save new version number to preferences
SharedPreferences.Editor editor = sp.edit();
editor.putInt(VERSION_KEY, this.thisVersion);
editor.commit();
}
/**
* @return The version name of the last installation of this app (as
* described in the former manifest). This will be the same as
* returned by <code>getThisVersion()</code> from the second time
* this version of the app is launched (more precisely: the
* second time ChangeLog is instantiated).
* @see AndroidManifest.xml#android:versionName
*/
public int getLastVersion() {
return this.lastVersion;
}
/**
* manually set the last version name - for testing purposes only
* @param lastVersion
*/
void setLastVersion(int lastVersion) {
this.lastVersion = lastVersion;
}
/**
* @return The version name of this app as described in the manifest.
* @see AndroidManifest.xml#android:versionName
*/
public int getThisVersion() {
return this.thisVersion;
}
/**
* @return <code>true</code> if this version of your app is started the
* first time
*/
public boolean firstRun() {
return this.lastVersion < this.thisVersion;
}
/**
* @return <code>true</code> if your app is started the first time ever.
* Also <code>true</code> if your app was deinstalled and
* installed again.
*/
public boolean firstRunEver() {
return "".equals(this.lastVersion);
}
/**
* @return an AlertDialog displaying the changes since the previous
* installed version of your app (what's new).
*/
public AlertDialog getLogDialog() {
return this.getDialog(false);
}
/**
* @return an AlertDialog with a full change log displayed
*/
public AlertDialog getFullLogDialog() {
return this.getDialog(true);
}
private AlertDialog getDialog(boolean full) {
WebView wv = new WebView(this.context);
wv.setBackgroundColor(0); // transparent
wv.loadData(this.getLog(full), "text/html", "UTF-8");
AlertDialog.Builder builder = new AlertDialog.Builder(this.context);
builder.setTitle(context.getResources().getString(
full
? R.string.changelog_full_title
: R.string.changelog_title))
.setView(wv)
.setCancelable(true) // Set to true, personal preference (chainsdd)
.setPositiveButton(
context.getResources().getString(
R.string.ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
return builder.create();
}
/**
* @return HTML displaying the changes since the previous
* installed version of your app (what's new)
*/
public String getLog() {
return this.getLog(false);
}
/**
* @return HTML which displays full change log
*/
public String getFullLog() {
return this.getLog(true);
}
/** modes for HTML-Lists (bullet, numbered) */
private enum Listmode {
NONE,
ORDERED,
UNORDERED,
};
private Listmode listMode = Listmode.NONE;
private StringBuffer sb = null;
private static final int EOCL = -1;
private String getLog(boolean full) {
// read changelog.txt file
sb = new StringBuffer();
try {
InputStream ins = context.getResources().openRawResource(
R.raw.changelog);
BufferedReader br = new BufferedReader(new InputStreamReader(ins));
String line = null;
boolean advanceToEOVS = false; // true = ignore further version sections
while (( line = br.readLine()) != null){
line = line.trim();
if (line.startsWith("$")) {
// begin of a version section
this.closeList();
int version = Integer.parseInt(line.substring(1).trim());
// stop output?
if (! full) {
if (version < this.lastVersion + 1)
advanceToEOVS = true;
else if (version == EOCL)
advanceToEOVS = false;
}
} else if (! advanceToEOVS) {
if (line.startsWith("%")) {
// line contains version title
this.closeList();
sb.append("<div class='title'>"
+ line.substring(1).trim() + "</div>\n");
} else if (line.startsWith("_")) {
// line contains version title
this.closeList();
sb.append("<div class='subtitle'>"
+ line.substring(1).trim() + "</div>\n");
} else if (line.startsWith("!")) {
// line contains free text
this.closeList();
sb.append("<div class='freetext'>"
+ line.substring(1).trim() + "</div>\n");
} else if (line.startsWith("#")) {
// line contains numbered list item
this.openList(Listmode.ORDERED);
sb.append("<li>"
+ line.substring(1).trim() + "</li>\n");
} else if (line.startsWith("*")) {
// line contains bullet list item
this.openList(Listmode.UNORDERED);
sb.append("<li>"
+ line.substring(1).trim() + "</li>\n");
} else {
// no special character: just use line as is
this.closeList();
sb.append(line + "\n");
}
}
}
this.closeList();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
private void openList(Listmode listMode) {
if (this.listMode != listMode) {
closeList();
if (listMode == Listmode.ORDERED) {
sb.append("<div class='list'><ol>\n");
} else if (listMode == Listmode.UNORDERED) {
sb.append("<div class='list'><ul>\n");
}
this.listMode = listMode;
}
}
private void closeList() {
if (this.listMode == Listmode.ORDERED) {
sb.append("</ol></div>\n");
} else if (this.listMode == Listmode.UNORDERED) {
sb.append("</ul></div>\n");
}
this.listMode = Listmode.NONE;
}
private static final String TAG = "ChangeLog";
}