Home | History | Annotate | Download | only in presence
      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