Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2013 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.internal.telephony;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.net.Uri;
     24 import android.os.BadParcelableException;
     25 import android.os.Build;
     26 import android.telephony.NetworkRegistrationState;
     27 import android.telephony.Rlog;
     28 import android.telephony.ServiceState;
     29 import android.telephony.ims.ImsCallProfile;
     30 import android.telephony.ims.ImsConferenceState;
     31 import android.telephony.ims.ImsExternalCallState;
     32 import android.telephony.ims.ImsReasonInfo;
     33 
     34 import com.android.ims.ImsCall;
     35 import com.android.internal.telephony.gsm.SuppServiceNotification;
     36 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
     37 import com.android.internal.telephony.imsphone.ImsPhone;
     38 import com.android.internal.telephony.imsphone.ImsPhoneCall;
     39 import com.android.internal.telephony.test.TestConferenceEventPackageParser;
     40 
     41 import java.io.File;
     42 import java.io.FileInputStream;
     43 import java.io.FileNotFoundException;
     44 import java.util.ArrayList;
     45 import java.util.List;
     46 
     47 /**
     48  * Telephony tester receives the following intents where {name} is the phone name
     49  *
     50  * adb shell am broadcast -a com.android.internal.telephony.{name}.action_detached
     51  * adb shell am broadcast -a com.android.internal.telephony.{name}.action_attached
     52  * adb shell am broadcast -a com.android.internal.telephony.TestConferenceEventPackage -e filename
     53  *      test_filename.xml
     54  * adb shell am broadcast -a com.android.internal.telephony.TestServiceState --ei data_rat 10 --ei
     55  *      data_roaming_type 3
     56  * adb shell am broadcast -a com.android.internal.telephony.TestServiceState --es action reset
     57  *
     58  */
     59 public class TelephonyTester {
     60     private static final String LOG_TAG = "TelephonyTester";
     61     private static final boolean DBG = true;
     62 
     63     /**
     64      * Test-only intent used to send a test conference event package to the IMS framework.
     65      */
     66     private static final String ACTION_TEST_CONFERENCE_EVENT_PACKAGE =
     67             "com.android.internal.telephony.TestConferenceEventPackage";
     68 
     69     /**
     70      * Test-only intent used to send a test dialog event package to the IMS framework.
     71      */
     72     private static final String ACTION_TEST_DIALOG_EVENT_PACKAGE =
     73             "com.android.internal.telephony.TestDialogEventPackage";
     74 
     75     private static final String EXTRA_FILENAME = "filename";
     76     private static final String EXTRA_STARTPACKAGE = "startPackage";
     77     private static final String EXTRA_SENDPACKAGE = "sendPackage";
     78     private static final String EXTRA_DIALOGID = "dialogId";
     79     private static final String EXTRA_NUMBER = "number";
     80     private static final String EXTRA_STATE = "state";
     81     private static final String EXTRA_CANPULL = "canPull";
     82 
     83     /**
     84      * Test-only intent used to trigger supp service notification failure.
     85      */
     86     private static final String ACTION_TEST_SUPP_SRVC_FAIL =
     87             "com.android.internal.telephony.TestSuppSrvcFail";
     88     private static final String EXTRA_FAILURE_CODE = "failureCode";
     89 
     90     /**
     91      * Test-only intent used to trigger the signalling which occurs when a handover to WIFI fails.
     92      */
     93     private static final String ACTION_TEST_HANDOVER_FAIL =
     94             "com.android.internal.telephony.TestHandoverFail";
     95 
     96     /**
     97      * Test-only intent used to trigger signalling of a
     98      * {@link com.android.internal.telephony.gsm.SuppServiceNotification} to the {@link ImsPhone}.
     99      * Use {@link #EXTRA_CODE} to specify the
    100      * {@link com.android.internal.telephony.gsm.SuppServiceNotification#code}.
    101      */
    102     private static final String ACTION_TEST_SUPP_SRVC_NOTIFICATION =
    103             "com.android.internal.telephony.TestSuppSrvcNotification";
    104 
    105     private static final String EXTRA_CODE = "code";
    106     private static final String EXTRA_TYPE = "type";
    107 
    108     private static final String ACTION_TEST_SERVICE_STATE =
    109             "com.android.internal.telephony.TestServiceState";
    110 
    111     private static final String EXTRA_ACTION = "action";
    112     private static final String EXTRA_VOICE_RAT = "voice_rat";
    113     private static final String EXTRA_DATA_RAT = "data_rat";
    114     private static final String EXTRA_VOICE_REG_STATE = "voice_reg_state";
    115     private static final String EXTRA_DATA_REG_STATE = "data_reg_state";
    116     private static final String EXTRA_VOICE_ROAMING_TYPE = "voice_roaming_type";
    117     private static final String EXTRA_DATA_ROAMING_TYPE = "data_roaming_type";
    118 
    119     private static final String ACTION_RESET = "reset";
    120 
    121     private static List<ImsExternalCallState> mImsExternalCallStates = null;
    122 
    123     private Intent mServiceStateTestIntent;
    124 
    125     private Phone mPhone;
    126 
    127     // The static intent receiver one for all instances and we assume this
    128     // is running on the same thread as Dcc.
    129     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    130             @Override
    131         public void onReceive(Context context, Intent intent) {
    132             String action = intent.getAction();
    133             try {
    134                 if (DBG) log("sIntentReceiver.onReceive: action=" + action);
    135                 if (action.equals(mPhone.getActionDetached())) {
    136                     log("simulate detaching");
    137                     mPhone.getServiceStateTracker().mDetachedRegistrants.notifyRegistrants();
    138                 } else if (action.equals(mPhone.getActionAttached())) {
    139                     log("simulate attaching");
    140                     mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants();
    141                 } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) {
    142                     log("inject simulated conference event package");
    143                     handleTestConferenceEventPackage(context,
    144                             intent.getStringExtra(EXTRA_FILENAME));
    145                 } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) {
    146                     log("handle test dialog event package intent");
    147                     handleTestDialogEventPackageIntent(intent);
    148                 } else if (action.equals(ACTION_TEST_SUPP_SRVC_FAIL)) {
    149                     log("handle test supp svc failed intent");
    150                     handleSuppServiceFailedIntent(intent);
    151                 } else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) {
    152                     log("handle handover fail test intent");
    153                     handleHandoverFailedIntent();
    154                 } else if (action.equals(ACTION_TEST_SUPP_SRVC_NOTIFICATION)) {
    155                     log("handle supp service notification test intent");
    156                     sendTestSuppServiceNotification(intent);
    157                 } else if (action.equals(ACTION_TEST_SERVICE_STATE)) {
    158                     log("handle test service state changed intent");
    159                     // Trigger the service state update. The replacement will be done in
    160                     // overrideServiceState().
    161                     mServiceStateTestIntent = intent;
    162                     mPhone.getServiceStateTracker().sendEmptyMessage(
    163                             ServiceStateTracker.EVENT_NETWORK_STATE_CHANGED);
    164                 } else {
    165                     if (DBG) log("onReceive: unknown action=" + action);
    166                 }
    167             } catch (BadParcelableException e) {
    168                 Rlog.w(LOG_TAG, e);
    169             }
    170         }
    171     };
    172 
    173     TelephonyTester(Phone phone) {
    174         mPhone = phone;
    175 
    176         if (Build.IS_DEBUGGABLE) {
    177             IntentFilter filter = new IntentFilter();
    178 
    179             filter.addAction(mPhone.getActionDetached());
    180             log("register for intent action=" + mPhone.getActionDetached());
    181 
    182             filter.addAction(mPhone.getActionAttached());
    183             log("register for intent action=" + mPhone.getActionAttached());
    184 
    185             if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
    186                 log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
    187                 filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
    188                 filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE);
    189                 filter.addAction(ACTION_TEST_SUPP_SRVC_FAIL);
    190                 filter.addAction(ACTION_TEST_HANDOVER_FAIL);
    191                 filter.addAction(ACTION_TEST_SUPP_SRVC_NOTIFICATION);
    192                 mImsExternalCallStates = new ArrayList<ImsExternalCallState>();
    193             } else {
    194                 filter.addAction(ACTION_TEST_SERVICE_STATE);
    195                 log("register for intent action=" + ACTION_TEST_SERVICE_STATE);
    196             }
    197 
    198             phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler());
    199         }
    200     }
    201 
    202     void dispose() {
    203         if (Build.IS_DEBUGGABLE) {
    204             mPhone.getContext().unregisterReceiver(mIntentReceiver);
    205         }
    206     }
    207 
    208     private static void log(String s) {
    209         Rlog.d(LOG_TAG, s);
    210     }
    211 
    212     private void handleSuppServiceFailedIntent(Intent intent) {
    213         ImsPhone imsPhone = (ImsPhone) mPhone;
    214         if (imsPhone == null) {
    215             return;
    216         }
    217         int code = intent.getIntExtra(EXTRA_FAILURE_CODE, 0);
    218         imsPhone.notifySuppServiceFailed(PhoneInternalInterface.SuppService.values()[code]);
    219     }
    220 
    221     private void handleHandoverFailedIntent() {
    222         // Attempt to get the active IMS call
    223         ImsPhone imsPhone = (ImsPhone) mPhone;
    224         if (imsPhone == null) {
    225             return;
    226         }
    227 
    228         ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
    229         if (imsPhoneCall == null) {
    230             return;
    231         }
    232 
    233         ImsCall imsCall = imsPhoneCall.getImsCall();
    234         if (imsCall == null) {
    235             return;
    236         }
    237 
    238         imsCall.getImsCallSessionListenerProxy().callSessionHandoverFailed(imsCall.getCallSession(),
    239                 ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
    240                 new ImsReasonInfo());
    241     }
    242 
    243     /**
    244      * Handles request to send a test conference event package to the active Ims call.
    245      *
    246      * @see com.android.internal.telephony.test.TestConferenceEventPackageParser
    247      * @param context The context.
    248      * @param fileName The name of the test conference event package file to read.
    249      */
    250     private void handleTestConferenceEventPackage(Context context, String fileName) {
    251         // Attempt to get the active IMS call before parsing the test XML file.
    252         ImsPhone imsPhone = (ImsPhone) mPhone;
    253         if (imsPhone == null) {
    254             return;
    255         }
    256 
    257         ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
    258         if (imsPhoneCall == null) {
    259             return;
    260         }
    261 
    262         ImsCall imsCall = imsPhoneCall.getImsCall();
    263         if (imsCall == null) {
    264             return;
    265         }
    266 
    267         File packageFile = new File(context.getFilesDir(), fileName);
    268         final FileInputStream is;
    269         try {
    270             is = new FileInputStream(packageFile);
    271         } catch (FileNotFoundException ex) {
    272             log("Test conference event package file not found: " + packageFile.getAbsolutePath());
    273             return;
    274         }
    275 
    276         TestConferenceEventPackageParser parser = new TestConferenceEventPackageParser(is);
    277         ImsConferenceState imsConferenceState = parser.parse();
    278         if (imsConferenceState == null) {
    279             return;
    280         }
    281 
    282         imsCall.conferenceStateUpdated(imsConferenceState);
    283     }
    284 
    285     /**
    286      * Handles intents containing test dialog event package data.
    287      *
    288      * @param intent
    289      */
    290     private void handleTestDialogEventPackageIntent(Intent intent) {
    291         ImsPhone imsPhone = (ImsPhone) mPhone;
    292         if (imsPhone == null) {
    293             return;
    294         }
    295         ImsExternalCallTracker externalCallTracker = imsPhone.getExternalCallTracker();
    296         if (externalCallTracker == null) {
    297             return;
    298         }
    299 
    300         if (intent.hasExtra(EXTRA_STARTPACKAGE)) {
    301             mImsExternalCallStates.clear();
    302         } else if (intent.hasExtra(EXTRA_SENDPACKAGE)) {
    303             externalCallTracker.refreshExternalCallState(mImsExternalCallStates);
    304             mImsExternalCallStates.clear();
    305         } else if (intent.hasExtra(EXTRA_DIALOGID)) {
    306             ImsExternalCallState state = new ImsExternalCallState(
    307                     intent.getIntExtra(EXTRA_DIALOGID, 0),
    308                     Uri.parse(intent.getStringExtra(EXTRA_NUMBER)),
    309                     intent.getBooleanExtra(EXTRA_CANPULL, true),
    310                     intent.getIntExtra(EXTRA_STATE,
    311                             ImsExternalCallState.CALL_STATE_CONFIRMED),
    312                     ImsCallProfile.CALL_TYPE_VOICE,
    313                     false /* isHeld */
    314                     );
    315             mImsExternalCallStates.add(state);
    316         }
    317     }
    318 
    319     private void sendTestSuppServiceNotification(Intent intent) {
    320         if (intent.hasExtra(EXTRA_CODE) && intent.hasExtra(EXTRA_TYPE)) {
    321             int code = intent.getIntExtra(EXTRA_CODE, -1);
    322             int type = intent.getIntExtra(EXTRA_TYPE, -1);
    323             ImsPhone imsPhone = (ImsPhone) mPhone;
    324             if (imsPhone == null) {
    325                 return;
    326             }
    327             log("Test supp service notification:" + code);
    328             SuppServiceNotification suppServiceNotification = new SuppServiceNotification();
    329             suppServiceNotification.code = code;
    330             suppServiceNotification.notificationType = type;
    331             imsPhone.notifySuppSvcNotification(suppServiceNotification);
    332         }
    333     }
    334 
    335     void overrideServiceState(ServiceState ss) {
    336         if (mServiceStateTestIntent == null || ss == null) return;
    337         if (mServiceStateTestIntent.hasExtra(EXTRA_ACTION)
    338                 && ACTION_RESET.equals(mServiceStateTestIntent.getStringExtra(EXTRA_ACTION))) {
    339             log("Service state override reset");
    340             return;
    341         }
    342         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_REG_STATE)) {
    343             ss.setVoiceRegState(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_REG_STATE,
    344                     NetworkRegistrationState.REG_STATE_UNKNOWN));
    345             log("Override voice reg state with " + ss.getVoiceRegState());
    346         }
    347         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_REG_STATE)) {
    348             ss.setDataRegState(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE,
    349                     NetworkRegistrationState.REG_STATE_UNKNOWN));
    350             log("Override data reg state with " + ss.getDataRegState());
    351         }
    352         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_RAT)) {
    353             ss.setRilVoiceRadioTechnology(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_RAT,
    354                     ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN));
    355             log("Override voice rat with " + ss.getRilVoiceRadioTechnology());
    356         }
    357         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_RAT)) {
    358             ss.setRilDataRadioTechnology(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_RAT,
    359                     ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN));
    360             log("Override data rat with " + ss.getRilDataRadioTechnology());
    361         }
    362         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_ROAMING_TYPE)) {
    363             ss.setVoiceRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_ROAMING_TYPE,
    364                     ServiceState.ROAMING_TYPE_UNKNOWN));
    365             log("Override voice roaming type with " + ss.getVoiceRoamingType());
    366         }
    367         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_ROAMING_TYPE)) {
    368             ss.setDataRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_ROAMING_TYPE,
    369                     ServiceState.ROAMING_TYPE_UNKNOWN));
    370             log("Override data roaming type with " + ss.getDataRoamingType());
    371         }
    372     }
    373 }