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 android.content.Intent; 32 import android.os.IBinder; 33 import android.os.RemoteException; 34 import android.app.Service; 35 import android.os.SystemProperties; 36 import android.os.Handler; 37 import android.os.Looper; 38 import android.os.Message; 39 import android.os.HandlerThread; 40 import android.os.Process; 41 import java.util.ArrayList; 42 import android.content.ContentValues; 43 import android.text.TextUtils; 44 45 import com.android.ims.internal.Logger; 46 import com.android.ims.RcsManager.ResultCode; 47 import com.android.ims.RcsPresence; 48 import com.android.ims.RcsPresenceInfo; 49 50 /** 51 * This service essentially plays the role of a "worker thread", allowing us to store 52 * presence information. 53 */ 54 public class PersistService extends Service { 55 private Logger logger = Logger.getLogger(this.getClass().getName()); 56 57 private static final int MESSAGE_PRESENCE_CHANGED = 1; 58 private static final int MESSAGE_PUBLISH_STATE_CHANGED = 2; 59 60 private int mVltProvisionErrorCount = 0; 61 private Looper mServiceLooper = null; 62 private ServiceHandler mServiceHandler = null; 63 private EABContactManager mEABContactManager = null; 64 65 @Override 66 public void onCreate() { 67 mEABContactManager = new EABContactManager(getContentResolver(), getPackageName()); 68 69 // separate thread because the service normally runs in the process's 70 // main thread, which we don't want to block. 71 HandlerThread thread = new HandlerThread("PersistServiceThread", 72 Process.THREAD_PRIORITY_BACKGROUND); 73 thread.start(); 74 75 mServiceLooper = thread.getLooper(); 76 mServiceHandler = new ServiceHandler(mServiceLooper); 77 } 78 79 @Override 80 public int onStartCommand(Intent intent, int flags, int startId) { 81 if(intent == null) { 82 return Service.START_NOT_STICKY; 83 } 84 85 if(RcsPresence.ACTION_PRESENCE_CHANGED.equals(intent.getAction())) { 86 Message msg = mServiceHandler.obtainMessage(MESSAGE_PRESENCE_CHANGED); 87 msg.arg1 = startId; 88 msg.obj = intent; 89 mServiceHandler.sendMessage(msg); 90 return Service.START_NOT_STICKY; 91 } else if(RcsPresence.ACTION_PUBLISH_STATE_CHANGED.equals(intent.getAction())) { 92 Message msg = mServiceHandler.obtainMessage(MESSAGE_PUBLISH_STATE_CHANGED); 93 msg.arg1 = startId; 94 msg.obj = intent; 95 mServiceHandler.sendMessage(msg); 96 return Service.START_NOT_STICKY; 97 } else { 98 logger.debug("unknown intent=" + intent); 99 } 100 101 return Service.START_NOT_STICKY; 102 } 103 104 @Override 105 public void onDestroy() { 106 mServiceLooper.quit(); 107 } 108 109 @Override 110 public IBinder onBind(Intent intent) { 111 return null; 112 } 113 114 private final class ServiceHandler extends Handler { 115 public ServiceHandler(Looper looper) { 116 super(looper); 117 } 118 119 /** 120 * Handler to save the presence information. 121 */ 122 @Override 123 public void handleMessage(Message msg) { 124 super.handleMessage(msg); 125 logger.print( "Thread=" + Thread.currentThread().getName() + " received " 126 + msg); 127 if(msg == null){ 128 logger.error("msg=null"); 129 return; 130 } 131 132 int serviceId = msg.arg1; 133 Intent intent = (Intent)msg.obj; 134 logger.print("handleMessage serviceId: " + serviceId + " intent: " + intent); 135 switch (msg.what) { 136 case MESSAGE_PRESENCE_CHANGED: 137 if (intent != null) { 138 if (RcsPresence.ACTION_PRESENCE_CHANGED.equals(intent.getAction())) { 139 handlePresence(intent); 140 } else { 141 logger.debug("I don't care about intent: " + intent); 142 } 143 intent.setComponent(null); 144 sendBroadcast(intent); 145 } 146 break; 147 148 case MESSAGE_PUBLISH_STATE_CHANGED: 149 if (intent != null) { 150 if (RcsPresence.ACTION_PUBLISH_STATE_CHANGED.equals(intent.getAction())) { 151 int publishState = intent.getIntExtra(RcsPresence.EXTRA_PUBLISH_STATE, 152 RcsPresence.PublishState.PUBLISH_STATE_200_OK); 153 handlePublishState(publishState); 154 } else { 155 logger.debug("I don't care about intent: " + intent); 156 } 157 } 158 break; 159 160 default: 161 logger.debug("unknown message:" + msg); 162 } 163 } 164 } 165 166 private void handlePublishState(int publishState) { 167 if(publishState == RcsPresence.PublishState.PUBLISH_STATE_VOLTE_PROVISION_ERROR) { 168 mVltProvisionErrorCount += 1; 169 if(mVltProvisionErrorCount >= 3){ 170 if(mEABContactManager != null) { 171 mEABContactManager.updateAllCapabilityToUnknown(); 172 logger.print("updateAllCapabilityToUnknown for publish 403 error"); 173 Intent intent = new Intent(RcsPresence.ACTION_PRESENCE_CHANGED); 174 sendBroadcast(intent); 175 } else { 176 logger.error("mEABContactManager is null"); 177 } 178 } 179 } else if(publishState == RcsPresence.PublishState.PUBLISH_STATE_RCS_PROVISION_ERROR){ 180 mVltProvisionErrorCount = 0; 181 if(mEABContactManager != null) { 182 mEABContactManager.updateAllVtCapabilityToUnknown(); 183 logger.print("updateAllVtCapabilityToUnknown for publish 404 error"); 184 Intent intent = new Intent(RcsPresence.ACTION_PRESENCE_CHANGED); 185 sendBroadcast(intent); 186 } else { 187 logger.error("mEABContactManager is null"); 188 } 189 } else { 190 mVltProvisionErrorCount = 0; 191 } 192 } 193 194 private void handlePresence(Intent intent) { 195 if(intent == null) { 196 return; 197 } 198 199 // save the presence information. 200 ArrayList<RcsPresenceInfo> rcsPresenceInfoList = intent.getParcelableArrayListExtra( 201 RcsPresence.EXTRA_PRESENCE_INFO_LIST); 202 boolean updateLastTimestamp = intent.getBooleanExtra("updateLastTimestamp", true); 203 logger.print("updateLastTimestamp=" + updateLastTimestamp + 204 " RcsPresenceInfoList=" + rcsPresenceInfoList); 205 for(int i=0; i< rcsPresenceInfoList.size(); i++){ 206 RcsPresenceInfo rcsPresenceInfoTmp = rcsPresenceInfoList.get(i); 207 if((rcsPresenceInfoTmp != null) && !TextUtils.isEmpty( 208 rcsPresenceInfoTmp.getContactNumber())){ 209 mEABContactManager.update(rcsPresenceInfoTmp, updateLastTimestamp); 210 } 211 } 212 } 213 } 214 215 216