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.content.SharedPreferences;
24import android.net.Uri;
25import android.os.BadParcelableException;
26import android.os.Build;
27import android.preference.PreferenceManager;
28import android.telephony.Rlog;
29import android.telephony.ServiceState;
30
31import com.android.ims.ImsCall;
32import com.android.ims.ImsCallProfile;
33import com.android.ims.ImsConferenceState;
34import com.android.ims.ImsExternalCallState;
35import com.android.ims.ImsReasonInfo;
36import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
37import com.android.internal.telephony.imsphone.ImsPhone;
38import com.android.internal.telephony.imsphone.ImsPhoneCall;
39import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
40import com.android.internal.telephony.test.TestConferenceEventPackageParser;
41
42import java.io.File;
43import java.io.FileInputStream;
44import java.io.FileNotFoundException;
45import java.util.ArrayList;
46import java.util.List;
47
48/**
49 * Telephony tester receives the following intents where {name} is the phone name
50 *
51 * adb shell am broadcast -a com.android.internal.telephony.{name}.action_detached
52 * adb shell am broadcast -a com.android.internal.telephony.{name}.action_attached
53 * adb shell am broadcast -a com.android.internal.telephony.TestConferenceEventPackage -e filename
54 *      test_filename.xml
55 */
56public class TelephonyTester {
57    private static final String LOG_TAG = "TelephonyTester";
58    private static final boolean DBG = true;
59
60    /**
61     * Test-only intent used to send a test conference event package to the IMS framework.
62     */
63    private static final String ACTION_TEST_CONFERENCE_EVENT_PACKAGE =
64            "com.android.internal.telephony.TestConferenceEventPackage";
65
66    /**
67     * Test-only intent used to send a test dialog event package to the IMS framework.
68     */
69    private static final String ACTION_TEST_DIALOG_EVENT_PACKAGE =
70            "com.android.internal.telephony.TestDialogEventPackage";
71
72    private static final String EXTRA_FILENAME = "filename";
73    private static final String EXTRA_STARTPACKAGE = "startPackage";
74    private static final String EXTRA_SENDPACKAGE = "sendPackage";
75    private static final String EXTRA_DIALOGID = "dialogId";
76    private static final String EXTRA_NUMBER = "number";
77    private static final String EXTRA_STATE = "state";
78    private static final String EXTRA_CANPULL = "canPull";
79
80    /**
81     * Test-only intent used to trigger the signalling which occurs when a handover to WIFI fails.
82     */
83    private static final String ACTION_TEST_HANDOVER_FAIL =
84            "com.android.internal.telephony.TestHandoverFail";
85
86    private static List<ImsExternalCallState> mImsExternalCallStates = null;
87
88    private Phone mPhone;
89
90    // The static intent receiver one for all instances and we assume this
91    // is running on the same thread as Dcc.
92    protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
93            @Override
94        public void onReceive(Context context, Intent intent) {
95            String action = intent.getAction();
96            try {
97                if (DBG) log("sIntentReceiver.onReceive: action=" + action);
98                if (action.equals(mPhone.getActionDetached())) {
99                    log("simulate detaching");
100                    mPhone.getServiceStateTracker().mDetachedRegistrants.notifyRegistrants();
101                } else if (action.equals(mPhone.getActionAttached())) {
102                    log("simulate attaching");
103                    mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants();
104                } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) {
105                    log("inject simulated conference event package");
106                    handleTestConferenceEventPackage(context,
107                            intent.getStringExtra(EXTRA_FILENAME));
108                } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) {
109                    log("handle test dialog event package intent");
110                    handleTestDialogEventPackageIntent(intent);
111                } else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) {
112                    log("handle handover fail test intent");
113                    handleHandoverFailedIntent();
114                } else {
115                    if (DBG) log("onReceive: unknown action=" + action);
116                }
117            } catch (BadParcelableException e) {
118                Rlog.w(LOG_TAG, e);
119            }
120        }
121    };
122
123    TelephonyTester(Phone phone) {
124        mPhone = phone;
125
126        if (Build.IS_DEBUGGABLE) {
127            IntentFilter filter = new IntentFilter();
128
129            filter.addAction(mPhone.getActionDetached());
130            log("register for intent action=" + mPhone.getActionDetached());
131
132            filter.addAction(mPhone.getActionAttached());
133            log("register for intent action=" + mPhone.getActionAttached());
134
135            if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
136                log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
137                filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
138                filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE);
139                filter.addAction(ACTION_TEST_HANDOVER_FAIL);
140                mImsExternalCallStates = new ArrayList<ImsExternalCallState>();
141            }
142
143            phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler());
144        }
145    }
146
147    void dispose() {
148        if (Build.IS_DEBUGGABLE) {
149            mPhone.getContext().unregisterReceiver(mIntentReceiver);
150        }
151    }
152
153    private static void log(String s) {
154        Rlog.d(LOG_TAG, s);
155    }
156
157    private void handleHandoverFailedIntent() {
158        // Attempt to get the active IMS call
159        ImsPhone imsPhone = (ImsPhone) mPhone;
160        if (imsPhone == null) {
161            return;
162        }
163
164        ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
165        if (imsPhoneCall == null) {
166            return;
167        }
168
169        ImsCall imsCall = imsPhoneCall.getImsCall();
170        if (imsCall == null) {
171            return;
172        }
173
174        imsCall.getImsCallSessionListenerProxy().callSessionHandoverFailed(imsCall.getCallSession(),
175                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
176                new ImsReasonInfo());
177    }
178
179    /**
180     * Handles request to send a test conference event package to the active Ims call.
181     *
182     * @see com.android.internal.telephony.test.TestConferenceEventPackageParser
183     * @param context The context.
184     * @param fileName The name of the test conference event package file to read.
185     */
186    private void handleTestConferenceEventPackage(Context context, String fileName) {
187        // Attempt to get the active IMS call before parsing the test XML file.
188        ImsPhone imsPhone = (ImsPhone) mPhone;
189        if (imsPhone == null) {
190            return;
191        }
192
193        ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
194        if (imsPhoneCall == null) {
195            return;
196        }
197
198        ImsCall imsCall = imsPhoneCall.getImsCall();
199        if (imsCall == null) {
200            return;
201        }
202
203        File packageFile = new File(context.getFilesDir(), fileName);
204        final FileInputStream is;
205        try {
206            is = new FileInputStream(packageFile);
207        } catch (FileNotFoundException ex) {
208            log("Test conference event package file not found: " + packageFile.getAbsolutePath());
209            return;
210        }
211
212        TestConferenceEventPackageParser parser = new TestConferenceEventPackageParser(is);
213        ImsConferenceState imsConferenceState = parser.parse();
214        if (imsConferenceState == null) {
215            return;
216        }
217
218        imsCall.conferenceStateUpdated(imsConferenceState);
219    }
220
221    /**
222     * Handles intents containing test dialog event package data.
223     *
224     * @param intent
225     */
226    private void handleTestDialogEventPackageIntent(Intent intent) {
227        ImsPhone imsPhone = (ImsPhone) mPhone;
228        if (imsPhone == null) {
229            return;
230        }
231        ImsExternalCallTracker externalCallTracker = imsPhone.getExternalCallTracker();
232        if (externalCallTracker == null) {
233            return;
234        }
235
236        if (intent.hasExtra(EXTRA_STARTPACKAGE)) {
237            mImsExternalCallStates.clear();
238        } else if (intent.hasExtra(EXTRA_SENDPACKAGE)) {
239            externalCallTracker.refreshExternalCallState(mImsExternalCallStates);
240            mImsExternalCallStates.clear();
241        } else if (intent.hasExtra(EXTRA_DIALOGID)) {
242            ImsExternalCallState state = new ImsExternalCallState(
243                    intent.getIntExtra(EXTRA_DIALOGID, 0),
244                    Uri.parse(intent.getStringExtra(EXTRA_NUMBER)),
245                    intent.getBooleanExtra(EXTRA_CANPULL, true),
246                    intent.getIntExtra(EXTRA_STATE,
247                            ImsExternalCallState.CALL_STATE_CONFIRMED),
248                    ImsCallProfile.CALL_TYPE_VOICE,
249                    false /* isHeld */
250                    );
251            mImsExternalCallStates.add(state);
252        }
253    }
254}
255