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