1 /* 2 * Copyright (c) 2015, Motorola Mobility LLC 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * - Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * - Neither the name of Motorola Mobility nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 * DAMAGE. 27 */ 28 29 package com.android.service.ims.presence; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 import android.content.ServiceConnection; 35 import android.annotation.SuppressLint; 36 import android.content.Intent; 37 import android.content.Context; 38 import android.content.SharedPreferences; 39 import android.os.Handler; 40 import android.os.Looper; 41 import android.os.Message; 42 import android.os.RemoteException; 43 import android.text.TextUtils; 44 import android.util.Log; 45 import android.os.Parcel; 46 47 import com.android.ims.internal.uce.presence.IPresenceListener; 48 import com.android.ims.internal.uce.presence.PresCmdId; 49 import com.android.ims.internal.uce.presence.PresCmdStatus; 50 import com.android.ims.internal.uce.presence.PresPublishTriggerType; 51 import com.android.ims.internal.uce.presence.PresResInfo; 52 import com.android.ims.internal.uce.presence.PresRlmiInfo; 53 import com.android.ims.internal.uce.presence.PresSipResponse; 54 import com.android.ims.internal.uce.presence.PresTupleInfo; 55 import com.android.ims.internal.uce.common.StatusCode; 56 import com.android.ims.internal.uce.common.StatusCode; 57 58 import com.android.ims.RcsManager; 59 import com.android.ims.RcsManager.ResultCode; 60 import com.android.ims.RcsPresence; 61 import com.android.ims.RcsPresenceInfo; 62 import com.android.ims.IRcsPresenceListener; 63 64 import com.android.ims.internal.Logger; 65 import com.android.service.ims.TaskManager; 66 import com.android.service.ims.Task; 67 import com.android.service.ims.RcsStackAdaptor; 68 import com.android.service.ims.LauncherUtils; 69 70 public class StackListener extends Handler{ 71 /* 72 * The logger 73 */ 74 private Logger logger = Logger.getLogger(this.getClass().getName()); 75 76 Context mContext; 77 private PresencePublication mPresencePublication = null; 78 private PresenceSubscriber mPresenceSubscriber = null; 79 80 // RCS stack notify the AP to publish the presence. 81 private static final short PRESENCE_IMS_UNSOL_PUBLISH_TRIGGER = 1; 82 // PUBLISH CMD status changed 83 private static final short PRESENCE_IMS_UNSOL_PUBLISH_CMDSTATUS = 2; 84 // Received the SIP response for publish 85 private static final short PRESENCE_IMS_UNSOL_PUBLISH_SIPRESPONSE = 3; 86 // Received the presence for single contact 87 private static final short PRESENCE_IMS_UNSOL_NOTIFY_UPDATE = 4; 88 // Received the presence for contacts. 89 private static final short PRESENCE_IMS_UNSOL_NOTIFY_LIST_UPDATE = 5; 90 // Received the CMD status for capability/availability request 91 private static final short PRESENCE_IMS_UNSOL_NOTIFY_UPDATE_CMDSTATUS = 6; 92 // Received the SIP response for capability/availability request 93 private static final short PRESENCE_IMS_UNSOL_NOTIFY_UPDATE_SIPRESPONSE = 7; 94 95 private final Object mSyncObj = new Object(); 96 97 public StackListener(Context context, Looper looper) { 98 super(looper); 99 mContext = context; 100 } 101 102 public void setPresencePublication(PresencePublication presencePublication){ 103 mPresencePublication = presencePublication; 104 } 105 106 public void setPresenceSubscriber(PresenceSubscriber presenceSubscriber){ 107 mPresenceSubscriber = presenceSubscriber; 108 } 109 110 @Override 111 public void handleMessage(Message msg) { 112 super.handleMessage(msg); 113 114 logger.debug( "Thread=" + Thread.currentThread().getName() + " received " 115 + msg); 116 if(msg == null){ 117 logger.error("msg=null"); 118 return; 119 } 120 121 switch (msg.what) { 122 // RCS stack notify the AP to publish the presence. 123 case PRESENCE_IMS_UNSOL_PUBLISH_TRIGGER: 124 { 125 PresPublishTriggerType val = (PresPublishTriggerType) msg.obj; 126 if(mPresencePublication == null || val == null){ 127 logger.error("mPresencePublication=" + mPresencePublication + " val=" + val); 128 return; 129 } 130 131 mPresencePublication.invokePublish(val); 132 break; 133 } 134 135 // RCS stack tell AP that the CMD status changed. 136 case PRESENCE_IMS_UNSOL_PUBLISH_CMDSTATUS: 137 { 138 PresCmdStatus pCmdStatus = (PresCmdStatus) msg.obj; 139 if(mPresencePublication == null || pCmdStatus == null){ 140 logger.error("mPresencePublication=" + mPresencePublication + 141 " pCmdStatus=" + pCmdStatus); 142 return; 143 } 144 145 mPresencePublication.handleCmdStatus(pCmdStatus); 146 } 147 break; 148 149 // RCS stack tells AP that the CMD status changed. 150 case PRESENCE_IMS_UNSOL_NOTIFY_UPDATE_CMDSTATUS: 151 { 152 PresCmdStatus pCmdStatus = (PresCmdStatus) msg.obj; 153 if(mPresenceSubscriber == null || pCmdStatus == null){ 154 logger.error("mPresenceSubcriber=" + mPresenceSubscriber + 155 " pCmdStatus=" + pCmdStatus); 156 return; 157 } 158 159 mPresenceSubscriber.handleCmdStatus(pCmdStatus); 160 break; 161 } 162 163 // RCS stack tells AP that the SIP response has been received. 164 case PRESENCE_IMS_UNSOL_PUBLISH_SIPRESPONSE: 165 { 166 PresSipResponse pSipResponse = (PresSipResponse) msg.obj; 167 if(mPresencePublication == null || pSipResponse == null){ 168 logger.error("mPresencePublication=" + mPresencePublication + 169 "pSipResponse=" +pSipResponse); 170 return; 171 } 172 173 mPresencePublication.handleSipResponse(pSipResponse); 174 break; 175 } 176 177 // RCS stack tells AP that the SIP response has been received. 178 case PRESENCE_IMS_UNSOL_NOTIFY_UPDATE_SIPRESPONSE: 179 { 180 PresSipResponse pSipResponse = (PresSipResponse) msg.obj; 181 if(mPresenceSubscriber == null || pSipResponse == null){ 182 logger.error("mPresenceSubscriber=" + mPresenceSubscriber + 183 " pSipResponse=" + pSipResponse); 184 return; 185 } 186 187 mPresenceSubscriber.handleSipResponse(pSipResponse); 188 break; 189 } 190 191 // RCS stack tells AP that the presence data has been received. 192 case PRESENCE_IMS_UNSOL_NOTIFY_UPDATE: 193 { 194 NotifyData notifyData = (NotifyData) msg.obj; 195 if(mPresenceSubscriber == null || notifyData == null){ 196 logger.error("mPresenceSubscriber=" + mPresenceSubscriber + 197 " notifyData=" + notifyData); 198 return; 199 } 200 201 mPresenceSubscriber.updatePresence(notifyData.getUri(), 202 notifyData.getTupleInfo()); 203 break; 204 } 205 206 case PRESENCE_IMS_UNSOL_NOTIFY_LIST_UPDATE: 207 { 208 NotifyListData notifyListData = (NotifyListData) msg.obj; 209 logger.debug("Received PRESENCE_IMS_UNSOL_NOTIFY_LIST_UPDATE"); 210 if(mPresenceSubscriber==null || notifyListData == null){ 211 logger.error("mPresenceSubscriber=" + mPresenceSubscriber + 212 " notifyListData=" + notifyListData); 213 return; 214 } 215 216 mPresenceSubscriber.updatePresences(notifyListData.getRlmiInfo(), 217 notifyListData.getResInfo()); 218 break; 219 } 220 221 default: 222 logger.debug("Unknown mesg " + msg.what + " recieved."); 223 } 224 } 225 226 public class NotifyData{ 227 private String mUri; 228 private PresTupleInfo[] mTupleInfo; 229 230 NotifyData(){ 231 mUri = null; 232 mTupleInfo = null; 233 } 234 235 NotifyData(String uri, PresTupleInfo[] pTupleInfo){ 236 mUri = uri; 237 mTupleInfo = pTupleInfo; 238 } 239 240 public String getUri(){ 241 return mUri; 242 } 243 244 public PresTupleInfo[] getTupleInfo(){ 245 return mTupleInfo; 246 } 247 } 248 249 public class NotifyListData{ 250 private PresRlmiInfo mRlmiInfo; 251 private PresResInfo[] mResInfo; 252 253 NotifyListData(){ 254 mRlmiInfo = null; 255 mResInfo = null; 256 } 257 258 NotifyListData(PresRlmiInfo pRlmiInfo, PresResInfo[] pResInfo){ 259 mRlmiInfo = pRlmiInfo; 260 mResInfo = pResInfo; 261 } 262 263 public PresRlmiInfo getRlmiInfo(){ 264 return mRlmiInfo; 265 } 266 267 public PresResInfo[] getResInfo(){ 268 return mResInfo; 269 } 270 } 271 272 public IPresenceListener mPresenceListener = new IPresenceListener.Stub() { 273 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 274 throws RemoteException{ 275 try{ 276 return super.onTransact(code, data, reply, flags); 277 } catch (RemoteException e) { 278 Log.w("ListenerHandler", "Unexpected remote exception", e); 279 e.printStackTrace(); 280 throw e; 281 } 282 } 283 284 public void getVersionCb(String pVersion) { 285 logger.debug("pVersion=" + pVersion); 286 } 287 288 public void sipResponseReceived(PresSipResponse pSipResponse) throws RemoteException { 289 synchronized(mSyncObj){ 290 if(pSipResponse == null){ 291 logger.error("ISipResponseReceived pSipResponse=null"); 292 return; 293 } 294 295 logger.debug("pSipResponse.getCmdId() "+ 296 pSipResponse.getCmdId().getCmdId()); 297 logger.debug("getReasonPhrase() "+pSipResponse.getReasonPhrase()); 298 logger.debug("getsRequestID() "+pSipResponse.getRequestId()); 299 logger.debug("getsSipResponseCode() "+pSipResponse.getSipResponseCode()); 300 301 switch (pSipResponse.getCmdId().getCmdId()) { 302 case PresCmdId.UCE_PRES_CMD_PUBLISHMYCAP: 303 { 304 Message updateMesgSipPub = StackListener.this.obtainMessage( 305 PRESENCE_IMS_UNSOL_PUBLISH_SIPRESPONSE, 306 pSipResponse); 307 StackListener.this.sendMessage(updateMesgSipPub); 308 break; 309 } 310 311 case PresCmdId.UCE_PRES_CMD_GETCONTACTCAP: 312 case PresCmdId.UCE_PRES_CMD_GETCONTACTLISTCAP: 313 { 314 Message updateMesgSipPub = StackListener.this.obtainMessage( 315 PRESENCE_IMS_UNSOL_NOTIFY_UPDATE_SIPRESPONSE, 316 pSipResponse); 317 StackListener.this.sendMessage(updateMesgSipPub); 318 319 break; 320 } 321 322 case PresCmdId.UCE_PRES_CMD_SETNEWFEATURETAG: 323 { 324 logger.debug("UCE_PRES_CMD_SETNEWFEATURETAG, doesn't care it"); 325 break; 326 } 327 328 default: 329 logger.debug("CMD ID for unknown value=" + 330 pSipResponse.getCmdId().getCmdId()); 331 } 332 } 333 } 334 335 public void serviceUnAvailable(StatusCode statusCode) throws RemoteException { 336 synchronized(mSyncObj){ 337 if(statusCode == null){ 338 logger.error("statusCode=null"); 339 }else{ 340 logger.debug("IServiceUnAvailable statusCode " + 341 statusCode.getStatusCode()); 342 } 343 logger.debug("QPresListener_ServiceUnAvailable"); 344 345 RcsStackAdaptor rcsStackAdaptor = RcsStackAdaptor.getInstance(null); 346 if (rcsStackAdaptor != null) { 347 rcsStackAdaptor.setImsEnableState(false); 348 } 349 350 Intent intent = new Intent(RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE); 351 mContext.sendBroadcast(intent, 352 "com.android.ims.rcs.permission.STATUS_CHANGED"); 353 } 354 } 355 356 public void serviceAvailable(StatusCode statusCode) throws RemoteException { 357 synchronized(mSyncObj){ 358 if(statusCode == null){ 359 logger.error("statusCode=null"); 360 }else{ 361 logger.debug("IServiceAvailable statusCode " + 362 statusCode.getStatusCode()); 363 } 364 365 logger.debug("QPresListener_ServiceAvailable"); 366 367 RcsStackAdaptor rcsStackAdaptor = RcsStackAdaptor.getInstance(null); 368 if (rcsStackAdaptor != null) { 369 rcsStackAdaptor.setImsEnableState(true); 370 } 371 372 // Handle the cached trigger which got from stack 373 if(mPresencePublication != null && mPresencePublication.getHasCachedTrigger()){ 374 logger.debug("publish for cached trigger"); 375 376 mPresencePublication.invokePublish( 377 PresencePublication.PublishType.PRES_PUBLISH_TRIGGER_CACHED_TRIGGER); 378 } 379 380 Intent intent = new Intent(RcsManager.ACTION_RCS_SERVICE_AVAILABLE); 381 mContext.sendBroadcast(intent, 382 "com.android.ims.rcs.permission.STATUS_CHANGED"); 383 } 384 } 385 386 public void publishTriggering(PresPublishTriggerType publishTrigger) 387 throws RemoteException { 388 if(publishTrigger == null){ 389 logger.error("publishTrigger=null"); 390 }else{ 391 logger.debug("getPublishTrigeerType() "+ 392 publishTrigger.getPublishTrigeerType()); 393 } 394 logger.debug("ListenerHandler : PublishTriggering"); 395 396 Message publishTrigerMsg = StackListener.this.obtainMessage( 397 PRESENCE_IMS_UNSOL_PUBLISH_TRIGGER, publishTrigger); 398 StackListener.this.sendMessage(publishTrigerMsg); 399 } 400 401 public void listCapInfoReceived(PresRlmiInfo pRlmiInfo, PresResInfo[] pResInfo) 402 throws RemoteException { 403 if(pRlmiInfo == null || pResInfo == null){ 404 logger.error("pRlmiInfo=" + pRlmiInfo + " pResInfo=" + pResInfo); 405 }else{ 406 logger.debug("pRlmiInfo.getListName "+pRlmiInfo.getListName()); 407 logger.debug("pRlmiInfo.isFullState "+pRlmiInfo.isFullState()); 408 logger.debug("pRlmiInfo.getUri "+pRlmiInfo.getUri()); 409 logger.debug("pRlmiInfo.getVersion "+pRlmiInfo.getVersion()); 410 logger.debug("pRlmiInfo.getSubscriptionTerminatedReason " + 411 pRlmiInfo.getSubscriptionTerminatedReason()); 412 logger.debug("pRlmiInfo.getPresSubscriptionState " + 413 pRlmiInfo.getPresSubscriptionState()); 414 logger.debug("pRlmiInfo.getRequestID=" + pRlmiInfo.getRequestId()); 415 for(int i=0; i < pResInfo.length; i++ ){ 416 if(pResInfo[i] == null){ 417 logger.debug("ignoring, pResInfo[" + i + "]=null"); 418 continue; 419 } 420 421 logger.debug(".getDisplayName() "+pResInfo[i].getDisplayName()); 422 logger.debug("getResUri() "+pResInfo[i].getResUri()); 423 if(pResInfo[i].getInstanceInfo() != null){ 424 logger.debug("getInstanceInfo().getPresentityUri() "+ 425 pResInfo[i].getInstanceInfo().getPresentityUri()); 426 logger.debug("getInstanceInfo().getResId() "+ 427 pResInfo[i].getInstanceInfo().getResId()); 428 logger.debug("getInstanceInfo().getsReason() "+ 429 pResInfo[i].getInstanceInfo().getReason()); 430 logger.debug("getInstanceInfo().getResInstanceState() "+ 431 pResInfo[i].getInstanceInfo().getResInstanceState()); 432 if(pResInfo[i].getInstanceInfo().getTupleInfo() == null){ 433 logger.debug("pResInfo[" + i +"].getInstanceInfo().getTupleInfo()=null"); 434 continue; 435 } 436 437 logger.debug("getTupleInfo().length "+ 438 pResInfo[i].getInstanceInfo().getTupleInfo().length); 439 if(pResInfo[i].getInstanceInfo().getTupleInfo() != null){ 440 for(int j = 0; j < pResInfo[i].getInstanceInfo().getTupleInfo().length; 441 j++) 442 { 443 if(pResInfo[i].getInstanceInfo().getTupleInfo() == null){ 444 logger.debug("ignoring, pResInfo[" + i + 445 "].getInstanceInfo().getTupleInfo()[" +j + "]"); 446 continue; 447 } 448 449 logger.debug("getFeatureTag "+ 450 pResInfo[i].getInstanceInfo().getTupleInfo()[j]. 451 getFeatureTag()); 452 logger.debug("getsContactUri "+ 453 pResInfo[i].getInstanceInfo().getTupleInfo()[j]. 454 getContactUri()); 455 logger.debug("getsTimestamp "+ 456 pResInfo[i].getInstanceInfo().getTupleInfo()[j]. 457 getTimestamp()); 458 } 459 } 460 } 461 } 462 } 463 464 Message notifyListReceivedMsg = StackListener.this.obtainMessage( 465 PRESENCE_IMS_UNSOL_NOTIFY_LIST_UPDATE, 466 new NotifyListData(pRlmiInfo, pResInfo)); 467 logger.debug("Send PRESENCE_IMS_UNSOL_NOTIFY_LIST_UPDATE"); 468 469 StackListener.this.sendMessage(notifyListReceivedMsg); 470 } 471 472 public void capInfoReceived(String presentityURI, PresTupleInfo[] pTupleInfo) 473 throws RemoteException { 474 logger.debug("ListenerHandler : CapInfoReceived"); 475 if(presentityURI == null || presentityURI == null){ 476 logger.error("presentityURI=null or presentityURI=null"); 477 return; 478 } 479 480 logger.debug("ListenerHandler : CapInfoReceived : presentityURI "+ presentityURI); 481 482 Message notifyReceivedMsg = StackListener.this.obtainMessage( 483 PRESENCE_IMS_UNSOL_NOTIFY_UPDATE, 484 new NotifyData(presentityURI, pTupleInfo)); 485 StackListener.this.sendMessage(notifyReceivedMsg); 486 } 487 488 public void cmdStatus(PresCmdStatus pCmdStatus) throws RemoteException { 489 synchronized(mSyncObj){ 490 if(pCmdStatus == null || pCmdStatus.getCmdId() == null){ 491 logger.debug( "ICMDStatus error, pCmdStatus="+ pCmdStatus); 492 return; 493 } 494 495 logger.debug("ListenerHandler : CMDStatus"); 496 logger.debug("ListenerHandler : CMDStatus : pCmdStatus.getRequestID() "+ 497 pCmdStatus.getRequestId()); 498 logger.debug("ListenerHandler : CMDStatus : pCmdStatus.getUserData() "+ 499 pCmdStatus.getUserData()); 500 logger.debug("ListenerHandler : CMDStatus : pCmdStatus.getCmdId() "+ 501 pCmdStatus.getCmdId().getCmdId()); 502 if(pCmdStatus.getStatus() != null){ 503 logger.debug("ListenerHandler : CMDStatus : pCmdStatus.getStatus() "+ 504 pCmdStatus.getStatus().getStatusCode()); 505 } 506 507 switch (pCmdStatus.getCmdId().getCmdId()) { 508 case PresCmdId.UCE_PRES_CMD_PUBLISHMYCAP: 509 Message publishCmdMsg = StackListener.this.obtainMessage( 510 PRESENCE_IMS_UNSOL_PUBLISH_CMDSTATUS, 511 pCmdStatus); 512 StackListener.this.sendMessage(publishCmdMsg); 513 break; 514 515 case PresCmdId.UCE_PRES_CMD_GETCONTACTCAP: 516 case PresCmdId.UCE_PRES_CMD_GETCONTACTLISTCAP: 517 Message notifyUpdateCmdMsg = StackListener.this.obtainMessage( 518 PRESENCE_IMS_UNSOL_NOTIFY_UPDATE_CMDSTATUS, 519 pCmdStatus); 520 StackListener.this.sendMessage(notifyUpdateCmdMsg); 521 break; 522 523 case PresCmdId.UCE_PRES_CMD_SETNEWFEATURETAG: 524 logger.debug("UCE_PRES_CMD_SETNEWFEATURETAG: app does not care it"); 525 break; 526 527 default: 528 logger.debug("CMD ID for unknown value=" + 529 pCmdStatus.getCmdId().getCmdId()); 530 } 531 } 532 } 533 534 public void unpublishMessageSent() { 535 logger.debug("unpublishMessageSent()"); 536 } 537 }; 538 } 539 540