1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.voicemail.impl.protocol; 18 19 import android.content.Context; 20 import android.provider.VoicemailContract.Status; 21 import android.support.annotation.IntDef; 22 import android.telecom.PhoneAccountHandle; 23 import com.android.voicemail.VoicemailComponent; 24 import com.android.voicemail.impl.DefaultOmtpEventHandler; 25 import com.android.voicemail.impl.OmtpEvents; 26 import com.android.voicemail.impl.OmtpEvents.Type; 27 import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; 28 import com.android.voicemail.impl.VoicemailStatus; 29 import com.android.voicemail.impl.VvmLog; 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 33 /** 34 * Handles {@link OmtpEvents} when {@link Vvm3Protocol} is being used. This handler writes custom 35 * error codes into the voicemail status table so support on the dialer side is required. 36 * 37 * <p>TODO(a bug) disable VVM3 by default so support on system dialer can be ensured. 38 */ 39 public class Vvm3EventHandler { 40 41 private static final String TAG = "Vvm3EventHandler"; 42 43 @Retention(RetentionPolicy.SOURCE) 44 @IntDef({ 45 VMS_DNS_FAILURE, 46 VMG_DNS_FAILURE, 47 SPG_DNS_FAILURE, 48 VMS_NO_CELLULAR, 49 VMG_NO_CELLULAR, 50 SPG_NO_CELLULAR, 51 VMS_TIMEOUT, 52 VMG_TIMEOUT, 53 STATUS_SMS_TIMEOUT, 54 SUBSCRIBER_BLOCKED, 55 UNKNOWN_USER, 56 UNKNOWN_DEVICE, 57 INVALID_PASSWORD, 58 MAILBOX_NOT_INITIALIZED, 59 SERVICE_NOT_PROVISIONED, 60 SERVICE_NOT_ACTIVATED, 61 USER_BLOCKED, 62 IMAP_GETQUOTA_ERROR, 63 IMAP_SELECT_ERROR, 64 IMAP_ERROR, 65 VMG_INTERNAL_ERROR, 66 VMG_DB_ERROR, 67 VMG_COMMUNICATION_ERROR, 68 SPG_URL_NOT_FOUND, 69 VMG_UNKNOWN_ERROR, 70 PIN_NOT_SET 71 }) 72 public @interface ErrorCode {} 73 74 public static final int VMS_DNS_FAILURE = -9001; 75 public static final int VMG_DNS_FAILURE = -9002; 76 public static final int SPG_DNS_FAILURE = -9003; 77 public static final int VMS_NO_CELLULAR = -9004; 78 public static final int VMG_NO_CELLULAR = -9005; 79 public static final int SPG_NO_CELLULAR = -9006; 80 public static final int VMS_TIMEOUT = -9007; 81 public static final int VMG_TIMEOUT = -9008; 82 public static final int STATUS_SMS_TIMEOUT = -9009; 83 84 public static final int SUBSCRIBER_BLOCKED = -9990; 85 public static final int UNKNOWN_USER = -9991; 86 public static final int UNKNOWN_DEVICE = -9992; 87 public static final int INVALID_PASSWORD = -9993; 88 public static final int MAILBOX_NOT_INITIALIZED = -9994; 89 public static final int SERVICE_NOT_PROVISIONED = -9995; 90 public static final int SERVICE_NOT_ACTIVATED = -9996; 91 public static final int USER_BLOCKED = -9998; 92 public static final int IMAP_GETQUOTA_ERROR = -9997; 93 public static final int IMAP_SELECT_ERROR = -9989; 94 public static final int IMAP_ERROR = -9999; 95 96 public static final int VMG_INTERNAL_ERROR = -101; 97 public static final int VMG_DB_ERROR = -102; 98 public static final int VMG_COMMUNICATION_ERROR = -103; 99 public static final int SPG_URL_NOT_FOUND = -301; 100 101 // Non VVM3 codes: 102 public static final int VMG_UNKNOWN_ERROR = -1; 103 public static final int PIN_NOT_SET = -100; 104 // STATUS SMS returned st=U and rc!=2. The user cannot be provisioned and must contact customer 105 // support. 106 public static final int SUBSCRIBER_UNKNOWN = -99; 107 handleEvent( Context context, OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status, OmtpEvents event)108 public static void handleEvent( 109 Context context, 110 OmtpVvmCarrierConfigHelper config, 111 VoicemailStatus.Editor status, 112 OmtpEvents event) { 113 boolean handled = false; 114 switch (event.getType()) { 115 case Type.CONFIGURATION: 116 handled = handleConfigurationEvent(context, status, event); 117 break; 118 case Type.DATA_CHANNEL: 119 handled = handleDataChannelEvent(status, event); 120 break; 121 case Type.NOTIFICATION_CHANNEL: 122 handled = handleNotificationChannelEvent(status, event); 123 break; 124 case Type.OTHER: 125 handled = handleOtherEvent(status, event); 126 break; 127 default: 128 VvmLog.wtf(TAG, "invalid event type " + event.getType() + " for " + event); 129 } 130 if (!handled) { 131 DefaultOmtpEventHandler.handleEvent(context, config, status, event); 132 } 133 } 134 handleConfigurationEvent( Context context, VoicemailStatus.Editor status, OmtpEvents event)135 private static boolean handleConfigurationEvent( 136 Context context, VoicemailStatus.Editor status, OmtpEvents event) { 137 switch (event) { 138 case CONFIG_REQUEST_STATUS_SUCCESS: 139 if (!isPinRandomized(context, status.getPhoneAccountHandle())) { 140 return false; 141 } else { 142 postError(status, PIN_NOT_SET); 143 } 144 break; 145 case CONFIG_ACTIVATING_SUBSEQUENT: 146 if (isPinRandomized(context, status.getPhoneAccountHandle())) { 147 status.setConfigurationState(PIN_NOT_SET); 148 } else { 149 status.setConfigurationState(Status.CONFIGURATION_STATE_OK); 150 } 151 status 152 .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK) 153 .setDataChannelState(Status.DATA_CHANNEL_STATE_OK) 154 .apply(); 155 break; 156 case CONFIG_DEFAULT_PIN_REPLACED: 157 postError(status, PIN_NOT_SET); 158 break; 159 case CONFIG_STATUS_SMS_TIME_OUT: 160 postError(status, STATUS_SMS_TIMEOUT); 161 break; 162 default: 163 return false; 164 } 165 return true; 166 } 167 handleDataChannelEvent(VoicemailStatus.Editor status, OmtpEvents event)168 private static boolean handleDataChannelEvent(VoicemailStatus.Editor status, OmtpEvents event) { 169 switch (event) { 170 case DATA_NO_CONNECTION: 171 case DATA_NO_CONNECTION_CELLULAR_REQUIRED: 172 case DATA_ALL_SOCKET_CONNECTION_FAILED: 173 postError(status, VMS_NO_CELLULAR); 174 break; 175 case DATA_SSL_INVALID_HOST_NAME: 176 case DATA_CANNOT_ESTABLISH_SSL_SESSION: 177 case DATA_IOE_ON_OPEN: 178 postError(status, VMS_TIMEOUT); 179 break; 180 case DATA_CANNOT_RESOLVE_HOST_ON_NETWORK: 181 postError(status, VMS_DNS_FAILURE); 182 break; 183 case DATA_BAD_IMAP_CREDENTIAL: 184 postError(status, IMAP_ERROR); 185 break; 186 case DATA_AUTH_UNKNOWN_USER: 187 postError(status, UNKNOWN_USER); 188 break; 189 case DATA_AUTH_UNKNOWN_DEVICE: 190 postError(status, UNKNOWN_DEVICE); 191 break; 192 case DATA_AUTH_INVALID_PASSWORD: 193 postError(status, INVALID_PASSWORD); 194 break; 195 case DATA_AUTH_MAILBOX_NOT_INITIALIZED: 196 postError(status, MAILBOX_NOT_INITIALIZED); 197 break; 198 case DATA_AUTH_SERVICE_NOT_PROVISIONED: 199 postError(status, SERVICE_NOT_PROVISIONED); 200 break; 201 case DATA_AUTH_SERVICE_NOT_ACTIVATED: 202 postError(status, SERVICE_NOT_ACTIVATED); 203 break; 204 case DATA_AUTH_USER_IS_BLOCKED: 205 postError(status, USER_BLOCKED); 206 break; 207 case DATA_REJECTED_SERVER_RESPONSE: 208 case DATA_INVALID_INITIAL_SERVER_RESPONSE: 209 case DATA_SSL_EXCEPTION: 210 postError(status, IMAP_ERROR); 211 break; 212 default: 213 return false; 214 } 215 return true; 216 } 217 handleNotificationChannelEvent( VoicemailStatus.Editor unusedStatus, OmtpEvents unusedEvent)218 private static boolean handleNotificationChannelEvent( 219 VoicemailStatus.Editor unusedStatus, OmtpEvents unusedEvent) { 220 return false; 221 } 222 handleOtherEvent(VoicemailStatus.Editor status, OmtpEvents event)223 private static boolean handleOtherEvent(VoicemailStatus.Editor status, OmtpEvents event) { 224 switch (event) { 225 case VVM3_NEW_USER_SETUP_FAILED: 226 postError(status, MAILBOX_NOT_INITIALIZED); 227 break; 228 case VVM3_VMG_DNS_FAILURE: 229 postError(status, VMG_DNS_FAILURE); 230 break; 231 case VVM3_SPG_DNS_FAILURE: 232 postError(status, SPG_DNS_FAILURE); 233 break; 234 case VVM3_VMG_CONNECTION_FAILED: 235 postError(status, VMG_NO_CELLULAR); 236 break; 237 case VVM3_SPG_CONNECTION_FAILED: 238 postError(status, SPG_NO_CELLULAR); 239 break; 240 case VVM3_VMG_TIMEOUT: 241 postError(status, VMG_TIMEOUT); 242 break; 243 case VVM3_SUBSCRIBER_PROVISIONED: 244 postError(status, SERVICE_NOT_ACTIVATED); 245 break; 246 case VVM3_SUBSCRIBER_BLOCKED: 247 postError(status, SUBSCRIBER_BLOCKED); 248 break; 249 case VVM3_SUBSCRIBER_UNKNOWN: 250 postError(status, SUBSCRIBER_UNKNOWN); 251 break; 252 default: 253 return false; 254 } 255 return true; 256 } 257 postError(VoicemailStatus.Editor editor, @ErrorCode int errorCode)258 private static void postError(VoicemailStatus.Editor editor, @ErrorCode int errorCode) { 259 switch (errorCode) { 260 case VMG_DNS_FAILURE: 261 case SPG_DNS_FAILURE: 262 case VMG_NO_CELLULAR: 263 case SPG_NO_CELLULAR: 264 case VMG_TIMEOUT: 265 case SUBSCRIBER_BLOCKED: 266 case UNKNOWN_USER: 267 case UNKNOWN_DEVICE: 268 case INVALID_PASSWORD: 269 case MAILBOX_NOT_INITIALIZED: 270 case SERVICE_NOT_PROVISIONED: 271 case SERVICE_NOT_ACTIVATED: 272 case USER_BLOCKED: 273 case VMG_UNKNOWN_ERROR: 274 case SPG_URL_NOT_FOUND: 275 case VMG_INTERNAL_ERROR: 276 case VMG_DB_ERROR: 277 case VMG_COMMUNICATION_ERROR: 278 case PIN_NOT_SET: 279 case SUBSCRIBER_UNKNOWN: 280 editor.setConfigurationState(errorCode); 281 break; 282 case VMS_NO_CELLULAR: 283 case VMS_DNS_FAILURE: 284 case VMS_TIMEOUT: 285 case IMAP_GETQUOTA_ERROR: 286 case IMAP_SELECT_ERROR: 287 case IMAP_ERROR: 288 editor.setDataChannelState(errorCode); 289 break; 290 case STATUS_SMS_TIMEOUT: 291 editor.setNotificationChannelState(errorCode); 292 break; 293 default: 294 VvmLog.wtf(TAG, "unknown error code: " + errorCode); 295 } 296 editor.apply(); 297 } 298 isPinRandomized(Context context, PhoneAccountHandle phoneAccountHandle)299 private static boolean isPinRandomized(Context context, PhoneAccountHandle phoneAccountHandle) { 300 if (phoneAccountHandle == null) { 301 // This should never happen. 302 VvmLog.e(TAG, "status editor has null phone account handle"); 303 return false; 304 } 305 return VoicemailComponent.get(context) 306 .getVoicemailClient() 307 .createPinChanger(context, phoneAccountHandle) 308 .getScrambledPin() 309 != null; 310 } 311 } 312