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