• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007-2008 Esmertec AG.
3  * Copyright (C) 2007-2008 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.im.app;
19 
20 import android.app.Activity;
21 import android.app.Application;
22 import android.content.ComponentName;
23 import android.content.ContentResolver;
24 import android.content.ContentUris;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.ServiceConnection;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ResolveInfo;
31 import android.content.pm.ServiceInfo;
32 import android.content.res.Resources;
33 import android.database.Cursor;
34 import android.net.ConnectivityManager;
35 import android.net.Uri;
36 import android.os.Broadcaster;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.IBinder;
40 import android.os.Message;
41 import android.os.RemoteException;
42 import android.provider.Im;
43 import android.text.TextUtils;
44 import android.util.Log;
45 
46 import com.android.im.IConnectionCreationListener;
47 import com.android.im.IImConnection;
48 import com.android.im.IRemoteImService;
49 import com.android.im.R;
50 import com.android.im.app.adapter.ConnectionListenerAdapter;
51 import com.android.im.engine.ImConnection;
52 import com.android.im.engine.ImErrorInfo;
53 import com.android.im.plugin.BrandingResourceIDs;
54 import com.android.im.plugin.ImPluginConstants;
55 import com.android.im.plugin.ImPluginInfo;
56 import com.android.im.service.ImServiceConstants;
57 
58 import java.util.ArrayList;
59 import java.util.HashMap;
60 import java.util.Iterator;
61 import java.util.List;
62 
63 public class ImApp extends Application {
64     public static final String LOG_TAG = "ImApp";
65 
66     public static final String EXTRA_INTENT_SEND_TO_USER = "Send2_U";
67     public static final String EXTRA_INTENT_PASSWORD = "password";
68 
69     public static final String IMPS_CATEGORY = "com.android.im.IMPS_CATEGORY";
70 
71     private static ImApp sImApp;
72 
73     IRemoteImService mImService;
74 
75     HashMap<Long, IImConnection> mConnections;
76     MyConnListener mConnectionListener;
77     HashMap<Long, ProviderDef> mProviders;
78 
79     Broadcaster mBroadcaster;
80 
81     /** A queue of messages that are waiting to be sent when service is connected.*/
82     ArrayList<Message> mQueue = new ArrayList<Message>();
83 
84     /** A flag indicates that we have called to start the service.*/
85     private boolean mServiceStarted;
86     private Context mApplicationContext;
87     private Resources mPrivateResources;
88 
89     private HashMap<String, BrandingResources> mBrandingResources;
90     private BrandingResources mDefaultBrandingResources;
91 
92     public static final int EVENT_SERVICE_CONNECTED = 100;
93     public static final int EVENT_CONNECTION_CREATED = 150;
94     public static final int EVENT_CONNECTION_LOGGING_IN = 200;
95     public static final int EVENT_CONNECTION_LOGGED_IN = 201;
96     public static final int EVENT_CONNECTION_LOGGING_OUT = 202;
97     public static final int EVENT_CONNECTION_DISCONNECTED = 203;
98     public static final int EVENT_CONNECTION_SUSPENDED = 204;
99     public static final int EVENT_USER_PRESENCE_UPDATED = 300;
100     public static final int EVENT_UPDATE_USER_PRESENCE_ERROR = 301;
101 
102     private static final String[] PROVIDER_PROJECTION = {
103         Im.Provider._ID,
104         Im.Provider.NAME,
105         Im.Provider.FULLNAME,
106         Im.Provider.SIGNUP_URL,
107     };
108 
109     private static final String[] ACCOUNT_PROJECTION = {
110         Im.Account._ID,
111         Im.Account.PROVIDER,
112         Im.Account.NAME,
113         Im.Account.USERNAME,
114         Im.Account.PASSWORD,
115     };
116 
log(String log)117     static final void log(String log) {
118         Log.d(LOG_TAG, log);
119     }
120 
getApplication(Activity activity)121     public static ImApp getApplication(Activity activity) {
122         // TODO should this be synchronized?
123         if (sImApp == null) {
124             initialize(activity);
125         }
126 
127         return sImApp;
128     }
129 
130     /**
131      * Initialize performs the manual ImApp instantiation and initialization. When the
132      * ImApp is started first in the process, the ImApp public constructor should be called,
133      * and sImApp initialized. So calling initialize() later should have no effect. However,
134      * if another application runs in the same process and is started first, the ImApp
135      * application object won't be instantiated, and we need to call initialize() manually to
136      * instantiate and initialize it.
137      */
initialize(Activity activity)138     private static void initialize(Activity activity) {
139         // construct the TalkApp manually and call onCreate().
140         sImApp = new ImApp();
141         sImApp.mApplicationContext = activity.getApplication();
142         sImApp.mPrivateResources = activity.getResources();
143         sImApp.onCreate();
144     }
145 
146     @Override
getResources()147     public Resources getResources() {
148         if (mApplicationContext == this) {
149             return super.getResources();
150         }
151 
152         return mPrivateResources;
153     }
154 
155     @Override
getContentResolver()156     public ContentResolver getContentResolver() {
157         if (mApplicationContext == this) {
158             return super.getContentResolver();
159         }
160 
161         return mApplicationContext.getContentResolver();
162     }
163 
ImApp()164     public ImApp() {
165         super();
166         mConnections = new HashMap<Long, IImConnection>();
167         mApplicationContext = this;
168         sImApp = this;
169     }
170 
171     @Override
onCreate()172     public void onCreate() {
173         super.onCreate();
174         mBroadcaster = new Broadcaster();
175         loadDefaultBrandingRes();
176         mBrandingResources = new HashMap<String, BrandingResources>();
177         loadThirdPartyResources();
178     }
179 
180     @Override
onTerminate()181     public void onTerminate() {
182         stopImServiceIfInactive();
183         if (mImService != null) {
184             try {
185                 mImService.removeConnectionCreatedListener(mConnCreationListener);
186             } catch (RemoteException e) {
187                 Log.w(LOG_TAG, "failed to remove ConnectionCreatedListener");
188             }
189         }
190 
191         super.onTerminate();
192     }
193 
startImServiceIfNeed()194     public synchronized void startImServiceIfNeed() {
195         if(!mServiceStarted) {
196             if(Log.isLoggable(LOG_TAG, Log.DEBUG)) log("start ImService");
197 
198             Intent serviceIntent = new Intent();
199             serviceIntent.setComponent(ImServiceConstants.IM_SERVICE_COMPONENT);
200             mApplicationContext.startService(serviceIntent);
201             mApplicationContext.bindService(serviceIntent, mImServiceConn, Context.BIND_AUTO_CREATE);
202             mServiceStarted = true;
203 
204             mConnectionListener = new MyConnListener(new Handler());
205         }
206     }
207 
stopImServiceIfInactive()208     public synchronized void stopImServiceIfInactive() {
209         boolean hasActiveConnection = true;
210         synchronized (mConnections) {
211             hasActiveConnection = !mConnections.isEmpty();
212         }
213 
214         if (!hasActiveConnection && mServiceStarted) {
215             if (Log.isLoggable(LOG_TAG, Log.DEBUG))
216                 log("stop ImService because there's no active connections");
217 
218             if(mImService != null) {
219                 mApplicationContext.unbindService(mImServiceConn);
220                 mImService = null;
221             }
222             Intent intent = new Intent();
223             intent.setComponent(ImServiceConstants.IM_SERVICE_COMPONENT);
224             mApplicationContext.stopService(intent);
225             mServiceStarted = false;
226         }
227     }
228 
229     private ServiceConnection mImServiceConn = new ServiceConnection() {
230         public void onServiceConnected(ComponentName className, IBinder service) {
231             if(Log.isLoggable(LOG_TAG, Log.DEBUG))
232                 log("service connected");
233 
234             mImService = IRemoteImService.Stub.asInterface(service);
235             fetchActiveConnections();
236 
237             synchronized (mQueue) {
238                 for (Message msg : mQueue) {
239                     msg.sendToTarget();
240                 }
241                 mQueue.clear();
242             }
243             Message msg = Message.obtain(null, EVENT_SERVICE_CONNECTED);
244             mBroadcaster.broadcast(msg);
245         }
246 
247         public void onServiceDisconnected(ComponentName className) {
248             if(Log.isLoggable(LOG_TAG, Log.DEBUG))
249                 log("service disconnected");
250 
251             mConnections.clear();
252             mImService = null;
253         }
254     };
255 
serviceConnected()256     public boolean serviceConnected() {
257         return mImService != null;
258     }
259 
isBackgroundDataEnabled()260     public boolean isBackgroundDataEnabled() {
261         ConnectivityManager manager =
262                 (ConnectivityManager) mApplicationContext.getSystemService(CONNECTIVITY_SERVICE);
263         return manager.getBackgroundDataSetting();
264     }
265 
insertOrUpdateAccount(ContentResolver cr, long providerId, String userName, String pw)266     public static long insertOrUpdateAccount(ContentResolver cr,
267             long providerId, String userName, String pw) {
268         String selection = Im.Account.PROVIDER + "=? AND " + Im.Account.USERNAME + "=?";
269         String[] selectionArgs = {Long.toString(providerId), userName };
270 
271         Cursor c = cr.query(Im.Account.CONTENT_URI, ACCOUNT_PROJECTION,
272                 selection, selectionArgs, null);
273         if (c != null && c.moveToFirst()) {
274             // Update the password
275             c.updateString(c.getColumnIndexOrThrow(Im.Account.PASSWORD), pw);
276             c.commitUpdates();
277 
278             long id = c.getLong(c.getColumnIndexOrThrow(Im.Account._ID));
279             c.close();
280             return id;
281         } else {
282             ContentValues values = new ContentValues(4);
283             values.put(Im.Account.PROVIDER, providerId);
284             values.put(Im.Account.NAME, userName);
285             values.put(Im.Account.USERNAME, userName);
286             values.put(Im.Account.PASSWORD, pw);
287 
288             Uri result = cr.insert(Im.Account.CONTENT_URI, values);
289             return ContentUris.parseId(result);
290         }
291     }
292 
loadImProviderSettings()293     private void loadImProviderSettings() {
294         if (mProviders != null) {
295             return;
296         }
297 
298         mProviders = new HashMap<Long, ProviderDef>();
299         ContentResolver cr = getContentResolver();
300 
301         String selectionArgs[] = new String[1];
302         selectionArgs[0] = ImApp.IMPS_CATEGORY;
303 
304         Cursor c = cr.query(Im.Provider.CONTENT_URI, PROVIDER_PROJECTION,
305                 Im.Provider.CATEGORY+"=?", selectionArgs, null);
306         if (c == null) {
307             return;
308         }
309 
310         try {
311             while (c.moveToNext()) {
312                 long id = c.getLong(0);
313                 String providerName = c.getString(1);
314                 String fullName = c.getString(2);
315                 String signUpUrl = c.getString(3);
316 
317                 mProviders.put(id, new ProviderDef(id, providerName, fullName, signUpUrl));
318             }
319         } finally {
320             c.close();
321         }
322     }
323 
loadDefaultBrandingRes()324     private void loadDefaultBrandingRes() {
325         HashMap<Integer, Integer> resMapping = new HashMap<Integer, Integer>();
326 
327         resMapping.put(BrandingResourceIDs.DRAWABLE_LOGO, R.drawable.imlogo_s);
328         resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_ONLINE,
329                 android.R.drawable.presence_online);
330         resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_AWAY,
331                 android.R.drawable.presence_away);
332         resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_BUSY,
333                 android.R.drawable.presence_busy);
334         resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_INVISIBLE,
335                 android.R.drawable.presence_invisible);
336         resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_OFFLINE,
337                 android.R.drawable.presence_offline);
338         resMapping.put(BrandingResourceIDs.DRAWABLE_READ_CHAT,
339                 R.drawable.status_chat);
340         resMapping.put(BrandingResourceIDs.DRAWABLE_UNREAD_CHAT,
341                 R.drawable.status_chat_new);
342         resMapping.put(BrandingResourceIDs.DRAWABLE_BLOCK,
343                 R.drawable.ic_im_block);
344 
345         resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_NAMES,
346                 R.array.default_smiley_names);
347         resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_TEXTS,
348                 R.array.default_smiley_texts);
349 
350         resMapping.put(BrandingResourceIDs.STRING_PRESENCE_AVAILABLE,
351                 R.string.presence_available);
352         resMapping.put(BrandingResourceIDs.STRING_PRESENCE_BUSY,
353                 R.string.presence_busy);
354         resMapping.put(BrandingResourceIDs.STRING_PRESENCE_AWAY,
355                 R.string.presence_away);
356         resMapping.put(BrandingResourceIDs.STRING_PRESENCE_IDLE,
357                 R.string.presence_idle);
358         resMapping.put(BrandingResourceIDs.STRING_PRESENCE_OFFLINE,
359                 R.string.presence_offline);
360         resMapping.put(BrandingResourceIDs.STRING_PRESENCE_INVISIBLE,
361                 R.string.presence_invisible);
362         resMapping.put(BrandingResourceIDs.STRING_LABEL_USERNAME,
363                 R.string.label_username);
364         resMapping.put(BrandingResourceIDs.STRING_ONGOING_CONVERSATION,
365                 R.string.ongoing_conversation);
366         resMapping.put(BrandingResourceIDs.STRING_ADD_CONTACT_TITLE,
367                 R.string.add_contact_title);
368         resMapping.put(BrandingResourceIDs.STRING_LABEL_INPUT_CONTACT,
369                 R.string.input_contact_label);
370         resMapping.put(BrandingResourceIDs.STRING_BUTTON_ADD_CONTACT,
371                 R.string.invite_label);
372         resMapping.put(BrandingResourceIDs.STRING_CONTACT_INFO_TITLE,
373                 R.string.contact_profile_title);
374 
375         resMapping.put(BrandingResourceIDs.STRING_MENU_ADD_CONTACT,
376                 R.string.menu_add_contact);
377         resMapping.put(BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT,
378                 R.string.menu_block_contact);
379         resMapping.put(BrandingResourceIDs.STRING_MENU_CONTACT_LIST,
380                 R.string.menu_view_contact_list);
381         resMapping.put(BrandingResourceIDs.STRING_MENU_DELETE_CONTACT,
382                 R.string.menu_remove_contact);
383         resMapping.put(BrandingResourceIDs.STRING_MENU_END_CHAT,
384                 R.string.menu_end_conversation);
385         resMapping.put(BrandingResourceIDs.STRING_MENU_INSERT_SMILEY,
386                 R.string.menu_insert_smiley);
387         resMapping.put(BrandingResourceIDs.STRING_MENU_START_CHAT,
388                 R.string.menu_start_chat);
389         resMapping.put(BrandingResourceIDs.STRING_MENU_VIEW_PROFILE,
390                 R.string.menu_view_profile);
391         resMapping.put(BrandingResourceIDs.STRING_MENU_SWITCH_CHATS,
392                 R.string.menu_switch_chats);
393 
394         resMapping.put(BrandingResourceIDs.STRING_TOAST_CHECK_AUTO_SIGN_IN,
395                 R.string.check_auto_sign_in);
396         resMapping.put(BrandingResourceIDs.STRING_LABEL_SIGN_UP,
397                 R.string.sign_up);
398 
399         mDefaultBrandingResources = new BrandingResources(this, resMapping,
400                 null /* default res */);
401     }
402 
loadThirdPartyResources()403     private void loadThirdPartyResources() {
404         PackageManager pm = getPackageManager();
405         List<ResolveInfo> plugins = pm.queryIntentServices(
406                 new Intent(ImPluginConstants.PLUGIN_ACTION_NAME), PackageManager.GET_META_DATA);
407         for (ResolveInfo info : plugins) {
408             Log.d(LOG_TAG, "Found plugin " + info);
409 
410             ServiceInfo serviceInfo = info.serviceInfo;
411             if (serviceInfo == null) {
412                 Log.e(LOG_TAG, "Ignore bad IM plugin: " + info);
413                 continue;
414             }
415             String providerName = null;
416             String providerFullName = null;
417             Bundle metaData = serviceInfo.metaData;
418             if (metaData != null) {
419                 providerName = metaData.getString(
420                         ImPluginConstants.METADATA_PROVIDER_NAME);
421                 providerFullName = metaData.getString(
422                         ImPluginConstants.METADATA_PROVIDER_FULL_NAME);
423             }
424             if (TextUtils.isEmpty(providerName)
425                     || TextUtils.isEmpty(providerFullName)) {
426                 Log.e(LOG_TAG, "Ignore bad IM plugin: " + info
427                         + ". Lack of required meta data");
428                 continue;
429             }
430 
431             ImPluginInfo pluginInfo = new ImPluginInfo(providerName,
432                     serviceInfo.packageName, serviceInfo.name,
433                     serviceInfo.applicationInfo.sourceDir);
434 
435             BrandingResources res = new BrandingResources(this, pluginInfo,
436                     mDefaultBrandingResources);
437             mBrandingResources.put(providerName, res);
438         }
439     }
440 
getProviderId(String name)441     public long getProviderId(String name) {
442         loadImProviderSettings();
443         for (ProviderDef provider: mProviders.values()) {
444             if(provider.mName.equals(name)) {
445                 return provider.mId;
446             }
447         }
448         return -1;
449     }
450 
getProvider(long id)451     public ProviderDef getProvider(long id) {
452         loadImProviderSettings();
453         return mProviders.get(id);
454     }
455 
getProviders()456     public List<ProviderDef> getProviders() {
457         loadImProviderSettings();
458         ArrayList<ProviderDef> result = new ArrayList<ProviderDef>();
459         result.addAll(mProviders.values());
460         return result;
461     }
462 
getBrandingResource(long providerId)463     public BrandingResources getBrandingResource(long providerId) {
464         ProviderDef provider = getProvider(providerId);
465         if (provider == null) {
466             return mDefaultBrandingResources;
467         }
468         BrandingResources res = mBrandingResources.get(provider.mName);
469         return res == null ? mDefaultBrandingResources : res;
470     }
471 
createConnection(long providerId)472     public IImConnection createConnection(long providerId) throws RemoteException {
473         if (mImService == null) {
474             // Service hasn't been connected or has died.
475             return null;
476         }
477         IImConnection conn = getConnection(providerId);
478         if (conn == null) {
479             conn = mImService.createConnection(providerId);
480         }
481         return conn;
482     }
483 
getConnection(long providerId)484     IImConnection getConnection(long providerId) {
485         synchronized (mConnections) {
486             return mConnections.get(providerId);
487         }
488     }
489 
getConnectionByAccount(long accountId)490     public IImConnection getConnectionByAccount(long accountId) {
491         synchronized (mConnections) {
492             for (IImConnection conn : mConnections.values()) {
493                 try {
494                     if (conn.getAccountId() == accountId) {
495                         return conn;
496                     }
497                 } catch (RemoteException e) {
498                     // No server!
499                 }
500             }
501             return null;
502         }
503     }
504 
getActiveConnections()505     public List<IImConnection> getActiveConnections() {
506         synchronized (mConnections) {
507             ArrayList<IImConnection> result = new ArrayList<IImConnection>();
508             result.addAll(mConnections.values());
509             return result;
510         }
511     }
512 
callWhenServiceConnected(Handler target, Runnable callback)513     public void callWhenServiceConnected(Handler target, Runnable callback) {
514         Message msg = Message.obtain(target, callback);
515         if (serviceConnected()) {
516             msg.sendToTarget();
517         } else {
518             startImServiceIfNeed();
519             synchronized (mQueue) {
520                 mQueue.add(msg);
521             }
522         }
523     }
524 
removePendingCall(Handler target)525     public void removePendingCall(Handler target) {
526         synchronized (mQueue) {
527            Iterator<Message> iter = mQueue.iterator();
528            while (iter.hasNext()) {
529                Message msg = iter.next();
530                if (msg.getTarget() == target) {
531                    iter.remove();
532                }
533            }
534        }
535    }
536 
registerForBroadcastEvent(int what, Handler target)537     public void registerForBroadcastEvent(int what, Handler target) {
538         mBroadcaster.request(what, target, what);
539     }
540 
unregisterForBroadcastEvent(int what, Handler target)541     public void unregisterForBroadcastEvent(int what, Handler target) {
542         mBroadcaster.cancelRequest(what, target, what);
543     }
544 
registerForConnEvents(Handler handler)545     public void registerForConnEvents(Handler handler) {
546         mBroadcaster.request(EVENT_CONNECTION_CREATED, handler,
547                 EVENT_CONNECTION_CREATED);
548         mBroadcaster.request(EVENT_CONNECTION_LOGGING_IN, handler,
549                 EVENT_CONNECTION_LOGGING_IN);
550         mBroadcaster.request(EVENT_CONNECTION_LOGGED_IN, handler,
551                 EVENT_CONNECTION_LOGGED_IN);
552         mBroadcaster.request(EVENT_CONNECTION_LOGGING_OUT, handler,
553                 EVENT_CONNECTION_LOGGING_OUT);
554         mBroadcaster.request(EVENT_CONNECTION_SUSPENDED, handler,
555                 EVENT_CONNECTION_SUSPENDED);
556         mBroadcaster.request(EVENT_CONNECTION_DISCONNECTED, handler,
557                 EVENT_CONNECTION_DISCONNECTED);
558         mBroadcaster.request(EVENT_USER_PRESENCE_UPDATED, handler,
559                 EVENT_USER_PRESENCE_UPDATED);
560         mBroadcaster.request(EVENT_UPDATE_USER_PRESENCE_ERROR, handler,
561                 EVENT_UPDATE_USER_PRESENCE_ERROR);
562     }
563 
unregisterForConnEvents(Handler handler)564     public void unregisterForConnEvents(Handler handler) {
565         mBroadcaster.cancelRequest(EVENT_CONNECTION_CREATED, handler,
566                 EVENT_CONNECTION_CREATED);
567         mBroadcaster.cancelRequest(EVENT_CONNECTION_LOGGING_IN, handler,
568                 EVENT_CONNECTION_LOGGING_IN);
569         mBroadcaster.cancelRequest(EVENT_CONNECTION_LOGGED_IN, handler,
570                 EVENT_CONNECTION_LOGGED_IN);
571         mBroadcaster.cancelRequest(EVENT_CONNECTION_LOGGING_OUT, handler,
572                 EVENT_CONNECTION_LOGGING_OUT);
573         mBroadcaster.cancelRequest(EVENT_CONNECTION_SUSPENDED, handler,
574                 EVENT_CONNECTION_SUSPENDED);
575         mBroadcaster.cancelRequest(EVENT_CONNECTION_DISCONNECTED, handler,
576                 EVENT_CONNECTION_DISCONNECTED);
577         mBroadcaster.cancelRequest(EVENT_USER_PRESENCE_UPDATED, handler,
578                 EVENT_USER_PRESENCE_UPDATED);
579         mBroadcaster.cancelRequest(EVENT_UPDATE_USER_PRESENCE_ERROR, handler,
580                 EVENT_UPDATE_USER_PRESENCE_ERROR);
581     }
582 
broadcastConnEvent(int what, long providerId, ImErrorInfo error)583     void broadcastConnEvent(int what, long providerId, ImErrorInfo error) {
584         if(Log.isLoggable(LOG_TAG, Log.DEBUG)){
585             log("broadcasting connection event " + what + ", provider id " + providerId);
586         }
587         android.os.Message msg = android.os.Message.obtain(
588                 null,
589                 what,
590                 (int)(providerId >> 32), (int)providerId,
591                 error);
592         mBroadcaster.broadcast(msg);
593     }
594 
dismissNotifications(long providerId)595     public void dismissNotifications(long providerId) {
596         if (mImService != null) {
597             try {
598                 mImService.dismissNotifications(providerId);
599             } catch (RemoteException e) {
600             }
601         }
602     }
603 
dismissChatNotification(long providerId, String username)604     public void dismissChatNotification(long providerId, String username) {
605         if (mImService != null) {
606             try {
607                 mImService.dismissChatNotification(providerId, username);
608             } catch (RemoteException e) {
609             }
610         }
611     }
612 
fetchActiveConnections()613     private void fetchActiveConnections() {
614           try {
615             // register the listener before fetch so that we won't miss any connection.
616             mImService.addConnectionCreatedListener(mConnCreationListener);
617             synchronized (mConnections) {
618                 for(IBinder binder: (List<IBinder>) mImService.getActiveConnections()) {
619                     IImConnection conn = IImConnection.Stub.asInterface(binder);
620                     long providerId = conn.getProviderId();
621                     if (!mConnections.containsKey(providerId)) {
622                         mConnections.put(providerId, conn);
623                         conn.registerConnectionListener(mConnectionListener);
624                     }
625                 }
626             }
627         } catch (RemoteException e) {
628             Log.e(LOG_TAG, "fetching active connections", e);
629         }
630     }
631 
632     private final IConnectionCreationListener mConnCreationListener
633             = new IConnectionCreationListener.Stub() {
634         public void onConnectionCreated(IImConnection conn)
635                 throws RemoteException {
636             long providerId = conn.getProviderId();
637             synchronized (mConnections) {
638                 if (!mConnections.containsKey(providerId)) {
639                     mConnections.put(providerId, conn);
640                     conn.registerConnectionListener(mConnectionListener);
641                 }
642             }
643             broadcastConnEvent(EVENT_CONNECTION_CREATED, providerId, null);
644         }
645       };
646 
647     private final class MyConnListener extends ConnectionListenerAdapter {
MyConnListener(Handler handler)648         public MyConnListener(Handler handler) {
649             super(handler);
650         }
651 
652         @Override
onConnectionStateChange(IImConnection conn, int state, ImErrorInfo error)653         public void onConnectionStateChange(IImConnection conn, int state,
654                 ImErrorInfo error) {
655             if(Log.isLoggable(LOG_TAG, Log.DEBUG)){
656                 log("onConnectionStateChange(" + state + ", " + error + ")");
657             }
658 
659             try {
660                 int what = -1;
661                 long providerId = conn.getProviderId();
662                 switch (state) {
663                 case ImConnection.LOGGED_IN:
664                     what = EVENT_CONNECTION_LOGGED_IN;
665                     break;
666 
667                 case ImConnection.LOGGING_IN:
668                     what = EVENT_CONNECTION_LOGGING_IN;
669                     break;
670 
671                 case ImConnection.LOGGING_OUT:
672                     what = EVENT_CONNECTION_LOGGING_OUT;
673                     break;
674 
675                 case ImConnection.DISCONNECTED:
676                     what = EVENT_CONNECTION_DISCONNECTED;
677                     synchronized (mConnections) {
678                         mConnections.remove(providerId);
679                     }
680                     // stop the service if there isn't an active connection anymore.
681                     stopImServiceIfInactive();
682                     break;
683 
684                 case ImConnection.SUSPENDED:
685                     what = EVENT_CONNECTION_SUSPENDED;
686                     break;
687                 }
688                 if (what != -1) {
689                     broadcastConnEvent(what, providerId, error);
690                 }
691             } catch (RemoteException e) {
692                 Log.e(LOG_TAG, "onConnectionStateChange", e);
693             }
694         }
695 
696         @Override
onUpdateSelfPresenceError(IImConnection connection, ImErrorInfo error)697         public void onUpdateSelfPresenceError(IImConnection connection,
698                 ImErrorInfo error) {
699             if(Log.isLoggable(LOG_TAG, Log.DEBUG)){
700                 log("onUpdateUserPresenceError(" + error + ")");
701             }
702             try {
703                 long providerId = connection.getProviderId();
704                 broadcastConnEvent(EVENT_UPDATE_USER_PRESENCE_ERROR, providerId,
705                         error);
706             } catch (RemoteException e) {
707                 Log.e(LOG_TAG, "onUpdateUserPresenceError", e);
708             }
709         }
710 
711         @Override
onSelfPresenceUpdated(IImConnection connection)712         public void onSelfPresenceUpdated(IImConnection connection) {
713             if(Log.isLoggable(LOG_TAG, Log.DEBUG)) log("onUserPresenceUpdated");
714 
715             try {
716                 long providerId = connection.getProviderId();
717                 broadcastConnEvent(EVENT_USER_PRESENCE_UPDATED, providerId,
718                         null);
719             } catch (RemoteException e) {
720                 Log.e(LOG_TAG, "onUserPresenceUpdated", e);
721             }
722         }
723     }
724 }
725