/** * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.easemob.applib.controller; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.util.Log; import com.easemob.EMCallBack; import com.easemob.EMConnectionListener; import com.easemob.EMError; import com.easemob.EMValueCallBack; import com.easemob.applib.model.DefaultHXSDKModel; import com.easemob.applib.model.HXNotifier; import com.easemob.applib.model.HXNotifier.HXNotificationInfoProvider; import com.easemob.applib.model.HXSDKModel; import com.easemob.chat.EMChat; import com.easemob.chat.EMChatConfig.EMEnvMode; import com.easemob.chat.EMChatManager; import com.easemob.chat.EMChatOptions; import com.easemob.chat.EMContactManager; import com.easemob.chat.EMGroupManager; import com.easemob.exceptions.EaseMobException; /** * The developer can derive from this class to talk with HuanXin SDK * All the Huan Xin related initialization and global listener are implemented in this class which will * help developer to speed up the SDK integration。 * this is a global instance class which can be obtained in any codes through getInstance() * * 开发人员可以选择继承这个环信SDK帮助类去加快初始化集成速度。此类会初始化环信SDK,并设置初始化参数和初始化相应的监听器 * 不过继承类需要根据要求求提供相应的函数,尤其是提供一个{@link HXSDKModel}. 所以请实现abstract protected HXSDKModel createModel(); * 全局仅有一个此类的实例存在,所以可以在任意地方通过getInstance()函数获取此全局实例 * * @author easemob * */ public abstract class HXSDKHelper { /** * 群组更新完成 */ static public interface HXSyncListener { public void onSyncSucess(boolean success); } private static final String TAG = "HXSDKHelper"; /** * application context */ protected Context appContext = null; /** * HuanXin mode helper, which will manage the user data and user preferences */ protected HXSDKModel hxModel = null; /** * MyConnectionListener */ protected EMConnectionListener connectionListener = null; /** * HuanXin ID in cache */ protected String hxId = null; /** * password in cache */ protected String password = null; /** * init flag: test if the sdk has been inited before, we don't need to init again */ private boolean sdkInited = false; /** * the global HXSDKHelper instance */ private static HXSDKHelper me = null; /** * the notifier */ protected HXNotifier notifier = null; /** * HuanXin sync groups status listener */ private List<HXSyncListener> syncGroupsListeners; /** * HuanXin sync contacts status listener */ private List<HXSyncListener> syncContactsListeners; /** * HuanXin sync blacklist status listener */ private List<HXSyncListener> syncBlackListListeners; private boolean isSyncingGroupsWithServer = false; private boolean isSyncingContactsWithServer = false; private boolean isSyncingBlackListWithServer = false; private boolean isGroupsSyncedWithServer = false; private boolean isContactsSyncedWithServer = false; private boolean isBlackListSyncedWithServer = false; private boolean alreadyNotified = false; public boolean isVoiceCalling; public boolean isVideoCalling; protected HXSDKHelper(){ me = this; } /** * this function will initialize the HuanXin SDK * * @return boolean true if caller can continue to call HuanXin related APIs after calling onInit, otherwise false. * * 环信初始化SDK帮助函数 * 返回true如果正确初始化,否则false,如果返回为false,请在后续的调用中不要调用任何和环信相关的代码 * * for example: * 例子: * * public class DemoHXSDKHelper extends HXSDKHelper * * HXHelper = new DemoHXSDKHelper(); * if(HXHelper.onInit(context)){ * // do HuanXin related work * } */ public synchronized boolean onInit(Context context){ if(sdkInited){ return true; } appContext = context; // create HX SDK model hxModel = createModel(); // create a defalut HX SDK model in case subclass did not provide the model if(hxModel == null){ hxModel = new DefaultHXSDKModel(appContext); } int pid = android.os.Process.myPid(); String processAppName = getAppName(pid); Log.d(TAG, "process app name : " + processAppName); // 如果app启用了远程的service,此application:onCreate会被调用2次 // 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次 // 默认的app会在以包名为默认的process name下运行,如果查到的process name不是app的process name就立即返回 if (processAppName == null || !processAppName.equalsIgnoreCase(hxModel.getAppProcessName())) { Log.e(TAG, "enter the service process!"); // 则此application::onCreate 是被service 调用的,直接返回 return false; } // 初始化环信SDK,一定要先调用init() EMChat.getInstance().init(context); // 设置sandbox测试环境 if(hxModel.isSandboxMode()){ EMChat.getInstance().setEnv(EMEnvMode.EMSandboxMode); } if(hxModel.isDebugMode()){ // set debug mode in development process EMChat.getInstance().setDebugMode(true); } Log.d(TAG, "initialize EMChat SDK"); initHXOptions(); initListener(); syncGroupsListeners = new ArrayList<HXSyncListener>(); syncContactsListeners = new ArrayList<HXSyncListener>(); syncBlackListListeners = new ArrayList<HXSyncListener>(); isGroupsSyncedWithServer = hxModel.isGroupsSynced(); isContactsSyncedWithServer = hxModel.isContactSynced(); isBlackListSyncedWithServer = hxModel.isBacklistSynced(); sdkInited = true; return true; } /** * get global instance * @return */ public static HXSDKHelper getInstance(){ return me; } public Context getAppContext(){ return appContext; } public HXSDKModel getModel(){ return hxModel; } public String getHXId(){ if(hxId == null){ hxId = hxModel.getHXId(); } return hxId; } public String getPassword(){ if(password == null){ password = hxModel.getPwd(); } return password; } public void setHXId(String hxId){ if (hxId != null) { if(hxModel.saveHXId(hxId)){ this.hxId = hxId; } } } public void setPassword(String password){ if(hxModel.savePassword(password)){ this.password = password; } } /** * the subclass must override this class to provide its own model or directly use {@link DefaultHXSDKModel} * @return */ abstract protected HXSDKModel createModel(); /** * please make sure you have to get EMChatOptions by following method and set related options * EMChatOptions options = EMChatManager.getInstance().getChatOptions(); */ protected void initHXOptions(){ Log.d(TAG, "init HuanXin Options"); // 获取到EMChatOptions对象 EMChatOptions options = EMChatManager.getInstance().getChatOptions(); // 默认添加好友时,是不需要验证的,改成需要验证 options.setAcceptInvitationAlways(hxModel.getAcceptInvitationAlways()); // 默认环信是不维护好友关系列表的,如果app依赖环信的好友关系,把这个属性设置为true options.setUseRoster(hxModel.getUseHXRoster()); // 设置是否需要已读回执 options.setRequireAck(hxModel.getRequireReadAck()); // 设置是否需要已送达回执 options.setRequireDeliveryAck(hxModel.getRequireDeliveryAck()); // 设置从db初始化加载时, 每个conversation需要加载msg的个数 options.setNumberOfMessagesLoaded(1); notifier = createNotifier(); notifier.init(appContext); notifier.setNotificationInfoProvider(getNotificationListener()); } /** * subclass can override this api to return the customer notifier * * @return */ protected HXNotifier createNotifier(){ return new HXNotifier(); } public HXNotifier getNotifier(){ return notifier; } /** * logout HuanXin SDK */ public void logout(final EMCallBack callback){ setPassword(null); reset(); EMChatManager.getInstance().logout(new EMCallBack(){ @Override public void onSuccess() { if(callback != null){ callback.onSuccess(); } } @Override public void onError(int code, String message) { } @Override public void onProgress(int progress, String status) { if(callback != null){ callback.onProgress(progress, status); } } }); } /** * 检查是否已经登录过 * @return */ public boolean isLogined(){ return EMChat.getInstance().isLoggedIn(); } protected HXNotificationInfoProvider getNotificationListener(){ return null; } /** * init HuanXin listeners */ protected void initListener(){ Log.d(TAG, "init listener"); // create the global connection listener connectionListener = new EMConnectionListener() { @Override public void onDisconnected(int error) { if (error == EMError.USER_REMOVED) { onCurrentAccountRemoved(); }else if (error == EMError.CONNECTION_CONFLICT) { onConnectionConflict(); }else{ onConnectionDisconnected(error); } } @Override public void onConnected() { onConnectionConnected(); } }; //注册连接监听 EMChatManager.getInstance().addConnectionListener(connectionListener); } /** * the developer can override this function to handle connection conflict error */ protected void onConnectionConflict(){} /** * the developer can override this function to handle user is removed error */ protected void onCurrentAccountRemoved(){} /** * handle the connection connected */ protected void onConnectionConnected(){} /** * handle the connection disconnect * @param error see {@link EMError} */ protected void onConnectionDisconnected(int error){} /** * check the application process name if process name is not qualified, then we think it is a service process and we will not init SDK * @param pID * @return */ private String getAppName(int pID) { String processName = null; ActivityManager am = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE); List l = am.getRunningAppProcesses(); Iterator i = l.iterator(); PackageManager pm = appContext.getPackageManager(); while (i.hasNext()) { ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next()); try { if (info.pid == pID) { CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(info.processName, PackageManager.GET_META_DATA)); // Log.d("Process", "Id: "+ info.pid +" ProcessName: "+ // info.processName +" Label: "+c.toString()); // processName = c.toString(); processName = info.processName; return processName; } } catch (Exception e) { // Log.d("Process", "Error>> :"+ e.toString()); } } return processName; } public void addSyncGroupListener(HXSyncListener listener) { if (listener == null) { return; } if (!syncGroupsListeners.contains(listener)) { syncGroupsListeners.add(listener); } } public void removeSyncGroupListener(HXSyncListener listener) { if (listener == null) { return; } if (syncGroupsListeners.contains(listener)) { syncGroupsListeners.remove(listener); } } public void addSyncContactListener(HXSyncListener listener) { if (listener == null) { return; } if (!syncContactsListeners.contains(listener)) { syncContactsListeners.add(listener); } } public void removeSyncContactListener(HXSyncListener listener) { if (listener == null) { return; } if (syncContactsListeners.contains(listener)) { syncContactsListeners.remove(listener); } } public void addSyncBlackListListener(HXSyncListener listener) { if (listener == null) { return; } if (!syncBlackListListeners.contains(listener)) { syncBlackListListeners.add(listener); } } public void removeSyncBlackListListener(HXSyncListener listener) { if (listener == null) { return; } if (syncBlackListListeners.contains(listener)) { syncBlackListListeners.remove(listener); } } /** * 同步操作,从服务器获取群组列表 * 该方法会记录更新状态,可以通过isSyncingGroupsFromServer获取是否正在更新 * 和HXPreferenceUtils.getInstance().getSettingSyncGroupsFinished()获取是否更新已经完成 * @throws EaseMobException */ public synchronized void asyncFetchGroupsFromServer(final EMCallBack callback){ if(isSyncingGroupsWithServer){ return; } isSyncingGroupsWithServer = true; new Thread(){ @Override public void run(){ try { EMGroupManager.getInstance().getGroupsFromServer(); // in case that logout already before server returns, we should return immediately if(!EMChat.getInstance().isLoggedIn()){ return; } hxModel.setGroupsSynced(true); isGroupsSyncedWithServer = true; isSyncingGroupsWithServer = false; if(callback != null){ callback.onSuccess(); } } catch (EaseMobException e) { hxModel.setGroupsSynced(false); isGroupsSyncedWithServer = false; isSyncingGroupsWithServer = false; if(callback != null){ callback.onError(e.getErrorCode(), e.toString()); } } } }.start(); } public void noitifyGroupSyncListeners(boolean success){ for (HXSyncListener listener : syncGroupsListeners) { listener.onSyncSucess(success); } } public void asyncFetchContactsFromServer(final EMValueCallBack<List<String>> callback){ if(isSyncingContactsWithServer){ return; } isSyncingContactsWithServer = true; new Thread(){ @Override public void run(){ List<String> usernames = null; try { usernames = EMContactManager.getInstance().getContactUserNames(); // in case that logout already before server returns, we should return immediately if(!EMChat.getInstance().isLoggedIn()){ return; } hxModel.setContactSynced(true); isContactsSyncedWithServer = true; isSyncingContactsWithServer = false; if(callback != null){ callback.onSuccess(usernames); } } catch (EaseMobException e) { hxModel.setContactSynced(false); isContactsSyncedWithServer = false; isSyncingContactsWithServer = false; e.printStackTrace(); if(callback != null){ callback.onError(e.getErrorCode(), e.toString()); } } } }.start(); } public void notifyContactsSyncListener(boolean success){ for (HXSyncListener listener : syncContactsListeners) { listener.onSyncSucess(success); } } public void asyncFetchBlackListFromServer(final EMValueCallBack<List<String>> callback){ if(isSyncingBlackListWithServer){ return; } isSyncingBlackListWithServer = true; new Thread(){ @Override public void run(){ try { List<String> usernames = null; usernames = EMContactManager.getInstance().getBlackListUsernamesFromServer(); // in case that logout already before server returns, we should return immediately if(!EMChat.getInstance().isLoggedIn()){ return; } hxModel.setBlacklistSynced(true); isBlackListSyncedWithServer = true; isSyncingBlackListWithServer = false; if(callback != null){ callback.onSuccess(usernames); } } catch (EaseMobException e) { hxModel.setBlacklistSynced(false); isBlackListSyncedWithServer = false; isSyncingBlackListWithServer = true; e.printStackTrace(); if(callback != null){ callback.onError(e.getErrorCode(), e.toString()); } } } }.start(); } public void notifyBlackListSyncListener(boolean success){ for (HXSyncListener listener : syncBlackListListeners) { listener.onSyncSucess(success); } } public boolean isSyncingGroupsWithServer() { return isSyncingGroupsWithServer; } public boolean isSyncingContactsWithServer() { return isSyncingContactsWithServer; } public boolean isSyncingBlackListWithServer() { return isSyncingBlackListWithServer; } public boolean isGroupsSyncedWithServer() { return isGroupsSyncedWithServer; } public boolean isContactsSyncedWithServer() { return isContactsSyncedWithServer; } public boolean isBlackListSyncedWithServer() { return isBlackListSyncedWithServer; } public synchronized void notifyForRecevingEvents(){ if(alreadyNotified){ return; } // 通知sdk,UI 已经初始化完毕,注册了相应的receiver和listener, 可以接受broadcast了 EMChat.getInstance().setAppInited(); alreadyNotified = true; } synchronized void reset(){ isSyncingGroupsWithServer = false; isSyncingContactsWithServer = false; isSyncingBlackListWithServer = false; hxModel.setGroupsSynced(false); hxModel.setContactSynced(false); hxModel.setBlacklistSynced(false); isGroupsSyncedWithServer = false; isContactsSyncedWithServer = false; isBlackListSyncedWithServer = false; alreadyNotified = false; } }