Home | History | Annotate | Download | only in ims
      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;
     30 
     31 import java.util.Set;
     32 import java.util.HashMap;
     33 import java.util.Iterator;
     34 import java.util.Map;
     35 import java.util.List;
     36 import java.util.ArrayList;
     37 import android.os.RemoteException;
     38 import android.content.Context;
     39 import android.os.Handler;
     40 import android.os.Message;
     41 import android.os.HandlerThread;
     42 import android.os.Looper;
     43 import android.telephony.PhoneNumberUtils;
     44 
     45 import com.android.ims.internal.uce.presence.PresCmdStatus;
     46 
     47 import com.android.ims.internal.Logger;
     48 import com.android.ims.RcsManager.ResultCode;
     49 import com.android.ims.RcsPresenceInfo;
     50 import com.android.ims.IRcsPresenceListener;
     51 
     52 import com.android.service.ims.presence.PresenceTask;
     53 import com.android.service.ims.presence.PresenceCapabilityTask;
     54 import com.android.service.ims.presence.PresenceAvailabilityTask;
     55 
     56 /**
     57  * TaskManager
     58  */
     59 public class TaskManager{
     60     /*
     61      * The logger
     62      */
     63     private Logger logger = Logger.getLogger(this.getClass().getName());
     64 
     65     private static TaskManager sTaskManager = null;
     66 
     67     private int mTaskId = 0;
     68 
     69     public final static int TASK_TYPE_GET_CAPABILITY   = 1;
     70     public final static int TASK_TYPE_GET_AVAILABILITY = 2;
     71     public final static int TASK_TYPE_PUBLISH          = 3;
     72 
     73     private Map<String, Task> mTaskMap;
     74 
     75     private final Object mSyncObj = new Object();
     76 
     77     private static final int TASK_MANAGER_ON_TERMINATED = 1;
     78     private static final int TASK_MANAGER_ON_TIMEOUT = 2;
     79 
     80     private static MessageHandler sMsgHandler;
     81 
     82     public TaskManager(){
     83         logger.debug("TaskManager created.");
     84         mTaskMap = new HashMap<String, Task>();
     85 
     86         HandlerThread messageHandlerThread = new HandlerThread("MessageHandler",
     87                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
     88 
     89         messageHandlerThread.start();
     90         Looper messageHandlerLooper = messageHandlerThread.getLooper();
     91         sMsgHandler = new MessageHandler(messageHandlerLooper);
     92     }
     93 
     94     public static synchronized TaskManager getDefault(){
     95         if(sTaskManager == null){
     96             sTaskManager = new TaskManager();
     97         }
     98 
     99         return sTaskManager;
    100     }
    101 
    102     public synchronized int generateTaskId(){
    103         return mTaskId++;
    104     }
    105 
    106     public void putTask(int taskId, Task task){
    107         synchronized (mSyncObj){
    108             putTaskInternal(taskId, task);
    109         }
    110     }
    111 
    112     private synchronized void putTaskInternal(int taskId, Task task){
    113         Task sameKeyTask = mTaskMap.put(String.valueOf(taskId), task);
    114 
    115         logger.debug("Added Task: " + task + "Original same key task:" + sameKeyTask);
    116     }
    117 
    118     public int addCapabilityTask(Context context, String[] contacts,
    119             IRcsPresenceListener listener, long timeout){
    120         int taskId = TaskManager.getDefault().generateTaskId();
    121         synchronized (mSyncObj){
    122             Task task = new PresenceCapabilityTask(context, taskId, TASK_TYPE_GET_CAPABILITY,
    123                     listener, contacts, timeout);
    124             putTaskInternal(taskId, task);
    125         }
    126 
    127         return taskId;
    128     }
    129 
    130     public int addAvailabilityTask(String contact, IRcsPresenceListener listener){
    131         int taskId = TaskManager.getDefault().generateTaskId();
    132         synchronized (mSyncObj){
    133             String[] contacts = new String[1];
    134             contacts[0] = contact;
    135             Task task = new PresenceAvailabilityTask(taskId, TASK_TYPE_GET_AVAILABILITY,
    136                     listener, contacts);
    137             putTaskInternal(taskId, task);
    138         }
    139 
    140         return taskId;
    141     }
    142 
    143     public int addPublishTask(String contact, IRcsPresenceListener listener){
    144         int taskId = TaskManager.getDefault().generateTaskId();
    145         synchronized (mSyncObj){
    146             String[] contacts = new String[1];
    147             contacts[0] = contact;
    148             Task task = new PresenceTask(taskId, TASK_TYPE_PUBLISH, listener, contacts);
    149             putTaskInternal(taskId, task);
    150         }
    151 
    152         return taskId;
    153     }
    154 
    155     // If need to call getTask in this class please add another one getTaskInternal
    156     public Task getTask(int taskId){
    157         synchronized (mSyncObj){
    158             return mTaskMap.get(String.valueOf(taskId));
    159         }
    160     }
    161 
    162     public void removeTask(int taskId){
    163         synchronized (mSyncObj){
    164             Task task = mTaskMap.remove(String.valueOf(taskId));
    165             if(task instanceof PresenceCapabilityTask){
    166                 ((PresenceCapabilityTask)task).cancelTimer();
    167             }
    168             logger.debug("Removed Task: " + task);
    169         }
    170     }
    171 
    172     public Task getTaskByRequestId(int sipRequestId){
    173         synchronized (mSyncObj){
    174             Set<String> keys= mTaskMap.keySet();
    175             if(keys == null){
    176                 logger.debug("getTaskByRequestId keys=null");
    177                 return null;
    178             }
    179 
    180             for(String key:keys){
    181                 if(mTaskMap.get(key).mSipRequestId == sipRequestId){
    182                     logger.debug("getTaskByRequestId, sipRequestId=" + sipRequestId +
    183                             " task=" + mTaskMap.get(key));
    184                     return mTaskMap.get(key);
    185                 }
    186             }
    187         }
    188 
    189         logger.debug("getTaskByRequestId, sipRequestId=" + sipRequestId + " task=null");
    190         return null;
    191     }
    192 
    193     public void onTerminated(String contact){ // for single number capability polling
    194         if(contact == null){
    195             return;
    196         }
    197 
    198         synchronized (mSyncObj){
    199             Set<String> keys= mTaskMap.keySet();
    200             if(keys == null){
    201                 logger.debug("onTerminated keys is null");
    202                 return;
    203             }
    204 
    205             for(String key:keys){
    206                 Task task = mTaskMap.get(key);
    207                 if(task == null){
    208                     continue;
    209                 }
    210 
    211                 if(task instanceof PresenceCapabilityTask){
    212                     PresenceCapabilityTask capabilityTask = (PresenceCapabilityTask)task;
    213                     if(capabilityTask.mContacts != null && capabilityTask.mContacts[0] != null &&
    214                             PhoneNumberUtils.compare(contact, capabilityTask.mContacts[0])){
    215                         if(!capabilityTask.isWaitingForNotify()){
    216                             logger.debug("onTerminated the tesk is not waiting for NOTIFY yet");
    217                             continue;
    218                         }
    219 
    220                         MessageData messageData = new MessageData();
    221                         messageData.mTask = capabilityTask;
    222                         messageData.mReason = null;
    223 
    224                         Message notifyMessage = sMsgHandler.obtainMessage(
    225                                 TASK_MANAGER_ON_TERMINATED,
    226                                 messageData);
    227                         sMsgHandler.sendMessage(notifyMessage);
    228                     }
    229                 }
    230             }
    231         }
    232     }
    233 
    234     public void onTerminated(int requestId, String reason){
    235         logger.debug("onTerminated requestId=" + requestId + " reason=" + reason);
    236 
    237         Task task = getTaskByRequestId(requestId);
    238         if(task == null){
    239             logger.debug("onTerminated Can't find request " + requestId);
    240             return;
    241         }
    242 
    243         synchronized (mSyncObj){
    244             if(task instanceof PresenceCapabilityTask){
    245                 MessageData messageData = new MessageData();
    246                 messageData.mTask = (PresenceCapabilityTask)task;
    247                 messageData.mReason = reason;
    248 
    249                 Message notifyMessage = sMsgHandler.obtainMessage(TASK_MANAGER_ON_TERMINATED,
    250                         messageData);
    251                 sMsgHandler.sendMessage(notifyMessage);
    252             }
    253         }
    254     }
    255 
    256     public void onTimeout(int taskId){
    257         logger.debug("onTimeout taskId=" + taskId);
    258 
    259         Task task = getTask(taskId);
    260         if(task == null){
    261             logger.debug("onTimeout task = null");
    262             return;
    263         }
    264         synchronized (mSyncObj){
    265             if(task instanceof PresenceCapabilityTask){
    266                 MessageData messageData = new MessageData();
    267                 messageData.mTask = (PresenceCapabilityTask)task;
    268                 messageData.mReason = null;
    269 
    270                 Message timeoutMessage = sMsgHandler.obtainMessage(TASK_MANAGER_ON_TIMEOUT,
    271                         messageData);
    272                 sMsgHandler.sendMessage(timeoutMessage);
    273             }else{
    274                 logger.debug("not PresenceCapabilityTask, taskId=" + taskId);
    275             }
    276         }
    277     }
    278 
    279     public class MessageData{
    280         public PresenceCapabilityTask mTask;
    281         public String mReason;
    282     }
    283 
    284     public class MessageHandler extends Handler{
    285         MessageHandler(Looper looper){
    286             super(looper);
    287         }
    288 
    289         @Override
    290         public void handleMessage(Message msg) {
    291             super.handleMessage(msg);
    292 
    293             logger.debug( "Thread=" + Thread.currentThread().getName() + " received "
    294                     + msg);
    295 
    296 
    297 
    298             if(msg == null){
    299                 logger.error("msg=null");
    300                 return;
    301             }
    302 
    303             switch (msg.what) {
    304                 case  TASK_MANAGER_ON_TERMINATED:
    305                 {
    306                     MessageData messageData = (MessageData) msg.obj;
    307                     if(messageData != null && messageData.mTask != null){
    308                         messageData.mTask.onTerminated(messageData.mReason);
    309                     }
    310                     break;
    311                 }
    312 
    313                 case TASK_MANAGER_ON_TIMEOUT:
    314                 {
    315                     MessageData messageData = (MessageData) msg.obj;
    316                     if(messageData != null && messageData.mTask != null){
    317                         messageData.mTask.onTimeout();
    318                     }
    319                     break;
    320                 }
    321 
    322                 default:
    323                     logger.debug("handleMessage unknown msg=" + msg.what);
    324             }
    325         }
    326     }
    327 
    328     public void clearTimeoutAvailabilityTask(long availabilityExpire) {
    329        logger.debug("clearTimeoutAvailabilityTask");
    330 
    331         synchronized (mSyncObj) {
    332             long currentTime = System.currentTimeMillis();
    333 
    334             Iterator<Map.Entry<String, Task>> iterator = mTaskMap.entrySet().iterator();
    335             while (iterator.hasNext()) {
    336                 Map.Entry<String, Task> entry = iterator.next();
    337 
    338                 Task task = (Task) entry.getValue();
    339                 logger.debug("Currently existing Availability task, key: " + entry.getKey()
    340                         + ", Task: " + task);
    341 
    342                 if ((task != null) && (task instanceof PresenceAvailabilityTask)) {
    343                     PresenceAvailabilityTask presenceTask = (PresenceAvailabilityTask)task;
    344 
    345                     long notifyTimestamp = presenceTask.getNotifyTimestamp();
    346                     long createTimestamp = presenceTask.getCreateTimestamp();
    347                     logger.debug("createTimestamp=" + createTimestamp + " notifyTimestamp=" +
    348                             notifyTimestamp + " currentTime=" + currentTime);
    349 
    350                      // remove it if it didn't get notify in 60s.
    351                      // or get notify for 60s
    352                     if(((notifyTimestamp != 0) &&
    353                             (notifyTimestamp + availabilityExpire < currentTime)) ||
    354                             (notifyTimestamp == 0) &&
    355                             (createTimestamp + availabilityExpire < currentTime)) {
    356                         logger.debug("remove expired availability task:" + presenceTask);
    357                         iterator.remove();
    358                     }
    359                 }
    360             }
    361         }
    362     }
    363 
    364     public PresenceAvailabilityTask getAvailabilityTaskByContact(String contact){
    365         synchronized (mSyncObj){
    366             Set<String> keys= mTaskMap.keySet();
    367             if(keys == null){
    368                 logger.debug("getTaskByContact keys=null");
    369                 return null;
    370             }
    371 
    372             for(String key:keys){
    373                 Task task = mTaskMap.get(key);
    374                 if(task == null){
    375                     continue;
    376                 }
    377 
    378                 if(task instanceof PresenceAvailabilityTask){
    379                     PresenceAvailabilityTask availabilityTask = (PresenceAvailabilityTask)task;
    380                     if(PhoneNumberUtils.compare(contact, availabilityTask.mContacts[0])){
    381                         return availabilityTask;
    382                     }
    383                 }
    384             }
    385         }
    386 
    387         return null;
    388     }
    389 }
    390 
    391