package com.openims.service;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.Toast;
import com.openims.downloader.DownloadInf;
import com.openims.model.pushService.PushInfoManager;
import com.openims.service.notificationPacket.RegPushIQ;
import com.openims.utility.DeviceFun;
import com.openims.utility.LogUtil;
import com.openims.utility.PushServiceUtil;
import com.openims.widgets.BigToast;
import com.smit.EasyLauncher.R;
public class IMService extends Service {
private static final String TAG = LogUtil.makeLogTag(IMService.class);
private static final String PRE = LogUtil.makeTag(IMService.class);
public static final String SERVICE_NAME = "com.openims.service.IMService";
private ExecutorService executorService;
private TaskSubmitter taskSubmitter;
private TaskTracker taskTracker;
private XmppManager xmppManager;
private SharedPreferences sharedPrefs;
/** Keeps track of all current registered clients. */
private List<Messenger> mClients = Collections.synchronizedList(
new ArrayList<Messenger>());
final Messenger mMessenger = new Messenger(new IncomingHandler());
private Map<Integer,DownloadAsyncTask> mDownloadTaskMap = null;
private View mPopupView;
private int mCurrentY;
private WindowManager mWindowManager;
private WindowManager.LayoutParams mWmlp;
public IMService(){
executorService = Executors.newSingleThreadExecutor();
taskSubmitter = new TaskSubmitter(this);
taskTracker = new TaskTracker(this);
}
@Override
public void onCreate(){
Log.d(TAG, PRE + "onCreate()...");
initSetting();
initDeviceId();
xmppManager = new XmppManager(this);
//alertbox(null,null);
}
@Override
public void onStart(Intent intent, int startId) {
Log.d(TAG, PRE + "onStart()...");
String action = intent.getAction();
if(PushServiceUtil.ACTION_SERVICE_STATUS.equals(action)){
getStatus();
}else if(PushServiceUtil.ACTION_SERVICE_REGISTER.equals(action)){
registerPush(intent);
}else if(PushServiceUtil.ACTION_SERVICE_MESSAGE.equals(action)){
sendMessageChat(intent);
}else if(PushServiceUtil.ACTION_SERVICE_PUBSUB.equals(action)){
sendTopic(intent);
}else if(PushServiceUtil.ACTION_SERVICE_CONNECT.equals(action)){
autoLogin();
}else if(PushServiceUtil.ACTION_SERVICE_LOGIN.equals(action)){
//TODO get login information and write to preference
String username = intent.getStringExtra(PushServiceUtil.XMPP_USERNAME);
String password = intent.getStringExtra(PushServiceUtil.XMPP_PASSWORD);
boolean auto_login = intent.getBooleanExtra(PushServiceUtil.XMPP_AUTO_LOGIN,false);
setLogin(username,password,auto_login);
login();
}else if(PushServiceUtil.ACTION_SERVICE_REGISTER_USER.equals(action)){
String username = intent.getStringExtra(PushServiceUtil.XMPP_USERNAME);
String password = intent.getStringExtra(PushServiceUtil.XMPP_PASSWORD);
xmppManager.registerAccount(username, password);
}else if(PushServiceUtil.ACTION_SERVICE_LOGOUT.equals(action)){
if(xmppManager.isAuthenticated())
logout();
}
}
public void autoLogin(){
if(isAutoLogin()){
//����if,�����Զ���¼�ᱨ��
if(!xmppManager.isAuthenticated())
login();
}
}
@Override
public void onDestroy() {
Log.d(TAG, PRE + "onDestroy()...");
logout();
}
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
@Override
public void onRebind(Intent intent) {
Log.d(TAG, PRE + "onRebind()...");
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, PRE + "onUnbind()...");
return true;
}
public void disconnect() {
Log.d(TAG, PRE + "disconnect()...");
if(getXmppManager().getConnection() == null){
return;
}
taskSubmitter.submit(new Runnable() {
public void run() {
getXmppManager().disconnect();
}
});
}
//----------------getter--------------------
public static Intent getIntent() {
return new Intent(SERVICE_NAME);
}
public ExecutorService getExecutorService() {
return executorService;
}
public TaskSubmitter getTaskSubmitter() {
return taskSubmitter;
}
public TaskTracker getTaskTracker() {
return taskTracker;
}
public XmppManager getXmppManager() {
return xmppManager;
}
public SharedPreferences getSharedPreferences() {
return sharedPrefs;
}
/**
* Class for summiting a new runnable task.
*/
public class TaskSubmitter {
final IMService imService;
public TaskSubmitter(IMService notificationService) {
this.imService = notificationService;
}
@SuppressWarnings("unchecked")
public Future submit(Runnable task) {
Future result = null;
if (!imService.getExecutorService().isTerminated()
&& !imService.getExecutorService().isShutdown()
&& task != null) {
result = imService.getExecutorService().submit(task);
}
return result;
}
}
/**
* Class for monitoring the running task count.
*/
public class TaskTracker {
final IMService imService;
public int count;
public TaskTracker(IMService notificationService) {
this.imService = notificationService;
this.count = 0;
}
public void increase() {
synchronized (imService.getTaskTracker()) {
imService.getTaskTracker().count++;
Log.d(TAG, PRE + "Incremented task count to " + count);
}
}
public void decrease() {
synchronized (imService.getTaskTracker()) {
imService.getTaskTracker().count--;
Log.d(TAG, PRE + "Decremented task count to " + count);
}
}
}
/**
* read default data and write to shared preference
*/
private Properties loadProperties() {
Properties props = new Properties();
try {
/*int id = this.getResources().getIdentifier("androidpn", "raw",
this.getPackageName());
props.load(this.getResources().openRawResource(id));*/
FileInputStream s = new FileInputStream("/sdcard/ehotel/androidpn.properties");
//props.loadFromXML(s);
props.load(s);
} catch (Exception e) {
Log.e(TAG, PRE + "Could not find the properties file.", e);
e.printStackTrace();
}
return props;
}
private boolean isAutoLogin(){
return sharedPrefs.getBoolean(PushServiceUtil.XMPP_AUTO_LOGIN,false);
}
private void setLogin(String userName,String password,boolean bAutoLogin){
Editor editor = sharedPrefs.edit();
editor.putString(PushServiceUtil.XMPP_USERNAME, userName);
editor.putString(PushServiceUtil.XMPP_PASSWORD, password);
editor.putBoolean(PushServiceUtil.XMPP_AUTO_LOGIN, bAutoLogin);
editor.commit();
xmppManager.initUserInf();
}
private void initSetting(){
sharedPrefs = getSharedPreferences(PushServiceUtil.SHARED_PREFERENCE_NAME,
Context.MODE_PRIVATE);
Properties props;
String version = "0.5.0";
String apiKey;
String xmppHost;
String xmppPort;
String userName;
String password;
props = loadProperties();
apiKey = props.getProperty("apiKey", "");
xmppHost = props.getProperty("xmppHost", "127.0.0.1");
xmppPort = props.getProperty("xmppPort", "5222");
userName = props.getProperty("userName","");
password = props.getProperty("password","");
Log.i(TAG, PRE + "apiKey=" + apiKey);
Log.i(TAG, PRE + "xmppHost=" + xmppHost);
Log.i(TAG, PRE + "xmppPort=" + xmppPort);
Editor editor = sharedPrefs.edit();
editor.putString(PushServiceUtil.API_KEY, apiKey);
editor.putString(PushServiceUtil.VERSION, version);
editor.putString(PushServiceUtil.XMPP_HOST, xmppHost);
editor.putInt(PushServiceUtil.XMPP_PORT, Integer.parseInt(xmppPort));
editor.putString(PushServiceUtil.XMPP_USERNAME, userName);
editor.putString(PushServiceUtil.XMPP_PASSWORD, password);
editor.commit();
}
private void initDeviceId(){
String deviceId = DeviceFun.getDeviceID();
Editor editor = sharedPrefs.edit();
editor.putString(PushServiceUtil.DEVICE_ID, deviceId);
editor.commit();
if (deviceId == null
|| deviceId.trim().length() == 0
|| deviceId.matches("0+")) {
if (sharedPrefs.contains("EMULATOR_DEVICE_ID")) {
deviceId = sharedPrefs.getString(PushServiceUtil.EMULATOR_DEVICE_ID,
"");
} else {
deviceId = (new StringBuilder("EMU")).append(
(new Random(System.currentTimeMillis())).nextLong())
.toString();
editor.putString(PushServiceUtil.EMULATOR_DEVICE_ID, deviceId);
editor.commit();
}
}
Log.e(TAG, PRE + "deviceId=" + deviceId);
}
private void login() {
Log.d(TAG, PRE + "start()...");
taskSubmitter.submit(new Runnable() {
public void run() {
IMService.this.getXmppManager().connect();
}
});
}
private void logout() {
// TODO when openfire crash, here cann't logout when time out
disconnect();
try {
executorService.awaitTermination(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//executorService.shutdown();
}
private void registerPush(Intent intent){
Bundle bundle = intent.getExtras();
String developer = bundle.getString(PushServiceUtil.PUSH_DEVELOPER);
String pushNameKey = bundle.getString(PushServiceUtil.PUSH_NAME_KEY);
String categoryName = bundle.getString(PushServiceUtil.PUSH_CATEGORY);
String regType = bundle.getString(PushServiceUtil.PUSH_TYPE);
// IM service has not connected
if(xmppManager.isAuthenticated() == false){
sendRegisterBroadcast(categoryName,null,
PushServiceUtil.PUSH_STATUS_UNCONNECT,
PushServiceUtil.PUSH_TYPE_REG,this);
return;
}
PushInfoManager pushInfo = new PushInfoManager(this);
if(regType.equals(PushServiceUtil.PUSH_TYPE_REG)){
if(pushInfo.isRegPush(pushNameKey,xmppManager.getUserNameWithHostName())){
sendRegisterBroadcast(categoryName,null,
PushServiceUtil.PUSH_STATUS_HAVEREGISTER,
PushServiceUtil.PUSH_TYPE_REG,this);
Log.i(TAG, PRE + TAG + "�Ѿ�ע��" + pushNameKey + " " + xmppManager.getUserNameWithHostName());
pushInfo.close();
return;
}
}else{
if(!pushInfo.isRegPush(pushNameKey,xmppManager.getUserNameWithHostName())){
sendRegisterBroadcast(categoryName,null,
PushServiceUtil.PUSH_STATUS_NOTREGISTER,
PushServiceUtil.PUSH_TYPE_UNREG,this);
Log.i(TAG, PRE + TAG + "�Ѿ���ע " + pushNameKey + " " + xmppManager.getUserNameWithHostName());
pushInfo.close();
return;
}
}
// write information to database
pushInfo.insertPushInfotoDb(xmppManager.getUserNameWithHostName(),
developer, pushNameKey, "", categoryName);
pushInfo.close();
// send packet
RegPushIQ regPushIQ = new RegPushIQ();
regPushIQ.setUserName(developer);
regPushIQ.setPushServiceName(pushNameKey);
if(regType.equals(PushServiceUtil.PUSH_TYPE_REG)){
regPushIQ.setRegOrUnreg(true);
}else if(regType.equals(PushServiceUtil.PUSH_TYPE_UNREG)){
regPushIQ.setRegOrUnreg(false);
}
xmppManager.sendPacket(regPushIQ);
// �ȴ���ʱ��
Thread thread = new Thread(new WaitThread(pushNameKey,
categoryName,regType,this));
thread.start();
}
public static void sendRegisterBroadcast(String categoryName,
String pushID,
String status,
String type,
Context context){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("sendRegisterBroadcast to packageName:")
.append("categoryName:").append(categoryName)
.append("pushID:").append(pushID).append("status:").append(status);
Log.d(TAG, PRE + TAG + stringBuilder);
Intent intentSend = new Intent(PushServiceUtil.ACTION_REGISTRATION);
//intentSend.setClassName(packageName, className);
intentSend.addCategory(categoryName);
intentSend.putExtra(PushServiceUtil.PUSH_STATUS, status);
intentSend.putExtra(PushServiceUtil.PUSH_ID, pushID);
intentSend.putExtra(PushServiceUtil.PUSH_TYPE, type);
context.sendBroadcast(intentSend);
}
private class WaitThread extends Thread {
String pushName = null;
String categoryName = null;
String className = null;
String type = null;
Context context = null;
private WaitThread(String pushName,
String categoryName,
String type,
Context context) {
this.pushName = pushName;
this.categoryName = categoryName;
this.type = type;
this.context = context;
}
public void run() {
Log.i(TAG, PRE + TAG + "WaitThread.run()...");
try {
sleep(PushServiceUtil.PUSH_TIMEOUT_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
PushInfoManager pushInfo = new PushInfoManager(IMService.this);
if(type.equals(PushServiceUtil.PUSH_TYPE_REG)){
if(pushInfo.isRegPush(pushName,xmppManager.getUserNameWithHostName()) == false){
Log.e(TAG, PRE + TAG + "register time out");
sendRegisterBroadcast(categoryName,null,
PushServiceUtil.PUSH_STATUS_FAIL,type,context);
}
}else if(type.equals(PushServiceUtil.PUSH_TYPE_UNREG)){
if(pushInfo.isRegPush(pushName,xmppManager.getUserNameWithHostName()) == true){
Log.e(TAG, PRE + TAG + "unregister time out");
sendRegisterBroadcast(categoryName,null,
PushServiceUtil.PUSH_STATUS_FAIL,type,context);
}
}
pushInfo.close();
}
}
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case PushServiceUtil.MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case PushServiceUtil.MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case PushServiceUtil.MSG_REQUEST_VCARD:
loadVCard((String)msg.obj);
break;
case PushServiceUtil.MSG_DOWNLOAD:
if(mDownloadTaskMap == null){
mDownloadTaskMap= new HashMap<Integer,DownloadAsyncTask>();
}
DownloadInf dl = (DownloadInf)msg.obj;
DownloadAsyncTask task = new DownloadAsyncTask();
mDownloadTaskMap.put(dl.id, task);
task.execute(dl);
break;
case PushServiceUtil.MSG_DOWNLOAD_STOP:
if(mDownloadTaskMap == null){
return;
}
DownloadInf dlInf = (DownloadInf)msg.obj;
DownloadAsyncTask t = mDownloadTaskMap.get(dlInf.id);
if(t != null){
if(t.cancel(true)){
IMService.this.notifyClients(
PushServiceUtil.MSG_DOWNLOAD_STOP,0,0,msg.obj);
}else{
showToast(R.string.pushcontent_stopFail,Toast.LENGTH_LONG);
}
}
break;
default:
super.handleMessage(msg);
}
Log.e(TAG, PRE+"Messager client num:"+ mClients.size());
}
}
private void showToast(int text,int duration){
Toast t = BigToast.makeText(this,
getResources().getString(text),
duration);
t.setGravity(Gravity.RIGHT|Gravity.BOTTOM, 0, 0);
t.setMargin(PushServiceUtil.HORIZONTAL_MARGIN, PushServiceUtil.VERTICAL_MARGIN);
t.show();
}
private void sendMessageChat(Intent intent){
if(xmppManager.isAuthenticated() == false){
return;
}
Bundle bundle = intent.getExtras();
String to = bundle.getString(PushServiceUtil.MESSAGE_TOWHOS);
String mesContent = bundle.getString(PushServiceUtil.MESSAGE_CONTENT);
xmppManager.sendChatMessage(to, mesContent);
}
private void sendTopic(Intent intent){
if(xmppManager.isAuthenticated() == false){
return;
}
String topic = intent.getStringExtra(PushServiceUtil.MESSAGE_TOWHOS);
String message = intent.getStringExtra(PushServiceUtil.MESSAGE_CONTENT);
xmppManager.sendTopic(topic, message);
}
private void getStatus(){
if(xmppManager.isAuthenticated()){
xmppManager.broadcastStatus(PushServiceUtil.PUSH_STATUS_LOGIN_SUC);
}else{
//connect();
xmppManager.broadcastStatus(PushServiceUtil.PUSH_STATUS_LOGIN_FAIL);
}
}
private void loadVCard(final String jid){
if(xmppManager.isAuthenticated() == false){
return;
}
taskSubmitter.submit(new Runnable() {
public void run() {
Log.e(TAG, PRE + "BEGIN LOAD CARD");
try {
xmppManager.getVCard(jid);
} catch (Exception e) {
e.printStackTrace();
return;
}
notifyClients(PushServiceUtil.MSG_REQUEST_VCARD,0, 0, jid);
Log.e(TAG, PRE + "END LOAD CARD");
}
});
}
protected void alertbox(String title, String mymessage)
{
mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams wmParams =new WindowManager.LayoutParams();
wmParams.type=WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
wmParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
wmParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
wmParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
wmParams.width=100;
wmParams.height=100;
wmParams.alpha=0.5f;
wmParams.dimAmount = 0.5f;
//wmParams.gravity = Gravity.NO_GRAVITY;
wmParams.gravity = Gravity.TOP|Gravity.LEFT;
wmParams.x = 0;
wmParams.y = 0;
Button b = new Button(getApplicationContext());
b.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
}
});;
b.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View arg0, MotionEvent me) {
int action = me.getAction();
Log.d(TAG, PRE + "action = " + action);
switch(action){
case MotionEvent.ACTION_OUTSIDE:
break;
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
});
b.setText("hello");
mWindowManager.addView(b, wmParams);
}
private void initPopupWindow(){
// ��ȡ��Ļ���
DisplayMetrics outMetrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(outMetrics);
int width = outMetrics.widthPixels;
//mlp = new WindowManager.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
mWmlp.alpha = 0.5f;
mWmlp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // ������ռ�۽���
mWmlp.flags = mWmlp.flags | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
mWmlp.flags = mWmlp.flags | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; // �Ű治������
mWmlp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // ϵͳ��ʾ����
mWmlp.width = width;
mWmlp.height = 30;
mWmlp.gravity = 2;
mWmlp.format = -1;
mWmlp.token = null;
mWmlp.x = 0;
mWmlp.y = 200;
mCurrentY = mWmlp.y;
}
public class DownloadAsyncTask extends AsyncTask<DownloadInf,DownloadInf,DownloadInf>{
@Override
protected DownloadInf doInBackground(DownloadInf... params) {
int nBufSize = 1024;
DownloadInf dInf = params[0];
dInf.status = PushServiceUtil.DOWNLOAD_ONGOING;
FileOutputStream fos = null;
try {
URL url = new URL(dInf.url);
File file = new File(dInf.desPath);
fos = new FileOutputStream(file);
long startTime = System.currentTimeMillis();
URLConnection ucon = url.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
dInf.nTotalSize = ucon.getContentLength();
if(dInf.nTotalSize == -1){
Log.e(TAG, PRE + "can't get file lenght:"+dInf.url);
dInf.nTotalSize = 102400;
}
byte[] data = new byte[nBufSize];
int nFinishSize = 0;
int nread = 0;
while( (nread = bis.read(data, 0, nBufSize)) != -1 &&
isCancelled() == false){
fos.write(data, 0, nread);
nFinishSize += nread;
Thread.sleep( 1 ); // this make cancel method work
dInf.nFinishSize = nFinishSize;
publishProgress(dInf);
}
data = null;
Log.d(TAG, PRE+"download ready in"
+ ((System.currentTimeMillis() - startTime) / 1000)
+ " sec");
dInf.status = PushServiceUtil.DOWNLOAD_SUCCESS;
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
dInf.status = PushServiceUtil.DOWNLOAD_FAIL;
} catch(InterruptedException e){
}catch (Exception e){
e.printStackTrace();
dInf.status = PushServiceUtil.DOWNLOAD_FAIL;
} finally{
try {
if(fos != null)
fos.close();
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
e.printStackTrace();
}
}
return dInf;
}
@Override
protected void onPostExecute(DownloadInf result) {
mDownloadTaskMap.remove(result.id);
if(PushServiceUtil.DOWNLOAD_STOP != result.status){
notifyClients(PushServiceUtil.MSG_DOWNLOAD,0,0,result);
}else{
notifyClients(PushServiceUtil.MSG_DOWNLOAD_STOP,0,0,result);
}
super.onPostExecute(result);
}
@Override
protected void onProgressUpdate(DownloadInf... values) {
Log.e(TAG, PRE+"onProgressUpdate Messager client num:"+ mClients.size());
DownloadInf result = values[0];
if(PushServiceUtil.DOWNLOAD_STOP != result.status){
notifyClients(PushServiceUtil.MSG_DOWNLOAD,0,0,result);
}else{
notifyClients(PushServiceUtil.MSG_DOWNLOAD_STOP,0,0,result);
}
super.onProgressUpdate(values);
}
}
private void notifyClients(int what, int arg1, int arg2, Object obj){
for (int j=mClients.size()-1; j>=0; j--) {
try {
mClients.get(j).send(Message.obtain(null,
what, arg1, arg2, obj));
} catch (RemoteException e) {
mClients.remove(j);
}
}
}
public void notifyRosterUpdated(String jid){
notifyClients(PushServiceUtil.MSG_ROSTER_UPDATED, 0, 1,jid);
}
public void setOneUnreadMessage(String jid){
notifyClients(PushServiceUtil.MSG_NEW_MESSAGE,0, 0, jid);
}
public void setNewPushContent(){
notifyClients(PushServiceUtil.MSG_NEW_PUSH_CONTENT,0, 0, null);
}
}