/* * Copyright (C) 2007-2008 Esmertec AG. Copyright (C) 2007-2008 The Android Open * Source Project * * 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 info.guardianproject.otr.app.im.app; import info.guardianproject.otr.app.Broadcaster; import info.guardianproject.otr.app.im.IChatSession; import info.guardianproject.otr.app.im.IChatSessionManager; import info.guardianproject.otr.app.im.IConnectionCreationListener; import info.guardianproject.otr.app.im.IImConnection; import info.guardianproject.otr.app.im.IRemoteImService; import info.guardianproject.otr.app.im.R; import info.guardianproject.otr.app.im.app.adapter.ConnectionListenerAdapter; import info.guardianproject.otr.app.im.engine.ImConnection; import info.guardianproject.otr.app.im.engine.ImErrorInfo; import info.guardianproject.otr.app.im.plugin.BrandingResourceIDs; import info.guardianproject.otr.app.im.plugin.ImPlugin; import info.guardianproject.otr.app.im.plugin.ImPluginInfo; import info.guardianproject.otr.app.im.provider.Imps; import info.guardianproject.otr.app.im.service.ImServiceConstants; import info.guardianproject.util.AssetUtil; import info.guardianproject.util.Debug; import info.guardianproject.util.PRNGFixes; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import ru.dtlbox.custom.CustomOrbotHelper; import android.app.Activity; import android.app.Application; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.preference.PreferenceManager; import android.util.Log; public class ImApp extends Application { public static final String LOG_TAG = "GB.ImApp"; public static final String EXTRA_INTENT_SEND_TO_USER = "Send2_U"; public static final String EXTRA_INTENT_PASSWORD = "password"; public static final String EXTRA_INTENT_PROXY_TYPE = "proxy.type"; public static final String EXTRA_INTENT_PROXY_HOST = "proxy.host"; public static final String EXTRA_INTENT_PROXY_PORT = "proxy.port"; public static final String IMPS_CATEGORY = "info.guardianproject.otr.app.im.IMPS_CATEGORY"; public static final String ACTION_QUIT = "info.guardianproject.otr.app.im.QUIT"; public static final int DEFAULT_AVATAR_WIDTH = 120; public static final int DEFAULT_AVATAR_HEIGHT = 120; public static final String HOCKEY_APP_ID = "2fa3b9252319e47367f1f125bb3adcd1"; public static final String DEFAULT_TIMEOUT_CACHEWORD = "-1"; //one day public static final String CACHEWORD_PASSWORD_KEY = "pkey"; public static final String CLEAR_PASSWORD_KEY = "clear_key"; public static final String NO_CREATE_KEY = "nocreate"; //ACCOUNT SETTINGS Imps defaults public static final String DEFAULT_XMPP_RESOURCE = "ChatSecure"; public static final int DEFAULT_XMPP_PRIORITY = 20; public static final String DEFAULT_XMPP_OTR_MODE = "auto"; private Locale locale = null; private static ImApp sImApp; IRemoteImService mImService; HashMap<Long, IImConnection> mConnections; MyConnListener mConnectionListener; HashMap<Long, ProviderDef> mProviders; Broadcaster mBroadcaster; /** * A queue of messages that are waiting to be sent when service is * connected. */ ArrayList<Message> mQueue = new ArrayList<Message>(); /** A flag indicates that we have called tomServiceStarted start the service. */ // private boolean mServiceStarted; private Context mApplicationContext; private Resources mPrivateResources; private HashMap<String, BrandingResources> mBrandingResources; private BrandingResources mDefaultBrandingResources; public static final int EVENT_SERVICE_CONNECTED = 100; public static final int EVENT_CONNECTION_CREATED = 150; public static final int EVENT_CONNECTION_LOGGING_IN = 200; public static final int EVENT_CONNECTION_LOGGED_IN = 201; public static final int EVENT_CONNECTION_LOGGING_OUT = 202; public static final int EVENT_CONNECTION_DISCONNECTED = 203; public static final int EVENT_CONNECTION_SUSPENDED = 204; public static final int EVENT_USER_PRESENCE_UPDATED = 300; public static final int EVENT_UPDATE_USER_PRESENCE_ERROR = 301; private static final String[] PROVIDER_PROJECTION = { Imps.Provider._ID, Imps.Provider.NAME, Imps.Provider.FULLNAME, Imps.Provider.SIGNUP_URL, }; private static final String[] ACCOUNT_PROJECTION = { Imps.Account._ID, Imps.Account.PROVIDER, Imps.Account.NAME, Imps.Account.USERNAME, Imps.Account.PASSWORD, }; static final void log(String log) { Log.d(LOG_TAG, log); } /* public static ImApp getApplication(Activity activity) { // TODO should this be synchronized? if (sImApp == null) { initialize(activity); } return sImApp; } public static ImApp getApplication() { // TODO should this be synchronized? if (sImApp == null) { new ImApp(); } return sImApp; }*/ /** * Initialize performs the manual ImApp instantiation and initialization. * When the ImApp is started first in the process, the ImApp public * constructor should be called, and sImApp initialized. So calling * initialize() later should have no effect. However, if another application * runs in the same process and is started first, the ImApp application * object won't be instantiated, and we need to call initialize() manually * to instantiate and initialize it. */ /* public void initialize(Activity activity) { // construct the TalkApp manually and call onCreate(). sImApp = new ImApp(); sImApp.mApplicationContext = activity.getApplication(); sImApp.mPrivateResources = activity.getResources(); sImApp.onCreate(); } */ @Override public Resources getResources() { if (mApplicationContext == this) { return super.getResources(); } return mPrivateResources; } @Override public ContentResolver getContentResolver() { if (mApplicationContext == this) { return super.getContentResolver(); } return mApplicationContext.getContentResolver(); } public ImApp() { super(); mConnections = new HashMap<Long, IImConnection>(); mApplicationContext = this; sImApp = this; } public ImApp(Context context) { super(); mConnections = new HashMap<Long, IImConnection>(); mApplicationContext = context; sImApp = this; } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (locale != null) { // We have to create a new configuration, because changing the passed-in Configuration // object causes an infinite relaunch loop in Android 4.2 (JB MR1) Configuration myConfig = new Configuration(newConfig); myConfig.locale = locale; Locale.setDefault(locale); getResources().updateConfiguration(myConfig, getResources().getDisplayMetrics()); } } @Override public void onCreate() { super.onCreate(); Debug.onAppStart(); CustomOrbotHelper.setContext(this); PRNGFixes.apply(); //Google's fix for SecureRandom bug: http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html mBroadcaster = new Broadcaster(); setAppTheme(null); checkLocale(); } public void setAppTheme (Activity activity) { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); boolean themeDark = settings.getBoolean("themeDark", false); if (themeDark) { setTheme(R.style.Theme_Sherlock); if (activity != null) activity.setTheme(R.style.Theme_Sherlock); } else { setTheme(R.style.Theme_Sherlock_Light); if (activity != null) activity.setTheme(R.style.Theme_Sherlock_Light); } Configuration config = getResources().getConfiguration(); getResources().updateConfiguration(config, getResources().getDisplayMetrics()); } public boolean checkLocale () { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); Configuration config = getResources().getConfiguration(); String lang = settings.getString(getString(R.string.pref_default_locale), ""); if ("".equals(lang)) { Properties props = AssetUtil.getProperties("gibberbot.properties", this); if (props != null) { String configuredLocale = props.getProperty("locale"); if (configuredLocale != null && !"CHOOSE".equals(configuredLocale)) { lang = configuredLocale; Editor editor = settings.edit(); editor.putString(getString(R.string.pref_default_locale), lang); editor.commit(); } } } boolean updatedLocale = false; if (!"".equals(lang) && !config.locale.getLanguage().equals(lang)) { locale = new Locale(lang); config.locale = locale; getResources().updateConfiguration(config, getResources().getDisplayMetrics()); updatedLocale = true; } loadDefaultBrandingRes(); return updatedLocale; } public boolean setNewLocale(Context context, String localeString) { /* Locale locale = new Locale(localeString); Configuration config = context.getResources().getConfiguration(); config.locale = locale; context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); Log.d(LOG_TAG, "locale = " + locale.getDisplayName()); */ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); Editor prefEdit = prefs.edit(); prefEdit.putString(context.getString(R.string.pref_default_locale), localeString); prefEdit.commit(); Configuration config = getResources().getConfiguration(); locale = new Locale(localeString); config.locale = locale; getResources().updateConfiguration(config, getResources().getDisplayMetrics()); return true; } @Override public void onTerminate() { stopImServiceIfInactive(); if (mImService != null) { try { mImService.removeConnectionCreatedListener(mConnCreationListener); } catch (RemoteException e) { Log.w(LOG_TAG, "failed to remove ConnectionCreatedListener"); } } super.onTerminate(); } public synchronized void startImServiceIfNeed() { startImServiceIfNeed(false); } public synchronized void startImServiceIfNeed(boolean isBoot) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) log("start ImService"); Intent serviceIntent = new Intent(); serviceIntent.setComponent(ImServiceConstants.IM_SERVICE_COMPONENT); serviceIntent.putExtra(ImServiceConstants.EXTRA_CHECK_AUTO_LOGIN, isBoot); if (mImService == null) { mApplicationContext.startService(serviceIntent); if (!isBoot) { mConnectionListener = new MyConnListener(new Handler()); } } if (mImServiceConn != null && !isBoot) mApplicationContext .bindService(serviceIntent, mImServiceConn, Context.BIND_AUTO_CREATE); } public boolean hasActiveConnections () { return !mConnections.isEmpty(); } public synchronized void stopImServiceIfInactive() { boolean hasActiveConnection = true; synchronized (mConnections) { hasActiveConnection = !mConnections.isEmpty(); } if (!hasActiveConnection) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) log("stop ImService because there's no active connections"); if (mImService != null) { mApplicationContext.unbindService(mImServiceConn); mImService = null; } Intent intent = new Intent(); intent.setComponent(ImServiceConstants.IM_SERVICE_COMPONENT); mApplicationContext.stopService(intent); } } //private boolean mKillServerOnStart = false; public synchronized void forceStopImService() { if (mImService != null) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) log("stop ImService"); mApplicationContext.unbindService(mImServiceConn); mImService = null; Intent intent = new Intent(); intent.setComponent(ImServiceConstants.IM_SERVICE_COMPONENT); mApplicationContext.stopService(intent); } } private ServiceConnection mImServiceConn = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) log("service connected"); mImService = IRemoteImService.Stub.asInterface(service); fetchActiveConnections(); synchronized (mQueue) { for (Message msg : mQueue) { msg.sendToTarget(); } mQueue.clear(); } Message msg = Message.obtain(null, EVENT_SERVICE_CONNECTED); mBroadcaster.broadcast(msg); /* if (mKillServerOnStart) { forceStopImService(); }*/ } public void onServiceDisconnected(ComponentName className) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) log("service disconnected"); //mConnections.clear(); mImService = null; } }; public boolean serviceConnected() { return mImService != null; } // public boolean isBackgroundDataEnabled() { //"background data" is a deprectaed concept public boolean isNetworkAvailableAndConnected () { ConnectivityManager manager = (ConnectivityManager) mApplicationContext .getSystemService(CONNECTIVITY_SERVICE); NetworkInfo nInfo = manager.getActiveNetworkInfo(); if (nInfo != null) { Log.d(LOG_TAG,"network state: available=" + nInfo.isAvailable() + " connected/connecting=" + nInfo.isConnectedOrConnecting()); return nInfo.isAvailable() && nInfo.isConnectedOrConnecting(); } else return false; //no network info is a bad idea } public static long insertOrUpdateAccount(ContentResolver cr, long providerId, String userName, String pw) { String selection = Imps.Account.PROVIDER + "=? AND " + Imps.Account.USERNAME + "=?"; String[] selectionArgs = { Long.toString(providerId), userName }; Cursor c = cr.query(Imps.Account.CONTENT_URI, ACCOUNT_PROJECTION, selection, selectionArgs, null); if (c != null && c.moveToFirst()) { long id = c.getLong(c.getColumnIndexOrThrow(Imps.Account._ID)); ContentValues values = new ContentValues(1); values.put(Imps.Account.PASSWORD, pw); Uri accountUri = ContentUris.withAppendedId(Imps.Account.CONTENT_URI, id); cr.update(accountUri, values, null, null); c.close(); return id; } else { ContentValues values = new ContentValues(4); values.put(Imps.Account.PROVIDER, providerId); values.put(Imps.Account.NAME, userName); values.put(Imps.Account.USERNAME, userName); values.put(Imps.Account.PASSWORD, pw); if (pw != null && pw.length() > 0) { values.put(Imps.Account.KEEP_SIGNED_IN, true); } Uri result = cr.insert(Imps.Account.CONTENT_URI, values); if (c != null) c.close(); return ContentUris.parseId(result); } } /** Used to reset the provider settings if a reload is required. */ public void resetProviderSettings() { mProviders = null; } // For testing public void setImProviderSettings(HashMap<Long, ProviderDef> providers) { mProviders = providers; } private void loadImProviderSettings() { if (mProviders != null) { return; } mProviders = new HashMap<Long, ProviderDef>(); ContentResolver cr = getContentResolver(); String selectionArgs[] = new String[1]; selectionArgs[0] = ImApp.IMPS_CATEGORY; Cursor c = cr.query(Imps.Provider.CONTENT_URI, PROVIDER_PROJECTION, Imps.Provider.CATEGORY + "=?", selectionArgs, null); if (c == null) { return; } try { while (c.moveToNext()) { long id = c.getLong(0); String providerName = c.getString(1); String fullName = c.getString(2); String signUpUrl = c.getString(3); mProviders.put(id, new ProviderDef(id, providerName, fullName, signUpUrl)); } } finally { c.close(); } } private void loadDefaultBrandingRes() { HashMap<Integer, Integer> resMapping = new HashMap<Integer, Integer>(); resMapping.put(BrandingResourceIDs.DRAWABLE_LOGO, R.drawable.ic_launcher_gibberbot); resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_ONLINE, android.R.drawable.presence_online); resMapping .put(BrandingResourceIDs.DRAWABLE_PRESENCE_AWAY, android.R.drawable.presence_away); resMapping .put(BrandingResourceIDs.DRAWABLE_PRESENCE_BUSY, android.R.drawable.presence_busy); resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_INVISIBLE, android.R.drawable.presence_invisible); resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_OFFLINE, android.R.drawable.presence_offline); resMapping.put(BrandingResourceIDs.DRAWABLE_READ_CHAT, R.drawable.status_chat); resMapping.put(BrandingResourceIDs.DRAWABLE_UNREAD_CHAT, R.drawable.status_chat_new); resMapping.put(BrandingResourceIDs.DRAWABLE_BLOCK, R.drawable.ic_im_block); resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_NAMES, R.array.default_smiley_names); resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_TEXTS, R.array.default_smiley_texts); resMapping.put(BrandingResourceIDs.STRING_PRESENCE_AVAILABLE, R.string.presence_available); resMapping.put(BrandingResourceIDs.STRING_PRESENCE_BUSY, R.string.presence_busy); resMapping.put(BrandingResourceIDs.STRING_PRESENCE_AWAY, R.string.presence_away); resMapping.put(BrandingResourceIDs.STRING_PRESENCE_IDLE, R.string.presence_idle); resMapping.put(BrandingResourceIDs.STRING_PRESENCE_OFFLINE, R.string.presence_offline); resMapping.put(BrandingResourceIDs.STRING_PRESENCE_INVISIBLE, R.string.presence_invisible); resMapping.put(BrandingResourceIDs.STRING_LABEL_USERNAME, R.string.label_username); resMapping.put(BrandingResourceIDs.STRING_ONGOING_CONVERSATION, R.string.ongoing_conversation); resMapping.put(BrandingResourceIDs.STRING_ADD_CONTACT_TITLE, R.string.add_contact_title); resMapping .put(BrandingResourceIDs.STRING_LABEL_INPUT_CONTACT, R.string.input_contact_label); resMapping.put(BrandingResourceIDs.STRING_BUTTON_ADD_CONTACT, R.string.invite_label); resMapping.put(BrandingResourceIDs.STRING_CONTACT_INFO_TITLE, R.string.contact_profile_title); resMapping.put(BrandingResourceIDs.STRING_MENU_ADD_CONTACT, R.string.menu_add_contact); resMapping.put(BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT, R.string.menu_block_contact); resMapping.put(BrandingResourceIDs.STRING_MENU_CONTACT_LIST, R.string.menu_view_contact_list); resMapping .put(BrandingResourceIDs.STRING_MENU_DELETE_CONTACT, R.string.menu_remove_contact); resMapping.put(BrandingResourceIDs.STRING_MENU_END_CHAT, R.string.menu_end_conversation); resMapping.put(BrandingResourceIDs.STRING_MENU_INSERT_SMILEY, R.string.menu_insert_smiley); resMapping.put(BrandingResourceIDs.STRING_MENU_START_CHAT, R.string.menu_start_chat); resMapping.put(BrandingResourceIDs.STRING_MENU_VIEW_PROFILE, R.string.menu_view_profile); resMapping.put(BrandingResourceIDs.STRING_MENU_SWITCH_CHATS, R.string.menu_switch_chats); resMapping.put(BrandingResourceIDs.STRING_TOAST_CHECK_SAVE_PASSWORD, R.string.check_save_password); resMapping.put(BrandingResourceIDs.STRING_TOAST_CHECK_AUTO_SIGN_IN, R.string.check_auto_sign_in); resMapping.put(BrandingResourceIDs.STRING_LABEL_SIGN_UP, R.string.sign_up); mDefaultBrandingResources = new BrandingResources(this, resMapping, null /* default res */); } private void loadThirdPartyResources() { ImPluginHelper helper = ImPluginHelper.getInstance(this); helper.loadAvailablePlugins(); ArrayList<ImPlugin> pluginList = helper.getPluginObjects(); ArrayList<ImPluginInfo> infoList = helper.getPluginsInfo(); int N = pluginList.size(); PackageManager pm = getPackageManager(); for (int i = 0; i < N; i++) { ImPlugin plugin = pluginList.get(i); ImPluginInfo pluginInfo = infoList.get(i); try { Resources packageRes = pm.getResourcesForApplication(pluginInfo.mPackageName); Map<Integer, Integer> resMap = plugin.getResourceMap(); //int[] smileyIcons = plugin.getSmileyIconIds(); BrandingResources res = new BrandingResources(packageRes, resMap, mDefaultBrandingResources); mBrandingResources.put(pluginInfo.mProviderName, res); } catch (NameNotFoundException e) { Log.e(LOG_TAG, "Failed to load third party resources.", e); } } } public long getProviderId(String name) { loadImProviderSettings(); for (ProviderDef provider : mProviders.values()) { if (provider.mName.equals(name)) { return provider.mId; } } return -1; } public ProviderDef getProvider(long id) { loadImProviderSettings(); return mProviders.get(id); } public List<ProviderDef> getProviders() { loadImProviderSettings(); ArrayList<ProviderDef> result = new ArrayList<ProviderDef>(); result.addAll(mProviders.values()); return result; } public BrandingResources getBrandingResource(long providerId) { ProviderDef provider = getProvider(providerId); if (provider == null) { return mDefaultBrandingResources; } if (mBrandingResources == null) { mBrandingResources = new HashMap<String, BrandingResources>(); loadThirdPartyResources(); } BrandingResources res = mBrandingResources.get(provider.mName); return res == null ? mDefaultBrandingResources : res; } public IImConnection createConnection(long providerId, long accountId) throws RemoteException { if (mImService == null) { // Service hasn't been connected or has died. return null; } IImConnection conn = getConnection(providerId); if (conn == null) { conn = mImService.createConnection(providerId, accountId); } return conn; } public IImConnection getConnection(long providerId) { synchronized (mConnections) { if (mConnections.size() == 0) fetchActiveConnections(); return mConnections.get(providerId); } } public IImConnection getConnectionByAccount(long accountId) { synchronized (mConnections) { for (IImConnection conn : mConnections.values()) { try { if (conn.getAccountId() == accountId) { return conn; } } catch (RemoteException e) { // No server! } } return null; } } public List<IImConnection> getActiveConnections() { synchronized (mConnections) { if (mConnections.size() == 0) fetchActiveConnections(); ArrayList<IImConnection> result = new ArrayList<IImConnection>(); result.addAll(mConnections.values()); return result; } } public void callWhenServiceConnected(Handler target, Runnable callback) { Message msg = Message.obtain(target, callback); if (serviceConnected() && msg != null) { msg.sendToTarget(); } else { startImServiceIfNeed(); synchronized (mQueue) { mQueue.add(msg); } } } public void deleteAccount (long accountId, long providerId) { ContentResolver resolver = getContentResolver(); Uri accountUri = ContentUris.withAppendedId(Imps.Account.CONTENT_URI, accountId); resolver.delete(accountUri, null, null); Uri providerUri = ContentUris.withAppendedId(Imps.Provider.CONTENT_URI, providerId); resolver.delete(providerUri, null, null); Uri.Builder builder = Imps.Contacts.CONTENT_URI_CONTACTS_BY.buildUpon(); ContentUris.appendId(builder, providerId); ContentUris.appendId(builder, accountId); resolver.delete(builder.build(), null, null); } public void removePendingCall(Handler target) { synchronized (mQueue) { Iterator<Message> iter = mQueue.iterator(); while (iter.hasNext()) { Message msg = iter.next(); if (msg.getTarget() == target) { iter.remove(); } } } } public void registerForBroadcastEvent(int what, Handler target) { mBroadcaster.request(what, target, what); } public void unregisterForBroadcastEvent(int what, Handler target) { mBroadcaster.cancelRequest(what, target, what); } public void registerForConnEvents(Handler handler) { mBroadcaster.request(EVENT_CONNECTION_CREATED, handler, EVENT_CONNECTION_CREATED); mBroadcaster.request(EVENT_CONNECTION_LOGGING_IN, handler, EVENT_CONNECTION_LOGGING_IN); mBroadcaster.request(EVENT_CONNECTION_LOGGED_IN, handler, EVENT_CONNECTION_LOGGED_IN); mBroadcaster.request(EVENT_CONNECTION_LOGGING_OUT, handler, EVENT_CONNECTION_LOGGING_OUT); mBroadcaster.request(EVENT_CONNECTION_SUSPENDED, handler, EVENT_CONNECTION_SUSPENDED); mBroadcaster.request(EVENT_CONNECTION_DISCONNECTED, handler, EVENT_CONNECTION_DISCONNECTED); mBroadcaster.request(EVENT_USER_PRESENCE_UPDATED, handler, EVENT_USER_PRESENCE_UPDATED); mBroadcaster.request(EVENT_UPDATE_USER_PRESENCE_ERROR, handler, EVENT_UPDATE_USER_PRESENCE_ERROR); } public void unregisterForConnEvents(Handler handler) { mBroadcaster.cancelRequest(EVENT_CONNECTION_CREATED, handler, EVENT_CONNECTION_CREATED); mBroadcaster.cancelRequest(EVENT_CONNECTION_LOGGING_IN, handler, EVENT_CONNECTION_LOGGING_IN); mBroadcaster.cancelRequest(EVENT_CONNECTION_LOGGED_IN, handler, EVENT_CONNECTION_LOGGED_IN); mBroadcaster.cancelRequest(EVENT_CONNECTION_LOGGING_OUT, handler, EVENT_CONNECTION_LOGGING_OUT); mBroadcaster.cancelRequest(EVENT_CONNECTION_SUSPENDED, handler, EVENT_CONNECTION_SUSPENDED); mBroadcaster.cancelRequest(EVENT_CONNECTION_DISCONNECTED, handler, EVENT_CONNECTION_DISCONNECTED); mBroadcaster.cancelRequest(EVENT_USER_PRESENCE_UPDATED, handler, EVENT_USER_PRESENCE_UPDATED); mBroadcaster.cancelRequest(EVENT_UPDATE_USER_PRESENCE_ERROR, handler, EVENT_UPDATE_USER_PRESENCE_ERROR); } void broadcastConnEvent(int what, long providerId, ImErrorInfo error) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) { log("broadcasting connection event " + what + ", provider id " + providerId); } android.os.Message msg = android.os.Message.obtain(null, what, (int) (providerId >> 32), (int) providerId, error); mBroadcaster.broadcast(msg); } public void dismissNotifications(long providerId) { if (mImService != null) { try { mImService.dismissNotifications(providerId); } catch (RemoteException e) { } } } public void dismissChatNotification(long providerId, String username) { if (mImService != null) { try { mImService.dismissChatNotification(providerId, username); } catch (RemoteException e) { } } } private void fetchActiveConnections() { if (mImService != null) { try { // register the listener before fetch so that we won't miss any connection. mImService.addConnectionCreatedListener(mConnCreationListener); synchronized (mConnections) { for (IBinder binder : (List<IBinder>) mImService.getActiveConnections()) { IImConnection conn = IImConnection.Stub.asInterface(binder); long providerId = conn.getProviderId(); if (!mConnections.containsKey(providerId)) { mConnections.put(providerId, conn); conn.registerConnectionListener(mConnectionListener); } } } } catch (RemoteException e) { Log.e(LOG_TAG, "fetching active connections", e); } } } private final IConnectionCreationListener mConnCreationListener = new IConnectionCreationListener.Stub() { public void onConnectionCreated(IImConnection conn) throws RemoteException { long providerId = conn.getProviderId(); synchronized (mConnections) { if (!mConnections.containsKey(providerId)) { mConnections.put(providerId, conn); conn.registerConnectionListener(mConnectionListener); } } broadcastConnEvent(EVENT_CONNECTION_CREATED, providerId, null); } }; private final class MyConnListener extends ConnectionListenerAdapter { public MyConnListener(Handler handler) { super(handler); } @Override public void onConnectionStateChange(IImConnection conn, int state, ImErrorInfo error) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) { log("onConnectionStateChange(" + state + ", " + error + ")"); } try { int what = -1; long providerId = conn.getProviderId(); switch (state) { case ImConnection.LOGGED_IN: what = EVENT_CONNECTION_LOGGED_IN; break; case ImConnection.LOGGING_IN: what = EVENT_CONNECTION_LOGGING_IN; break; case ImConnection.LOGGING_OUT: what = EVENT_CONNECTION_LOGGING_OUT; // MIRON - remove only if disconnected! // synchronized (mConnections) { // mConnections.remove(providerId); // } break; case ImConnection.DISCONNECTED: what = EVENT_CONNECTION_DISCONNECTED; synchronized (mConnections) { mConnections.remove(providerId); } // stop the service if there isn't an active connection anymore. // stopImServiceIfInactive(); break; case ImConnection.SUSPENDED: what = EVENT_CONNECTION_SUSPENDED; break; } if (what != -1) { broadcastConnEvent(what, providerId, error); } } catch (RemoteException e) { Log.e(LOG_TAG, "onConnectionStateChange", e); } } @Override public void onUpdateSelfPresenceError(IImConnection connection, ImErrorInfo error) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) { log("onUpdateUserPresenceError(" + error + ")"); } try { long providerId = connection.getProviderId(); broadcastConnEvent(EVENT_UPDATE_USER_PRESENCE_ERROR, providerId, error); } catch (RemoteException e) { Log.e(LOG_TAG, "onUpdateUserPresenceError", e); } } @Override public void onSelfPresenceUpdated(IImConnection connection) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) log("onUserPresenceUpdated"); try { long providerId = connection.getProviderId(); broadcastConnEvent(EVENT_USER_PRESENCE_UPDATED, providerId, null); } catch (RemoteException e) { Log.e(LOG_TAG, "onUserPresenceUpdated", e); } } } public IRemoteImService getRemoteImService() { return mImService; } public IChatSession getChatSession(long providerId, String remoteAddress) { IImConnection conn = getConnection(providerId); IChatSessionManager chatSessionManager = null; if (conn != null) { try { chatSessionManager = conn.getChatSessionManager(); } catch (RemoteException e) { Log.e(LOG_TAG, "error in getting ChatSessionManager", e); } } if (chatSessionManager != null) { try { return chatSessionManager.getChatSession(remoteAddress); } catch (RemoteException e) { Log.e(LOG_TAG, "error in getting ChatSession", e); } } return null; } public void maybeInit(Activity activity) { startImServiceIfNeed(); setAppTheme(activity); ImPluginHelper.getInstance(this).loadAvailablePlugins(); } }