package com.salama.android.support;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import MetoXML.Util.ClassFinder;
import android.app.Application;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.salama.android.util.SSLog;
import com.salama.android.util.http.HttpClientUtil;
import dalvik.system.DexFile;
public class ServiceSupportApplication extends Application implements ClassFinder {
private static ServiceSupportApplication _singleton = null;
private ExecutorService _defaultThreadPool;
private LocalBroadcastManager _localBroadcastManager = null;
private ConcurrentHashMap<String, Object> _sessionValueMap = new ConcurrentHashMap<String, Object>();
private ConcurrentLinkedQueue<SessionKeyObj> _sessionKeyObjQueue = new ConcurrentLinkedQueue<ServiceSupportApplication.SessionKeyObj>();
private volatile long _lastClearSessionTime = System.currentTimeMillis();
private List<ExecutorService> _threadPoolList = new ArrayList<ExecutorService>();
private static final String SESSION_KEY_PREFIX_BROADCAST_DATA = "broadcastData.";
private long _sessionKeySeq = Long.MIN_VALUE;
private Object _sessionKeySeqLocker = new Object();
private HashMap<String, Class<?>> _classSimpleNameClassMapping = new HashMap<String, Class<?>>();
private HashMap<String, Class<?>> _classNameClassMapping = new HashMap<String, Class<?>>();
private static final int VIEW_ID_MIN = 100;
private static final int VIEW_ID_MAX = 300;
private int _viewIdSeed = VIEW_ID_MIN;
private Object _viewIdSeedLocker = new Object();
public static ServiceSupportApplication singleton() {
return _singleton;
}
@Override
public void onCreate() {
super.onCreate();
SSLog.d("ServiceSupportApplication", "onCreate()");
_singleton = this;
_defaultThreadPool = Executors.newCachedThreadPool();
_localBroadcastManager = LocalBroadcastManager.getInstance(this);
scanClassesOfApplication();
initHttpUserAgent();
}
@Override
public void onTerminate() {
super.onTerminate();
_defaultThreadPool.shutdown();
for(int i = 0; i < _threadPoolList.size(); i++) {
_threadPoolList.get(i).shutdown();
}
_threadPoolList.clear();
_singleton = null;
SSLog.d("ServiceCommonApp", "onTerminate()");
}
/**
* 创建线程池(单线程模式)
* @return 线程池对象(ExecutorService)
*/
public ExecutorService createSingleThreadPool() {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
_threadPoolList.add(threadPool);
return threadPool;
}
/**
* 创建线程池(缓冲模式)
* @return 线程池对象(ExecutorService)
*/
public ExecutorService createCachedThreadPool() {
ExecutorService threadPool = Executors.newCachedThreadPool();
_threadPoolList.add(threadPool);
return threadPool;
}
/**
* 创建线程池(固定数量模式)
* @param threadMaxCount 最大线程数
* @return 线程池对象(ExecutorService)
*/
public ExecutorService createFixedThreadPool(int threadMaxCount) {
ExecutorService threadPool = Executors.newFixedThreadPool(threadMaxCount);
_threadPoolList.add(threadPool);
return threadPool;
}
/**
* 异步执行线程任务(使用cachedThreadPool执行)
* @param task 线程任务
*/
public void asyncExecute(Runnable task) {
_defaultThreadPool.execute(task);
}
/**
* 发送本地通知
* @param intent
*/
public void sendLocalBroadcast(Intent intent) {
_localBroadcastManager.sendBroadcast(intent);
}
/**
* 发送本地通知(数据通过某种方式封装传递给接收方)
* @param broadcastName 通知名
* @param data 参数对象
* @param extraName 参数名(接收时用)
*/
public void sendWrappedLocalBroadcast(String broadcastName, Object data, String extraName) {
Intent intent = new Intent(broadcastName);
if(data != null) {
String dataSessionKey = SESSION_KEY_PREFIX_BROADCAST_DATA + getNewSessionKey();
setSessionValue(dataSessionKey, data);
intent.putExtra(extraName, dataSessionKey);
_sessionKeyObjQueue.add(new SessionKeyObj(dataSessionKey));
}
_localBroadcastManager.sendBroadcast(intent);
}
/**
* 本地通知的接收方获取参数值
* @param intent 本地通知接收时获得的intent
* @param extraName 参数名
* @return
*/
public Object getWrappedDataFromLocalBroadcast(Intent intent, String extraName) {
String sessionKey = intent.getStringExtra(extraName);
if(sessionKey == null) {
return null;
} else {
clearOldSessionKey();
return getSessionValue(sessionKey);
}
}
private void clearOldSessionKey() {
long curTime = System.currentTimeMillis();
long clearInterval = 300000;
if((curTime - _lastClearSessionTime) >= clearInterval) {
int i = 0;
SessionKeyObj keyObj = null;
while(i < 100) {
keyObj = _sessionKeyObjQueue.peek();
if(keyObj == null) {
break;
} else {
if((curTime - keyObj.createTime) >= clearInterval) {
//delete
_sessionValueMap.remove(keyObj.sessionKey);
_sessionKeyObjQueue.poll();
} else {
break;
}
}
i++;
}
}
}
/**
* 取得session值.为便于各个画面之间共享数据,此处提供session容器存储变量。
* @param key
* @return
*/
public Object getSessionValue(String key) {
return _sessionValueMap.get(key);
}
/**
* 取得session值,并且删除
* @param key
* @return
*/
public Object getSessionValueAndRemove(String key) {
Object returnVal = _sessionValueMap.get(key);
_sessionValueMap.remove(key);
return returnVal;
}
/**
* 设置session值
* @param key
* @param value
*/
public void setSessionValue(String key, Object value) {
_sessionValueMap.put(key, value);
}
/**
* 删除session值
* @param key
*/
public void removeSessionValue(String key) {
_sessionValueMap.remove(key);
}
// public Class<?> loadClass(String className) throws ClassNotFoundException {
// return getClassLoader().loadClass(className);
// }
/**
* 根据类名取得类
* @param className 类名。可以是简称也可以全称(包含package)
* @return 类
*/
@Override
public Class<?> findClass(String className) throws ClassNotFoundException {
Class<?> cls = _classSimpleNameClassMapping.get(className);
if(cls != null) {
return cls;
}
cls = _classNameClassMapping.get(className);
if(cls != null) {
return cls;
}
return getClassLoader().loadClass(className);
}
private void scanClassesOfApplication() {
try {
/* hack way
Field dexField = PathClassLoader.class.getDeclaredField("mDexs");
dexField.setAccessible(true);
DexFile[] dexs = (DexFile[]) dexField.get(getClassLoader());
*/
String currentAppPackageName = getPackageName();
String sourceDirPath = getPackageManager().getApplicationInfo(
getPackageName(), 0).sourceDir;
DexFile dexFile = new DexFile(sourceDirPath);
Enumeration<String> entries = dexFile.entries();
String className;
Class<?> cls;
ClassLoader classLoader = getClassLoader();
while(entries.hasMoreElements()) {
className = entries.nextElement();
try {
//cls = dexFile.loadClass(className, getClassLoader());
cls = classLoader.loadClass(className);
if(className.startsWith(currentAppPackageName)
|| className.startsWith("com.salama.android.")
) {
_classSimpleNameClassMapping.put(cls.getSimpleName(), cls);
_classNameClassMapping.put(className, cls);
SSLog.d("ServiceSupportApplication", "scanClassesOfApplication() class:" + className);
}
} catch(Exception e) {
//Log.e("ServiceSupportApplication", "scanClassesOfApplication() Error in while{}", e);
}
}
} catch(Exception e) {
Log.e("ServiceSupportApplication", "scanClassesOfApplication()", e);
}
}
private long getNewSessionKey() {
synchronized (_sessionKeySeqLocker) {
if(_sessionKeySeq == Long.MAX_VALUE) {
_sessionKeySeq = Long.MIN_VALUE;
} else {
_sessionKeySeq++;
}
return _sessionKeySeq;
}
}
/**
* 取得新viewId。提供了一个顺序自增长的序号。
* @return
*/
public int newViewId() {
synchronized (_viewIdSeedLocker) {
if(_viewIdSeed == VIEW_ID_MAX) {
_viewIdSeed = VIEW_ID_MIN;
} else {
_viewIdSeed++;
}
return _viewIdSeed;
}
}
private class SessionKeyObj {
public String sessionKey = null;
public long createTime = System.currentTimeMillis();
public SessionKeyObj(String key) {
sessionKey = key;
}
}
private void initHttpUserAgent() {
PackageInfo pkgInfo;
try {
pkgInfo = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
String userAgent = "Android " + Build.VERSION.RELEASE + ";"
+ "API " + Build.VERSION.SDK_INT + ";"
+ "APP " + this.getPackageName() + " " + pkgInfo.versionName + ";"
+ "salama" + ";";
HttpClientUtil.setUserAgent(userAgent);
//SalamaHttpClientUtil.setUserAgent(userAgent);
SSLog.d("ServiceSupportApplication", "setUserAgent:" + userAgent);
} catch (Exception e) {
SSLog.i("ServiceSupportApplication", "", e);
}
}
}