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.lang.String;
     32 import java.util.ArrayList;
     33 import java.util.List;
     34 import android.text.TextUtils;
     35 
     36 import com.android.ims.internal.uce.presence.PresTupleInfo;
     37 import com.android.ims.internal.uce.presence.PresRlmiInfo;
     38 import com.android.ims.internal.uce.presence.PresResInfo;
     39 import com.android.ims.internal.uce.presence.PresResInstanceInfo;
     40 
     41 import com.android.ims.RcsManager.ResultCode;
     42 import com.android.ims.RcsPresenceInfo;
     43 import com.android.ims.RcsPresenceInfo.ServiceType;
     44 import com.android.ims.RcsPresenceInfo.ServiceState;
     45 
     46 import com.android.ims.internal.Logger;
     47 
     48 public class PresenceInfoParser{
     49     /*
     50      * The logger
     51      */
     52     static private Logger logger = Logger.getLogger("PresenceInfoParser");
     53 
     54     public PresenceInfoParser() {
     55     }
     56 
     57     static public RcsPresenceInfo getPresenceInfoFromTuple(String pPresentityURI,
     58             PresTupleInfo[] pTupleInfo){
     59         logger.debug("getPresenceInfoFromTuple: pPresentityURI=" + pPresentityURI +
     60                 " pTupleInfo=" + pTupleInfo);
     61 
     62         if(pPresentityURI == null){
     63             logger.error("pPresentityURI=" + pPresentityURI);
     64             return null;
     65         }
     66 
     67         String contactNumber = getPhoneFromUri(pPresentityURI);
     68         // Now that we got notification if the content didn't indicate it is not Volte
     69         // then it should be Volte enabled. So default to Volte enabled.
     70         int volteStatus = RcsPresenceInfo.VolteStatus.VOLTE_ENABLED;
     71 
     72         int ipVoiceCallState = RcsPresenceInfo.ServiceState.UNKNOWN;
     73         String ipVoiceCallServiceNumber = null;
     74          // We use the timestamp which when we received it instead of the one in PDU
     75         long ipVoiceCallTimestamp = System.currentTimeMillis();
     76 
     77         int ipVideoCallState = RcsPresenceInfo.ServiceState.UNKNOWN;
     78         String ipVideoCallServiceNumber = null;
     79         long ipVideoCallTimestamp = System.currentTimeMillis();
     80 
     81         if( pTupleInfo == null){
     82             logger.debug("pTupleInfo=null");
     83             return (new RcsPresenceInfo(contactNumber, volteStatus,
     84                 ipVoiceCallState, ipVoiceCallServiceNumber, ipVoiceCallTimestamp,
     85                 ipVideoCallState, ipVideoCallServiceNumber, ipVideoCallTimestamp));
     86         }
     87 
     88         for(int i = 0; i < pTupleInfo.length; i++){
     89             // Video call has high priority. If it supports video call it will support voice call.
     90             String featureTag = pTupleInfo[i].getFeatureTag();
     91             logger.debug("getFeatureTag " + i + ": " + featureTag);
     92             if(featureTag.equals(
     93                 "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\";video") ||
     94                 featureTag.equals("+g.gsma.rcs.telephony=\"cs,volte\";video")) {
     95                 logger.debug("Got Volte and VT enabled tuple");
     96                 ipVoiceCallState = RcsPresenceInfo.ServiceState.ONLINE;
     97                 ipVideoCallState = RcsPresenceInfo.ServiceState.ONLINE;
     98 
     99                 if(pTupleInfo[i].getContactUri() != null){
    100                     ipVideoCallServiceNumber = getPhoneFromUri(
    101                             pTupleInfo[i].getContactUri().toString());
    102                 }
    103             } else if(featureTag.equals("+g.gsma.rcs.telephony=\"cs\";video")) {
    104                 logger.debug("Got Volte disabled but VT enabled tuple");
    105                 ipVoiceCallState = RcsPresenceInfo.ServiceState.OFFLINE;
    106                 ipVideoCallState = RcsPresenceInfo.ServiceState.ONLINE;
    107 
    108                 if(pTupleInfo[i].getContactUri() != null){
    109                     ipVideoCallServiceNumber = getPhoneFromUri(
    110                             pTupleInfo[i].getContactUri().toString());
    111                 }
    112             }else{
    113                 if(featureTag.equals(
    114                     "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\"") ||
    115                     featureTag.equals("+g.gsma.rcs.telephony=\"cs,volte\"")) {
    116 
    117                     logger.debug("Got Volte only tuple");
    118                     ipVoiceCallState = RcsPresenceInfo.ServiceState.ONLINE;
    119                     // "OR" for multiple tuples.
    120                     if(RcsPresenceInfo.ServiceState.UNKNOWN == ipVideoCallState) {
    121                         ipVideoCallState = RcsPresenceInfo.ServiceState.OFFLINE;
    122                     }
    123 
    124                     if(pTupleInfo[i].getContactUri() != null){
    125                         ipVoiceCallServiceNumber = getPhoneFromUri(
    126                                 pTupleInfo[i].getContactUri().toString());
    127                     }
    128                 }else{
    129                     logger.debug("Ignoring feature tag: " + pTupleInfo[i].getFeatureTag());
    130                 }
    131            }
    132         }
    133 
    134         RcsPresenceInfo retPresenceInfo = new RcsPresenceInfo(contactNumber,volteStatus,
    135                 ipVoiceCallState, ipVoiceCallServiceNumber, ipVoiceCallTimestamp,
    136                 ipVideoCallState, ipVideoCallServiceNumber, ipVideoCallTimestamp);
    137 
    138         logger.debug("getPresenceInfoFromTuple: " + retPresenceInfo);
    139 
    140         return retPresenceInfo;
    141     }
    142 
    143     static private void addPresenceInfo(ArrayList<RcsPresenceInfo> presenceInfoList,
    144             RcsPresenceInfo presenceInfo){
    145         logger.debug("addPresenceInfo presenceInfoList=" + presenceInfoList +
    146                     " presenceInfo=" + presenceInfo);
    147 
    148         if(presenceInfoList == null || presenceInfo == null){
    149             logger.debug("addPresenceInfo presenceInfoList=" + presenceInfoList +
    150                     " presenceInfo=" + presenceInfo);
    151             return;
    152         }
    153 
    154         for(int i=0; i< presenceInfoList.size(); i++){
    155             RcsPresenceInfo presenceInfoTmp = presenceInfoList.get(i);
    156             if((presenceInfoTmp != null) && (presenceInfoTmp.getContactNumber() != null) &&
    157                     presenceInfoTmp.getContactNumber().equalsIgnoreCase(
    158                     presenceInfo.getContactNumber())){
    159                 // merge the information
    160                 presenceInfoList.set(i, new RcsPresenceInfo(presenceInfoTmp.getContactNumber(),
    161                         presenceInfoTmp.getVolteStatus(),
    162                         ((ServiceState.ONLINE == presenceInfo.getServiceState(
    163                                 ServiceType.VOLTE_CALL)) ||
    164                                 (ServiceState.ONLINE == presenceInfoTmp.getServiceState(
    165                                 ServiceType.VOLTE_CALL)))?ServiceState.ONLINE:
    166                                     presenceInfoTmp.getServiceState(ServiceType.VOLTE_CALL),
    167                         presenceInfoTmp.getServiceContact(ServiceType.VOLTE_CALL),
    168                         presenceInfoTmp.getTimeStamp(ServiceType.VOLTE_CALL),
    169                         ((ServiceState.ONLINE == presenceInfo.getServiceState(
    170                                 ServiceType.VT_CALL)) ||
    171                                 (ServiceState.ONLINE == presenceInfoTmp.getServiceState(
    172                                 ServiceType.VT_CALL)))?ServiceState.ONLINE:
    173                                     presenceInfoTmp.getServiceState(ServiceType.VT_CALL),
    174                         presenceInfoTmp.getServiceContact(ServiceType.VOLTE_CALL),
    175                         presenceInfoTmp.getTimeStamp(ServiceType.VOLTE_CALL)));
    176                 return;
    177             }
    178         }
    179 
    180         // didn't merge, so add the new one.
    181         presenceInfoList.add(presenceInfo);
    182     }
    183 
    184     static public RcsPresenceInfo[] getPresenceInfosFromPresenceRes(
    185             PresRlmiInfo pRlmiInfo, PresResInfo[] pRcsPresenceInfo) {
    186         if(pRcsPresenceInfo == null){
    187             logger.debug("getPresenceInfosFromPresenceRes pRcsPresenceInfo=null");
    188             return null;
    189         }
    190 
    191         ArrayList<RcsPresenceInfo> presenceInfoList = new ArrayList<RcsPresenceInfo>();
    192         for(int i=0; i < pRcsPresenceInfo.length; i++ ) {
    193             if(pRcsPresenceInfo[i].getInstanceInfo() == null){
    194                 logger.error("invalid data getInstanceInfo = null");
    195                 continue;
    196             }
    197 
    198             String resUri = pRcsPresenceInfo[i].getResUri();
    199             if(resUri == null){
    200                 logger.error("invalid data getResUri = null");
    201                 continue;
    202             }
    203 
    204             String contactNumber = getPhoneFromUri(resUri);
    205             if(contactNumber == null){
    206                 logger.error("invalid data contactNumber=null");
    207                 continue;
    208             }
    209 
    210             if(pRcsPresenceInfo[i].getInstanceInfo().getResInstanceState() ==
    211                     PresResInstanceInfo.UCE_PRES_RES_INSTANCE_STATE_TERMINATED){
    212                 logger.debug("instatance state is terminated");
    213                 String reason = pRcsPresenceInfo[i].getInstanceInfo().getReason();
    214                 if(reason != null){
    215                     reason = reason.toLowerCase();
    216                     // Noresource: 404. Device shall consider the resource as non-EAB capable
    217                     // Rejected: 403. Device shall consider the resource as non-EAB  capable
    218                     // Deactivated: 408, 481, 603, other 4xx, 5xx 6xx. Ignore.
    219                     // Give Up: 480. Ignore.
    220                     // Probation: 503. Ignore.
    221                     if(reason.equals("rejected") || reason.equals("noresource")){
    222                         RcsPresenceInfo presenceInfo = new RcsPresenceInfo(contactNumber,
    223                                 RcsPresenceInfo.VolteStatus.VOLTE_DISABLED,
    224                                 RcsPresenceInfo.ServiceState.OFFLINE, null,
    225                                 System.currentTimeMillis(),
    226                                 RcsPresenceInfo.ServiceState.OFFLINE, null,
    227                                 System.currentTimeMillis());
    228                         addPresenceInfo(presenceInfoList, presenceInfo);
    229                         logger.debug("reason=" + reason + " presenceInfo=" + presenceInfo);
    230                         continue;
    231                     }
    232                 }
    233             }
    234 
    235             RcsPresenceInfo presenceInfo = getPresenceInfoFromTuple(resUri,
    236                     pRcsPresenceInfo[i].getInstanceInfo().getTupleInfo());
    237             if(presenceInfo != null){
    238                 addPresenceInfo(presenceInfoList, presenceInfo);
    239             }else{
    240                 logger.debug("presenceInfo["+ i + "] = null");
    241                 addPresenceInfo(presenceInfoList, getPresenceInfoFromTuple(resUri, null));
    242             }
    243         }
    244 
    245         logger.debug("getPresenceInfoFromPresenceRes, presenceInfos:" + presenceInfoList);
    246         if(presenceInfoList.size() == 0){
    247             return null;
    248         }
    249 
    250         RcsPresenceInfo[] theArray = new RcsPresenceInfo[presenceInfoList.size()];
    251         return (RcsPresenceInfo[])presenceInfoList.toArray(theArray);
    252     }
    253 
    254     static public String getPhoneFromUri(String uriValue) {
    255         if(uriValue == null){
    256             return null;
    257         }
    258 
    259         int startIndex = uriValue.indexOf(":", 0);
    260         int endIndex = uriValue.indexOf("@", startIndex);
    261 
    262         logger.debug("getPhoneFromUri uriValue=" + uriValue +
    263             " startIndex=" + startIndex + " endIndex=" + endIndex);
    264 
    265         String number = uriValue;
    266         if(endIndex != -1){
    267             number = uriValue.substring(0, endIndex);
    268         }
    269 
    270         if (startIndex != -1) {
    271             return number = number.substring(startIndex + 1);
    272         }
    273 
    274         return number;
    275     }
    276 }
    277