package com.smartisanos.sidebar.util;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Files.FileColumns;
import android.provider.MediaStore.Video;
import android.util.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class RecentFileManager extends DataManager implements IClear{
private static final String TAG = RecentFileManager.class.getName();
private static final String DB_NAME = "UselessFile";
private volatile static RecentFileManager sInstance;
public synchronized static RecentFileManager getInstance(Context context){
if(sInstance == null){
synchronized(RecentFileManager.class){
if(sInstance == null){
sInstance = new RecentFileManager(context);
}
}
}
return sInstance;
}
private static final String[] FILE_PROJECTION = new String[] {
FileColumns._ID,
FileColumns.TITLE,
FileColumns.DATA,
FileColumns.SIZE,
FileColumns.DATE_MODIFIED,
FileColumns.MIME_TYPE,
};
private Context mContext;
private Handler mHandler;
private static final int MSG_UPDATE_DATABASE_LIST = 0;
private static final int MSG_SEARCH_FILE = 1;
private static final String VOLUME_EXTERNAL = "external";
private static final Uri[] URIS = new Uri[] {
Audio.Media.getContentUri(VOLUME_EXTERNAL),
Video.Media.getContentUri(VOLUME_EXTERNAL)
};
private static final String[] TARGET_DIR = new String[]{
Environment.getExternalStorageDirectory().getAbsolutePath()+"/tencent/QQfile_recv/",
Environment.getExternalStorageDirectory().getAbsolutePath()+"/tencent/MicroMsg/Download/",
Environment.getExternalStorageDirectory().getAbsolutePath()+"/DingTalk/",
Environment.getExternalStorageDirectory().getAbsolutePath()+"/微盘/",
Environment.getExternalStorageDirectory().getAbsolutePath()+"/yunpan/",
Environment.getExternalStorageDirectory().getAbsolutePath()+"/BaiduNetdisk/",
Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/",
};
private List<FileInfo> mList = new ArrayList<FileInfo>();
private List<FileInfo> mCursorCacheList = new ArrayList<FileInfo>();
private List<FileInfo> mSearchCacheList = new ArrayList<FileInfo>();
private boolean mRegistered;
private DatabaseObserver mDatabaseObserver;
private ClearDatabaseHelper mDatabaseHelper;
private RecentFileManager(Context context) {
mContext = context;
HandlerThread thread = new HandlerThread(RecentFileManager.class.getName());
thread.start();
mHandler = new FileManagerHandler(thread.getLooper());
mDatabaseObserver = new DatabaseObserver(mHandler);
mDatabaseHelper = new ClearDatabaseHelper(mContext,DB_NAME, mCallback);
}
private ClearDatabaseHelper.Callback mCallback = new ClearDatabaseHelper.Callback() {
@Override
public void onInitComplete() {
sendMessageIfNotExist(MSG_SEARCH_FILE);
sendMessageIfNotExist(MSG_UPDATE_DATABASE_LIST);
}
};
public List<FileInfo> getFileList(){
synchronized (RecentFileManager.class) {
List<FileInfo> recentList = new ArrayList<FileInfo>();
recentList.addAll(mList);
return recentList;
}
}
public void startSearchFile() {
sendMessageIfNotExist(MSG_SEARCH_FILE);
}
public void startFileObserver(){
synchronized (mDatabaseObserver) {
if (!mRegistered) {
for (Uri uri : URIS) {
mContext.getContentResolver().registerContentObserver(uri,
true, mDatabaseObserver);
}
mContext.getContentResolver().registerContentObserver(
RecorderInfo.RECORDER_URI, true, mDatabaseObserver);
mRegistered = true;
}
}
sendMessageIfNotExist(MSG_UPDATE_DATABASE_LIST);
}
public void stopFileObserver() {
mHandler.removeMessages(MSG_SEARCH_FILE);
synchronized (mDatabaseObserver) {
if (mRegistered) {
mContext.getContentResolver().unregisterContentObserver(mDatabaseObserver);
mRegistered = false;
}
}
}
public void onClearSetChange(){
sortRecentFileList();
}
private List<String> searchDestinationFolder(File dir) {
List<String> filePathList = new ArrayList<String>();
if (dir.exists()) {
for (File file : dir.listFiles()) {
if (file.isFile()) {
filePathList.add(file.getAbsolutePath());
} else {
filePathList.addAll(searchDestinationFolder(file));
}
}
}
return filePathList;
}
private void searchFile(){
List<String> allFile = new ArrayList<String>();
for(String path : TARGET_DIR){
allFile.addAll(searchDestinationFolder(new File(path)));
}
mSearchCacheList.clear();
for(int i = 0 ; i < allFile.size() ; i++){
String filePath = allFile.get(i);
FileInfo info = new FileInfo(filePath);
if(info.valid()){
mSearchCacheList.add(info);
}
}
if (false) {
Log.d(TAG, "dump search cache list !");
for (FileInfo info : mSearchCacheList) {
Log.d(TAG, "sdcard.fileinfo -> " + info.filePath);
}
}
}
private void updateDatabaseContent() {
ThreadVerify.verify(false);
mCursorCacheList.clear();
for (Uri uri : URIS) {
mCursorCacheList.addAll(getFileInfoByCursor(mContext
.getContentResolver().query(uri, FILE_PROJECTION, null, null, null)));
}
mCursorCacheList.addAll(RecorderInfo.getFileInfoFromRecorder(mContext));
if (false) {
Log.d(TAG, "dump cursor cache list !");
for (FileInfo info : mCursorCacheList) {
Log.d(TAG, "database.fileinfo -> " + info.filePath);
}
}
}
private void sortRecentFileList() {
if(!mDatabaseHelper.isDataSetOk()){
return;
}
List<FileInfo> allInfo = new ArrayList<FileInfo>();
Set<Integer> clearSet = mDatabaseHelper.getSet();
Set<String> dataSet = new HashSet<String>();
for (FileInfo info : mCursorCacheList) {
info.refresh();
if (!clearSet.contains(info.getHashKey())
&& !dataSet.contains(info.filePath)) {
dataSet.add(info.filePath);
allInfo.add(info);
}
}
for (FileInfo info : mSearchCacheList) {
info.refresh();
if (!clearSet.contains(info.getHashKey())
&& !dataSet.contains(info.filePath)) {
dataSet.add(info.filePath);
allInfo.add(info);
}
}
FileComparator comparator = new FileComparator();
Collections.sort(allInfo, comparator);
synchronized (RecentFileManager.class) {
mList.clear();
mList.addAll(allInfo);
}
notifyListener();
}
private class FileComparator implements Comparator<FileInfo> {
public int compare(FileInfo fileInfo1, FileInfo fileInfo2) {
long time1 = fileInfo1.lastTime;
long time2 = fileInfo2.lastTime;
if (time1 == time2) {
return 0;
}
if (time1 < time2) {
return 1;
} else {
return -1;
}
}
}
private List<FileInfo> getFileInfoByCursor(Cursor cursor) {
List<FileInfo> infos = new ArrayList<FileInfo>();
if (cursor != null) {
try {
Set<Integer> clearSet = mDatabaseHelper.getSet();
if (cursor.moveToFirst()) {
do {
int size = cursor.getInt(cursor.getColumnIndexOrThrow(FileColumns.SIZE));
if (size == 0) {
continue;
}
String filePath = cursor.getString(cursor.getColumnIndexOrThrow(FileColumns.DATA));
String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(FileColumns.MIME_TYPE));
FileInfo info = new FileInfo(filePath, mimeType);
if (info.valid()) {
if (!clearSet.contains(info.getHashKey())) {
infos.add(info);
}
}
} while (cursor.moveToNext());
}
} catch(Exception e){
// NA
} finally {
cursor.close();
}
}
return infos;
}
private class ReceiveFileOberver extends FileObserver{
public ReceiveFileOberver(String path) {
super(path);
}
@Override
public void onEvent(int event, String path) {
// NA
}
}
private class DatabaseObserver extends ContentObserver{
public DatabaseObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
sendMessageIfNotExist(MSG_UPDATE_DATABASE_LIST);
}
}
private void sendMessageIfNotExist(int msgId) {
if (!mHandler.hasMessages(msgId)) {
mHandler.obtainMessage(msgId).sendToTarget();
}
}
private class FileManagerHandler extends Handler {
public FileManagerHandler(Looper looper) {
super(looper, null, false);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_DATABASE_LIST:
updateDatabaseContent();
sortRecentFileList();
break;
case MSG_SEARCH_FILE:
searchFile();
sortRecentFileList();
break;
}
}
}
@Override
public void clear() {
synchronized (RecentFileManager.class) {
List<Integer> clearList = new ArrayList<Integer>();
for(FileInfo fi : mList){
clearList.add(fi.getHashKey());
}
mDatabaseHelper.addUselessId(clearList);
mList.clear();
}
notifyListener();
}
public void refresh() {
notifyListener();
}
}