import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;
import com.bitvf.bitcoinWallet.base.JJApplication;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class FileLogger {
private static final String TAG = "FileLogger";
private static final long MB = 1024 * 1024;
private static final long LOG_LIMIT = 1 * 1024 * 1024;
private static final long FREE_SPACE_LIMIT = 5 * 1024 * 1024;
private static final long FREE_SPACE_TIMER = 20 * 60 * 1000;
private static final int DAY_LIMIT = 3; //日志保存的天数
private static final String INFO_COLOR = "green";
private static final String ERROR_COLOR = "red";
private static final String WARN_COLOR = "orange";
private static final String DEBUG_COLOR = "blue";
private ExecutorService singleThreadService = Executors.newSingleThreadExecutor();
private Timer timer = null;
private boolean spaceAvailable = true;
void d(String tag, String msg) {
startThreadService(DEBUG_COLOR, "[" + tag + "]" + msg);
}
void e(String tag, String msg) {
startThreadService(ERROR_COLOR, "[" + tag + "]" + "[ERROR]" + msg);
}
void i(String tag, String msg) {
startThreadService(INFO_COLOR, "[" + tag + "]" + msg);
}
void w(String tag, String msg) {
startThreadService(WARN_COLOR, "[" + tag + "]" + "[WARN]" + msg);
}
void v(String tag, String msg) {
startThreadService(INFO_COLOR, "[" + tag + "]" + msg);
}
private void startThreadService(String tag, String msg) {
File file = getLogRoot();
if ((file == null) || (!file.exists())) {
return;
}
singleThreadService.execute(getWriterRunnable(tag, msg));
}
private Runnable getWriterRunnable(final String tag, final String msg) {
Runnable runnable = new Runnable() {
public void run() {
try {
File file = getLogRoot();
if ((file == null) || (!file.exists())) {
return;
}
if ((timer == null) && (!freeSpace())) {
return;
}
FileLogger.this.startCleanUpTimer();
File availableFile = FileLogger.this.getAvailableFile();
if (availableFile == null) {
return;
}
boolean available = false;
if (!availableFile.exists()) {
try {
availableFile.createNewFile();
available = true;
} catch (IOException e) {
e.printStackTrace();
}
}
if (!availableFile.exists()) {
return;
}
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(availableFile, true);
if (available) {
String header = "<header>"
+ "<meta http-equiv=" + "\""
+ "Content-Type" + "\"" + " content="
+ "\"" + "text/html; charset=UTF-8" + "\">"
+ "</header>";
fileOutputStream.write(header.getBytes());
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
String strDate = simpleDateFormat.format(new Date());
String body = "<p><font color =\"" + tag + "\">" + strDate + " " + msg.replaceAll(">", ">").replaceAll("<", "<") + "</p>";
fileOutputStream.write(body.getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return;
} catch (NullPointerException e) {
e.printStackTrace();
if(null != e) {
Log.e(TAG, e.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
if(null != e) {
Log.e(TAG, e.getMessage());
}
}
}
};
return runnable;
}
private File getAvailableFile() {
File rootFile = getLogRoot();
if ((rootFile == null) || (!rootFile.exists())) {
return null;
}
removeOldFolders();
File file = getLogFolder();
int index = 0;
List<File> fileList = null;
File[] files = file.listFiles();
if ((files != null) && (files.length > 0)) {
fileList = Arrays.asList(files);
if (fileList.size() > 1) {
getSortedFileListByName(fileList);
files = (File[]) fileList.toArray();
}
String name = files[0].getName();
String cntName = name.substring(0, name.indexOf("."));
try {
index = Integer.parseInt(cntName);
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Wrong cntName! : " + cntName);
}
if (files[0].length() >= MB / 2) {
index++;
}
}
String fileName = getLogFileName(index);
return new File(file, fileName);
}
private static String getLogFileName(int index) {
return String.format("%03d", index) + ".html";
}
private File getLogFolder() {
File rootFile = getLogRoot();
File file = new File(rootFile, getCurrentDate());
if (!file.exists()) {
file.mkdirs();
}
return file;
}
private void removeFolderBeforeDay(String strDate, int offset) {
String strBeforeDate = getSpecifiedDayBefore(strDate, offset);
File rootFile = getLogRoot();
File file = new File(rootFile, strBeforeDate);
if (file.exists()) {
deleteFile(file);
}
}
private void removeOldFolders() {
File file = getLogRoot();
if ((file == null) || (!file.exists())) {
return;
}
String strDate = getCurrentDate();
String strYesterdayDate = getSpecifiedDayBefore(strDate, -1);
String strBeforeYesterdayDate = getSpecifiedDayBefore(strDate, -2);
File[] files = file.listFiles();
if (files == null) {
return;
}
for (File subFile : files) {
if (subFile.isDirectory()) {
String fileName = subFile.getName();
if (!fileName.contains(strDate) && !fileName.contains(strYesterdayDate) && !fileName.contains(strBeforeYesterdayDate)) {
deleteFile(subFile);
}
} else {
subFile.delete();
}
}
}
private static void deleteFile(File file) {
if (file == null) {
return;
}
if (file.exists()) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File subFile : files) {
deleteFile(subFile);
}
}
file.delete();
} else {
file.delete();
}
}
}
private static long getDirSize(File floder) {
if (floder == null) {
return 0L;
}
if (floder.isDirectory()) {
long size = 0L;
File[] files = floder.listFiles();
if (files != null) {
for (File subFile : files) {
size += getDirSize(subFile);
}
}
return size;
}
return floder.length();
}
private static String getSpecifiedDayBefore(String strDate, int offset) {
Calendar calendar = Calendar.getInstance();
Date date = null;
try {
date = new SimpleDateFormat("yyyyMMdd").parse(strDate);
} catch (ParseException e) {
e.printStackTrace();
}
calendar.setTime(date);
calendar.add(Calendar.DATE, offset);
String dateTime = new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
return dateTime;
}
private static File getStorageDir() {
if (Environment.getExternalStorageState().equals("mounted")) {
return Environment.getExternalStorageDirectory();
}
return Environment.getDataDirectory();
}
private static void getSortedFileListByName(List<File> fileList) {
Collections.sort(fileList, new Comparator<File>() {
public int compare(File lhs, File rhs) {
return lhs.getName().compareTo(rhs.getName());
}
});
}
private boolean spaceIsAlearting() {
return getCurrentAvailabeSpace() < FREE_SPACE_LIMIT;
}
private boolean logSizeAlearting() {
return getDirSize(getLogRoot()) > LOG_LIMIT;
}
boolean freeSpace() {
File file = getLogRoot();
if ((file == null) || (!file.exists())) {
return false;
}
if (spaceIsAlearting()) {
Log.w(TAG, "there is no availabe free space and try to free space");
freeLogFolder();
return !spaceIsAlearting();
}
checkAndFreeLogFiles();
return true;
}
private void freeLogFolder() {
deleteFile(getLogRoot());
}
private void freeOldFolders() {
File[] files = getLogRoot().listFiles();
for (File file : files) {
if ((file.isDirectory()) && (!file.getName().contains(getCurrentDate()))) {
deleteFile(file);
} else {
file.delete();
}
}
}
private String getCurrentDate() {
return new SimpleDateFormat("yyyyMMdd").format(new Date());
}
private void freeOldFiles() {
File[] files = getLogFolder().listFiles();
if (files != null) {
List<File> fileList = Arrays.asList(files);
getSortedFileListByName(fileList);
if (fileList.size() > 5) {
int i = fileList.size();
for (int j = 5; j < i; j++) {
Log.w(TAG, "try to delete file : " + fileList.get(j).getAbsoluteFile());
fileList.get(j).delete();
}
}
}
}
@TargetApi(18)
private static long getCurrentAvailabeSpace() {
StatFs statFs = new StatFs(getStorageDir().getPath());
if (Build.VERSION.SDK_INT >= 18) {
return statFs.getAvailableBytes();
}
long availableBlocks = statFs.getAvailableBlocks();
long blockSize = statFs.getBlockSize();
return availableBlocks * blockSize;
}
File getLogRoot() {
try {
Context context = JJApplication.getInstance();
String filePath = "/Android/data/" + context.getPackageName() + "/log/";
File file = new File(getStorageDir(), filePath);
synchronized (this) {
if (!file.exists()) {
file.mkdirs();
}
}
return file;
} catch (Throwable e) {
return null;
}
}
void checkAndFreeLogFiles() {
if (logSizeAlearting()) {
Log.w(TAG, "the log size is > 8M, try to free log files");
freeOldFolders();
Log.w(TAG, "old folders are deleted");
if (logSizeAlearting()) {
Log.w(TAG, "try to delete old log files");
freeOldFiles();
}
}
}
private void startCleanUpTimer() {
synchronized (this) {
if (timer == null) {
timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
singleThreadService.execute(new Runnable() {
public void run() {
try {
File file = getLogRoot();
if ((file == null) || (!getLogRoot().exists())) {
return;
}
spaceAvailable = freeSpace();
} catch (NullPointerException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
}
});
}
};
timer.schedule(task, FREE_SPACE_TIMER, FREE_SPACE_TIMER);
}
}
}
}