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