Home | History | Annotate | Download | only in protocol
      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 
    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 
    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 
    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 
    218   private static boolean handleNotificationChannelEvent(
    219       VoicemailStatus.Editor unusedStatus, OmtpEvents unusedEvent) {
    220     return false;
    221   }
    222 
    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 
    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 
    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