diff options
Diffstat (limited to 'tests')
36 files changed, 11127 insertions, 0 deletions
diff --git a/tests/telephonymockriltests/Android.mk b/tests/telephonymockriltests/Android.mk new file mode 100644 index 0000000..9731d0d --- /dev/null +++ b/tests/telephonymockriltests/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_STATIC_JAVA_LIBRARIES := mockrilcontroller + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := TelephonyMockRilTests + +include $(BUILD_PACKAGE) diff --git a/tests/telephonymockriltests/AndroidManifest.xml b/tests/telephonymockriltests/AndroidManifest.xml new file mode 100644 index 0000000..63f44a2 --- /dev/null +++ b/tests/telephonymockriltests/AndroidManifest.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.telephonymockriltests"> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:label="TelephonyMockRilTest" + android:name="TelephonyMockRilTest"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> + + <instrumentation android:name=".TelephonyMockTestRunner" + android:targetPackage="com.android.telephonymockriltests" + android:label="Test runner for Telephony Tests Using Mock RIL" + /> + + <uses-permission android:name="android.permission.READ_PHONE_STATE" /> + <uses-permission android:name="android.permission.INTERNET" /> + +</manifest> diff --git a/tests/telephonymockriltests/src/com/android/telephonymockriltests/TelephonyMockTestRunner.java b/tests/telephonymockriltests/src/com/android/telephonymockriltests/TelephonyMockTestRunner.java new file mode 100644 index 0000000..78ee738 --- /dev/null +++ b/tests/telephonymockriltests/src/com/android/telephonymockriltests/TelephonyMockTestRunner.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.telephonymockriltests; + +import android.os.Bundle; +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; +import com.android.internal.telephony.mockril.MockRilController; +import android.util.Log; + +import com.android.telephonymockriltests.functional.SimpleTestUsingMockRil; + +import java.io.IOException; +import junit.framework.TestSuite; +import junit.framework.TestCase; + +/** + * Test runner for telephony tests that using Mock RIL + * + */ +public class TelephonyMockTestRunner extends InstrumentationTestRunner { + private static final String TAG="TelephonyMockTestRunner"; + public MockRilController mController; + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(SimpleTestUsingMockRil.class); + return suite; + } + + @Override + public void onCreate(Bundle icicle) { + try { + mController = new MockRilController(); + } catch (IOException e) { + e.printStackTrace(); + TestCase.assertTrue("Create Mock RIl Controller failed", false); + } + TestCase.assertNotNull(mController); + super.onCreate(icicle); + } + + @Override + public void finish(int resultCode, Bundle results) { + if (mController != null) + mController.closeChannel(); + super.finish(resultCode, results); + } +} diff --git a/tests/telephonymockriltests/src/com/android/telephonymockriltests/functional/SimpleTestUsingMockRil.java b/tests/telephonymockriltests/src/com/android/telephonymockriltests/functional/SimpleTestUsingMockRil.java new file mode 100644 index 0000000..3ea1cf2 --- /dev/null +++ b/tests/telephonymockriltests/src/com/android/telephonymockriltests/functional/SimpleTestUsingMockRil.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.telephonymockriltests.functional; + +import com.android.internal.telephony.mockril.MockRilController; +import android.test.InstrumentationTestCase; +import android.util.Log; + +import com.android.telephonymockriltests.TelephonyMockTestRunner; + +/** + * A simple test that using Mock RIL Controller + */ +public class SimpleTestUsingMockRil extends InstrumentationTestCase { + private static final String TAG = "SimpleTestUsingMockRil"; + private MockRilController mMockRilCtrl = null; + private TelephonyMockTestRunner mRunner; + + @Override + public void setUp() throws Exception { + super.setUp(); + mRunner = (TelephonyMockTestRunner)getInstrumentation(); + mMockRilCtrl = mRunner.mController; + assertNotNull(mMockRilCtrl); + } + + /** + * Get the current radio state of RIL + */ + public void testGetRadioState() { + int state = mMockRilCtrl.getRadioState(); + Log.v(TAG, "testGetRadioState: " + state); + assertTrue(state >= 0 && state <= 9); + } + + /** + * Set the current radio state of RIL + * and verify the radio state is set correctly + */ + public void testSetRadioState() { + for (int state = 0; state <= 9; state++) { + Log.v(TAG, "set radio state to be " + state); + assertTrue("set radio state: " + state + " failed.", + mMockRilCtrl.setRadioState(state)); + } + assertFalse("use an invalid radio state", mMockRilCtrl.setRadioState(-1)); + assertFalse("the radio state doesn't exist", mMockRilCtrl.setRadioState(10)); + } +} diff --git a/tests/telephonytests/Android.mk b/tests/telephonytests/Android.mk new file mode 100644 index 0000000..197cedf --- /dev/null +++ b/tests/telephonytests/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_STATIC_JAVA_LIBRARIES := librilproto-java + +LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common + +LOCAL_PACKAGE_NAME := FrameworksTelephonyTests + +include $(BUILD_PACKAGE) diff --git a/tests/telephonytests/AndroidManifest.xml b/tests/telephonytests/AndroidManifest.xml new file mode 100644 index 0000000..ba1d957 --- /dev/null +++ b/tests/telephonytests/AndroidManifest.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.frameworks.telephonytests"> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:label="TelephonyTest" + android:name="TelephonyTest"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.frameworks.telephonytests" + android:label="Frameworks Telephony Tests"> + </instrumentation> + + <instrumentation android:name=".TelephonyMockRilTestRunner" + android:targetPackage="com.android.frameworks.telephonytests" + android:label="Test Runner for Mock Ril Tests" + /> + + <uses-permission android:name="android.permission.READ_PHONE_STATE" /> + <uses-permission android:name="android.permission.INTERNET" /> + +</manifest> diff --git a/tests/telephonytests/src/com/android/frameworks/telephonytests/TelephonyMockRilTestRunner.java b/tests/telephonytests/src/com/android/frameworks/telephonytests/TelephonyMockRilTestRunner.java new file mode 100644 index 0000000..9192f57 --- /dev/null +++ b/tests/telephonytests/src/com/android/frameworks/telephonytests/TelephonyMockRilTestRunner.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.frameworks.telephonytests; + +import android.os.Bundle; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; +import android.util.Log; + +import java.io.IOException; + +import com.android.internal.telephony.RilChannel; +import com.android.internal.telephony.mockril.MockRilTest; + +import junit.framework.TestSuite; + +public class TelephonyMockRilTestRunner extends InstrumentationTestRunner { + + public RilChannel mMockRilChannel; + + @Override + public TestSuite getAllTests() { + log("getAllTests E"); + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(MockRilTest.class); + log("getAllTests X"); + return suite; + } + + @Override + public ClassLoader getLoader() { + log("getLoader EX"); + return TelephonyMockRilTestRunner.class.getClassLoader(); + } + + @Override + public void onCreate(Bundle icicle) { + log("onCreate E"); + try { + mMockRilChannel = RilChannel.makeRilChannel(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + log("onCreate X"); + + super.onCreate(icicle); + } + + @Override + public void onDestroy() { + // I've not seen this called + log("onDestroy EX"); + super.onDestroy(); + } + + @Override + public void onStart() { + // Called when the instrumentation thread is started. + // At the moment we don't need the thread so return + // which will shut down this unused thread. + log("onStart EX"); + super.onStart(); + } + + @Override + public void finish(int resultCode, Bundle results) { + // Called when complete so I ask the mMockRilChannel to quit. + log("finish E"); + mMockRilChannel.close(); + log("finish X"); + super.finish(resultCode, results); + } + + private void log(String s) { + Log.e("TelephonyMockRilTestRunner", s); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java b/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java new file mode 100644 index 0000000..81727e4 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class ATResponseParserTest extends TestCase { + @SmallTest + public void testBasic() throws Exception { + ATResponseParser p = new ATResponseParser("+CREG: 0"); + + assertEquals(0, p.nextInt()); + + assertFalse(p.hasMore()); + + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0,1"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CREG: 0, 1"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CREG: 0, 1,"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + // this seems odd but is probably OK + assertFalse(p.hasMore()); + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0, 1 "); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("0, 1 "); + // no prefix -> exception + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0, 1, 5"); + assertFalse(p.nextBoolean()); + assertTrue(p.nextBoolean()); + try { + // is this over-constraining? + p.nextBoolean(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212\",145"); + + assertEquals(1, p.nextInt()); + assertFalse(p.nextBoolean()); + assertEquals(2, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals("+18005551212", p.nextString()); + assertEquals(145, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212,145"); + + assertEquals(1, p.nextInt()); + assertFalse(p.nextBoolean()); + assertEquals(2, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals(0, p.nextInt()); + try { + p.nextString(); + fail("expected ex"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+FOO: \"\""); + assertEquals("", p.nextString()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java b/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java new file mode 100644 index 0000000..8a4a285 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * {@hide} + */ +public class AdnRecordTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + AdnRecord adn; + + // + // Typical record + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C07918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("+18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Empty records, empty strings + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + + assertEquals("", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertTrue(adn.isEmpty()); + + // + // Record too short + // + adn = new AdnRecord(IccUtils.hexStringToBytes( "FF")); + + assertEquals("", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertTrue(adn.isEmpty()); + + // + // TOA = 0xff ("control string") + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C07FF8150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // TOA = 0x81 (unknown) + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C07818150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is too long + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C0F918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is zero (invalid) + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C00918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is 2, first number byte is FF, TOA is international + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C0291FF50367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is 2, first number digit is valid, TOA is international + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C0291F150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("+1", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record + // + adn = new AdnRecord( + IccUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(IccUtils.hexStringToBytes("0206092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678901234567890", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record with an invalid extension + // + adn = new AdnRecord( + IccUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(IccUtils.hexStringToBytes("0106092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record with an invalid extension + // + adn = new AdnRecord( + IccUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(IccUtils.hexStringToBytes("020B092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + } +} + + diff --git a/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java new file mode 100755 index 0000000..ac8c4c1 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import junit.framework.TestCase; + +import android.test.suitebuilder.annotation.SmallTest; + +public class ApnSettingTest extends TestCase { + + public static final String[] TYPES = {"default", "*"}; + + public static void assertApnSettingEqual(ApnSetting a1, ApnSetting a2) { + assertEquals(a1.carrier, a2.carrier); + assertEquals(a1.apn, a2.apn); + assertEquals(a1.proxy, a2.proxy); + assertEquals(a1.port, a2.port); + assertEquals(a1.mmsc, a2.mmsc); + assertEquals(a1.mmsProxy, a2.mmsProxy); + assertEquals(a1.mmsPort, a2.mmsPort); + assertEquals(a1.user, a2.user); + assertEquals(a1.password, a2.password); + assertEquals(a1.authType, a2.authType); + assertEquals(a1.id, a2.id); + assertEquals(a1.numeric, a2.numeric); + assertEquals(a1.protocol, a2.protocol); + assertEquals(a1.roamingProtocol, a2.roamingProtocol); + assertEquals(a1.types.length, a2.types.length); + int i; + for (i = 0; i < a1.types.length; i++) { + assertEquals(a1.types[i], a2.types[i]); + } + assertEquals(a1.carrierEnabled, a2.carrierEnabled); + assertEquals(a1.bearer, a2.bearer); + } + + @SmallTest + public void testFromString() throws Exception { + String[] dunTypes = {"DUN"}; + String[] mmsTypes = {"mms", "*"}; + + ApnSetting expected_apn; + String testString; + + // A real-world v1 example string. + testString = "Vodafone IT,web.omnitel.it,,,,,,,,,222,10,,DUN"; + expected_apn = new ApnSetting( + -1, "22210", "Vodafone IT", "web.omnitel.it", "", "", + "", "", "", "", "", 0, dunTypes, "IP", "IP",true,0); + assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString)); + + // A v2 string. + testString = "[ApnSettingV2] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP,true,14"; + expected_apn = new ApnSetting( + -1, "12345", "Name", "apn", "", "", + "", "", "", "", "", 0, mmsTypes, "IPV6", "IP",true,14); + assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString)); + + // A v2 string with spaces. + testString = "[ApnSettingV2] Name,apn, ,,,,,,,,123,45,,mms|*,IPV4V6, IP,true,14"; + expected_apn = new ApnSetting( + -1, "12345", "Name", "apn", "", "", + "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP",true,14); + assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString)); + + // Return null if insufficient fields given. + testString = "[ApnSettingV2] Name,apn,,,,,,,,,123, 45,,mms|*"; + assertEquals(null, ApnSetting.fromString(testString)); + + testString = "Name,apn,,,,,,,,,123, 45,"; + assertEquals(null, ApnSetting.fromString(testString)); + + // Parse (incorrect) V2 format without the tag as V1. + testString = "Name,apn,,,,,,,,,123, 45,,mms|*,IPV6,true,14"; + String[] incorrectTypes = {"mms|*", "IPV6"}; + expected_apn = new ApnSetting( + -1, "12345", "Name", "apn", "", "", + "", "", "", "", "", 0, incorrectTypes, "IP", "IP",true,14); + assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString)); + } + + + @SmallTest + public void testToString() throws Exception { + String[] types = {"default", "*"}; + ApnSetting apn = new ApnSetting( + 99, "12345", "Name", "apn", "proxy", "port", + "mmsc", "mmsproxy", "mmsport", "user", "password", 0, + types, "IPV4V6", "IP", true, 14); + String expected = "[ApnSettingV2] Name, 99, 12345, apn, proxy, " + + "mmsc, mmsproxy, mmsport, port, 0, default | *, " + + "IPV4V6, IP, true, 14"; + assertEquals(expected, apn.toString()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallerInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallerInfoTest.java new file mode 100644 index 0000000..1e5dafb --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/CallerInfoTest.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import com.android.internal.telephony.CallerInfo; +import com.android.internal.telephony.CallerInfoAsyncQuery; +import android.util.Log; +import android.os.Looper; +import android.test.ActivityInstrumentationTestCase; +import android.util.StringBuilderPrinter; + +/* + * Check the CallerInfo utility class works as expected. + * + */ + +public class CallerInfoTest extends AndroidTestCase { + private CallerInfo mInfo; + private Context mContext; + + private static final String kEmergencyNumber = "Emergency Number"; + private static final int kToken = 0xdeadbeef; + private static final String TAG = "CallerInfoUnitTest"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContext = new MockContext(); + mInfo = new CallerInfo(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Checks the caller info instance is flagged as an emergency if + * the number is an emergency one. There is no test for the + * contact based constructors because emergency number are not in + * the contact DB. + */ + @SmallTest + public void testEmergencyIsProperlySet() throws Exception { + assertFalse(mInfo.isEmergencyNumber()); + + mInfo = CallerInfo.getCallerInfo(mContext, "911"); + assertIsValidEmergencyCallerInfo(); + + mInfo = CallerInfo.getCallerInfo(mContext, "tel:911"); + assertIsValidEmergencyCallerInfo(); + + + // This one hits the content resolver. + mInfo = CallerInfo.getCallerInfo(mContext, "18001234567"); + assertFalse(mInfo.isEmergencyNumber()); + } + + /** + * Same as testEmergencyIsProperlySet but uses the async query api. + */ + @SmallTest + public void testEmergencyIsProperlySetUsingAsyncQuery() throws Exception { + QueryRunner query; + + query = new QueryRunner("911"); + query.runAndCheckCompletion(); + assertIsValidEmergencyCallerInfo(); + + query = new QueryRunner("tel:911"); + query.runAndCheckCompletion(); + assertIsValidEmergencyCallerInfo(); + + query = new QueryRunner("18001234567"); + query.runAndCheckCompletion(); + assertFalse(mInfo.isEmergencyNumber()); + } + + /** + * For emergency caller info, phoneNumber should be set to the + * string emergency_call_dialog_number_for_display and the + * photoResource should be set to the picture_emergency drawable. + */ + @SmallTest + public void testEmergencyNumberAndPhotoAreSet() throws Exception { + mInfo = CallerInfo.getCallerInfo(mContext, "911"); + + assertIsValidEmergencyCallerInfo(); + } + + // TODO: Add more tests: + /** + * Check if the voice mail number cannot be retrieved that the + * original phone number is preserved. + */ + /** + * Check the markAs* methods work. + */ + + + // + // Helpers + // + + // Partial implementation of MockResources. + public class MockResources extends android.test.mock.MockResources + { + @Override + public String getString(int resId) throws Resources.NotFoundException { + switch (resId) { + case com.android.internal.R.string.emergency_call_dialog_number_for_display: + return kEmergencyNumber; + default: + throw new UnsupportedOperationException("Missing handling for resid " + resId); + } + } + } + + // Partial implementation of MockContext. + public class MockContext extends android.test.mock.MockContext { + private ContentResolver mResolver; + private Resources mResources; + + public MockContext() { + mResolver = new android.test.mock.MockContentResolver(); + mResources = new MockResources(); + } + + @Override + public ContentResolver getContentResolver() { + return mResolver; + } + + @Override + public Resources getResources() { + return mResources; + } + } + + /** + * Class to run a CallerInfoAsyncQuery in a separate thread, with + * its own Looper. We cannot use the main Looper because on the + * 1st quit the thread is maked dead, ie no further test can use + * it. Also there is not way to inject a Looper instance in the + * query, so we have to use a thread with its own looper. + */ + private class QueryRunner extends Thread + implements CallerInfoAsyncQuery.OnQueryCompleteListener { + private Looper mLooper; + private String mNumber; + private boolean mAsyncCompleted; + + public QueryRunner(String number) { + super(); + mNumber = number; + } + + // Run the query in the thread, wait for completion. + public void runAndCheckCompletion() throws InterruptedException { + start(); + join(); + assertTrue(mAsyncCompleted); + } + + @Override + public void run() { + Looper.prepare(); + mLooper = Looper.myLooper(); + mAsyncCompleted = false; + // The query will pick the thread local looper we've just prepared. + CallerInfoAsyncQuery.startQuery(kToken, mContext, mNumber, this, null); + mLooper.loop(); + } + + // Quit the Looper on the 1st callback + // (EVENT_EMERGENCY_NUMBER). There is another message + // (EVENT_END_OF_QUEUE) that will never be delivered because + // the test has exited. The corresponding stack trace + // "Handler{xxxxx} sending message to a Handler on a dead + // thread" can be ignored. + public void onQueryComplete(int token, Object cookie, CallerInfo info) { + mAsyncCompleted = true; + mInfo = info; + mLooper.quit(); + } + } + + /** + * Fail if mInfo does not contain a valid emergency CallerInfo instance. + */ + private void assertIsValidEmergencyCallerInfo() throws Exception { + assertTrue(mInfo.isEmergencyNumber()); + + // For emergency caller info, phoneNumber should be set to the + // string emergency_call_dialog_number_for_display and the + // photoResource should be set to the picture_emergency drawable. + assertEquals(kEmergencyNumber, mInfo.phoneNumber); + assertEquals(com.android.internal.R.drawable.picture_emergency, mInfo.photoResource); + + // The name should be null + assertNull(mInfo.name); + assertEquals(0, mInfo.namePresentation); + assertNull(mInfo.cnapName); + assertEquals(0, mInfo.numberPresentation); + + assertFalse(mInfo.contactExists); + assertEquals(0, mInfo.person_id); + assertFalse(mInfo.needUpdate); + assertNull(mInfo.contactRefUri); + + assertNull(mInfo.phoneLabel); + assertEquals(0, mInfo.numberType); + assertNull(mInfo.numberLabel); + + assertNull(mInfo.contactRingtoneUri); + assertFalse(mInfo.shouldSendToVoicemail); + + assertNull(mInfo.cachedPhoto); + assertFalse(mInfo.isCachedPhotoCurrent); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java new file mode 100644 index 0000000..f9dc3a9 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.GsmAlphabet; + +import junit.framework.TestCase; + +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; + +public class GsmAlphabetTest extends TestCase { + + private static final String sGsmExtendedChars = "{|}\\[~]\f\u20ac"; + + @SmallTest + public void test7bitWithHeader() throws Exception { + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 1; + concatRef.seqNumber = 2; + concatRef.msgCount = 2; + concatRef.isEightBits = true; + SmsHeader header = new SmsHeader(); + header.concatRef = concatRef; + + String message = "aaaaaaaaaabbbbbbbbbbcccccccccc"; + byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, + SmsHeader.toByteArray(header), 0, 0); + int septetCount = GsmAlphabet.countGsmSeptetsUsingTables(message, true, 0, 0); + String parsedMessage = GsmAlphabet.gsm7BitPackedToString( + userData, SmsHeader.toByteArray(header).length+2, septetCount, 1, 0, 0); + assertEquals(message, parsedMessage); + } + + // TODO: This method should *really* be a series of individual test methods. + // However, it's a SmallTest because it executes quickly. + @SmallTest + public void testBasic() throws Exception { + // '@' maps to char 0 + assertEquals(0, GsmAlphabet.charToGsm('@')); + + // `a (a with grave accent) maps to last GSM character + assertEquals(0x7f, GsmAlphabet.charToGsm('\u00e0')); + + // + // These are the extended chars + // They should all return GsmAlphabet.GSM_EXTENDED_ESCAPE + // + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, + GsmAlphabet.charToGsm(sGsmExtendedChars.charAt(i))); + + } + + // euro symbol + assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, + GsmAlphabet.charToGsm('\u20ac')); + + // An unmappable char (the 'cent' char) maps to a space + assertEquals(GsmAlphabet.charToGsm(' '), + GsmAlphabet.charToGsm('\u00a2')); + + // unmappable = space = 1 septet + assertEquals(1, GsmAlphabet.countGsmSeptets('\u00a2')); + + // + // Test extended table + // + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + assertEquals(sGsmExtendedChars.charAt(i), + GsmAlphabet.gsmExtendedToChar( + GsmAlphabet.charToGsmExtended(sGsmExtendedChars.charAt(i)))); + + } + + // Unmappable extended char + assertEquals(GsmAlphabet.charToGsm(' '), + GsmAlphabet.charToGsmExtended('@')); + + // + // gsmToChar() + // + + assertEquals('@', GsmAlphabet.gsmToChar(0)); + + // `a (a with grave accent) maps to last GSM character + assertEquals('\u00e0', GsmAlphabet.gsmToChar(0x7f)); + + assertEquals('\uffff', + GsmAlphabet.gsmToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE)); + + // Out-of-range/unmappable value + assertEquals(' ', GsmAlphabet.gsmToChar(0x80)); + + // + // gsmExtendedToChar() + // + + assertEquals('{', GsmAlphabet.gsmExtendedToChar(0x28)); + + // No double-escapes + assertEquals(' ', GsmAlphabet.gsmExtendedToChar( + GsmAlphabet.GSM_EXTENDED_ESCAPE)); + + // Reserved for extension to extension table (mapped to space) + assertEquals(' ', GsmAlphabet.gsmExtendedToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE)); + + // Unmappable (mapped to character in default or national locking shift table) + assertEquals('@', GsmAlphabet.gsmExtendedToChar(0)); + assertEquals('\u00e0', GsmAlphabet.gsmExtendedToChar(0x7f)); + + // + // stringTo7BitPacked, gsm7BitPackedToString + // + + byte[] packed; + StringBuilder testString = new StringBuilder(300); + + // Check all alignment cases + for (int i = 0; i < 9; i++, testString.append('@')) { + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + } + + // Check full non-extended alphabet + for (int i = 0; i < 0x80; i++) { + char c; + + if (i == GsmAlphabet.GSM_EXTENDED_ESCAPE) { + continue; + } + + c = GsmAlphabet.gsmToChar(i); + testString.append(c); + + // These are all non-extended chars, so it should be + // one septet per char + assertEquals(1, GsmAlphabet.countGsmSeptets(c)); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // Test extended chars too + + testString.append(sGsmExtendedChars); + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + // These are all extended chars, so it should be + // two septets per char + assertEquals(2, GsmAlphabet.countGsmSeptets(sGsmExtendedChars.charAt(i))); + + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // stringTo7BitPacked handles up to 255 septets + + testString.setLength(0); + for (int i = 0; i < 255; i++) { + testString.append('@'); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // > 255 septets throws runtime exception + testString.append('@'); + + try { + GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); + fail("expected exception"); + } catch (EncodeException ex) { + // exception expected + } + + // Try 254 septets with 127 extended chars + + testString.setLength(0); + for (int i = 0; i < (255 / 2); i++) { + testString.append('{'); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // > 255 septets throws runtime exception + testString.append('{'); + + try { + GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); + fail("expected exception"); + } catch (EncodeException ex) { + // exception expected + } + + // Reserved for extension to extension table (mapped to space) + packed = new byte[]{(byte)(0x1b | 0x80), 0x1b >> 1}; + assertEquals(" ", GsmAlphabet.gsm7BitPackedToString(packed, 0, 2)); + + // Unmappable (mapped to character in default alphabet table) + packed[0] = 0x1b; + packed[1] = 0x00; + assertEquals("@", GsmAlphabet.gsm7BitPackedToString(packed, 0, 2)); + packed[0] = (byte)(0x1b | 0x80); + packed[1] = (byte)(0x7f >> 1); + assertEquals("\u00e0", GsmAlphabet.gsm7BitPackedToString(packed, 0, 2)); + + // + // 8 bit unpacked format + // + // Note: we compare hex strings here + // because Assert doesn't have array comparisons + + byte unpacked[]; + + unpacked = IccUtils.hexStringToBytes("566F696365204D61696C"); + assertEquals("Voice Mail", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + assertEquals(IccUtils.bytesToHexString(unpacked), + IccUtils.bytesToHexString( + GsmAlphabet.stringToGsm8BitPacked("Voice Mail"))); + + unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars); + // two bytes for every extended char + assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); + assertEquals(sGsmExtendedChars, + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // should be two bytes per extended char + assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); + + // Test truncation of unaligned extended chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField(sGsmExtendedChars, unpacked, + 0, unpacked.length); + + // Should be one extended char and an 0xff at the end + + assertEquals(0xff, 0xff & unpacked[2]); + assertEquals(sGsmExtendedChars.substring(0, 1), + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test truncation of normal chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, + 0, unpacked.length); + + assertEquals("abc", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test truncation of mixed normal and extended chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("a{cd", unpacked, + 0, unpacked.length); + + assertEquals("a{", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test padding after normal char + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("a", unpacked, + 0, unpacked.length); + + assertEquals("a", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + assertEquals(0xff, 0xff & unpacked[1]); + assertEquals(0xff, 0xff & unpacked[2]); + + // Test malformed input -- escape char followed by end of field + unpacked[0] = 0; + unpacked[1] = 0; + unpacked[2] = GsmAlphabet.GSM_EXTENDED_ESCAPE; + + assertEquals("@@", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // non-zero offset + assertEquals("@", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + + // test non-zero offset + unpacked[0] = 0; + GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, + 1, unpacked.length - 1); + + + assertEquals(0, unpacked[0]); + + assertEquals("ab", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + + // test non-zero offset with truncated extended char + unpacked[0] = 0; + + GsmAlphabet.stringToGsm8BitUnpackedField("a{", unpacked, + 1, unpacked.length - 1); + + assertEquals(0, unpacked[0]); + + assertEquals("a", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + + // Reserved for extension to extension table (mapped to space) + unpacked[0] = 0x1b; + unpacked[1] = 0x1b; + assertEquals(" ", GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, 2)); + + // Unmappable (mapped to character in default or national locking shift table) + unpacked[1] = 0x00; + assertEquals("@", GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, 2)); + unpacked[1] = 0x7f; + assertEquals("\u00e0", GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, 2)); + } + + @SmallTest + public void testGsm8BitUpackedWithEuckr() throws Exception { + // Some feature phones in Korea store contacts as euc-kr. + // Test this situations. + byte unpacked[]; + + // Test general alphabet strings. + unpacked = IccUtils.hexStringToBytes("61626320646566FF"); + assertEquals("abc def", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr")); + + // Test korean strings. + unpacked = IccUtils.hexStringToBytes("C5D7BDBAC6AEFF"); + assertEquals("\uD14C\uC2A4\uD2B8", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr")); + + // Test gsm Extented Characters. + unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars); + assertEquals(sGsmExtendedChars, + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr")); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java new file mode 100644 index 0000000..f2e5da1 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.telephony.TelephonyManager; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.util.HexDump; + +import java.util.ArrayList; + +public class GsmSmsTest extends AndroidTestCase { + + @SmallTest + public void testAddressing() throws Exception { + String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("Test", sms.getMessageBody()); + + pdu = "07914151551512f2040B916105551511f100036060924180008A0DA" + + "8695DAC2E8FE9296A794E07"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("(Subject)Test", sms.getMessageBody()); + } + + @SmallTest + public void testUdh() throws Exception { + String pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F" + + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D" + + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426" + + "66C414141414D7741414236514141414141008D908918802B3135313232393737" + + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703" + + "A2F2F36"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + SmsHeader header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 42); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 1); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + + pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F" + + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141" + + "42666C414141414D774141423651414141414100"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 42); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 2); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @SmallTest + public void testUcs2() throws Exception { + String pdu = "07912160130300F4040B914151245584F600087010807121352B1021220" + + "0A900AE00680065006C006C006F"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("\u2122\u00a9\u00aehello", sms.getMessageBody()); + } + + @SmallTest + public void testMultipart() throws Exception { + /* + * Multi-part text SMS with septet data. + */ + String pdu = "07916163838408F6440B816105224431F700007060217175830AA0050003" + + "00020162B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals(sms.getMessageBody(), + "1111111111111111111111111111111111111111" + + "1111111111111111111111111111111111111111" + + "1111111111111111111111111111111111111111" + + "111111111111111111111111111111111"); + + pdu = "07916163838408F6440B816105224431F700007060217185000A23050003" + + "00020262B1582C168BC96432994C2693C96432994C2693C96432990C"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("1111111222222222222222222222", sms.getMessageBody()); + } + + @SmallTest + public void testCPHSVoiceMail() throws Exception { + // "set MWI flag" + + String pdu = "07912160130310F20404D0110041006060627171118A0120"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isReplace()); + assertEquals("_@", sms.getOriginatingAddress()); + assertEquals(" ", sms.getMessageBody()); + assertTrue(sms.isMWISetMessage()); + + // "clear mwi flag" + + pdu = "07912160130310F20404D0100041006021924193352B0120"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWIClearMessage()); + + // "clear MWI flag" + + pdu = "07912160130310F20404D0100041006060627161058A0120"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isReplace()); + assertEquals("\u0394@", sms.getOriginatingAddress()); + assertEquals(" ", sms.getMessageBody()); + assertTrue(sms.isMWIClearMessage()); + } + + @SmallTest + public void testCingularVoiceMail() throws Exception { + // "set MWI flag" + + String pdu = "07912180958750F84401800500C87020026195702B06040102000200"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWISetMessage()); + assertTrue(sms.isMwiDontStore()); + + // "clear mwi flag" + + pdu = "07912180958750F84401800500C07020027160112B06040102000000"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWIClearMessage()); + assertTrue(sms.isMwiDontStore()); + } + + @SmallTest + public void testEmailGateway() throws Exception { + String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" + + "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertTrue(sms.isEmail()); + assertEquals("foo@example.com", sms.getEmailFrom()); + assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); + // As of https://android-git.corp.google.com/g/#change,9324 + // getPseudoSubject will always be empty, and any subject is not extracted. + assertEquals("", sms.getPseudoSubject()); + assertEquals("test subject /test body", sms.getDisplayMessageBody()); + assertEquals("test subject /test body", sms.getEmailBody()); + + // email gateway sms test, including gsm extended character set. + pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" + + "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertTrue(sms.isEmail()); + assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); + assertEquals("foo@example.com", sms.getEmailFrom()); + assertEquals("{ testBody[^~\\] }", sms.getDisplayMessageBody()); + assertEquals("{ testBody[^~\\] }", sms.getEmailBody()); + } + + @SmallTest + public void testExtendedCharacterTable() throws Exception { + String pdu = "07914151551512f2040B916105551511f100006080615131728A44D4F29C0E2" + + "AE3E96537B94C068DD16179784C2FCB41F4B0985D06B958ADD00FB0E94536AF9749" + + "74DA6D281BA00E95E26D509B946FC3DBF87A25D56A04"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("Test extended character table .,-!?@~_\\/&\"';^|:()<{}>[]=%*+#", + sms.getMessageBody()); + } + + // GSM 7 bit tables in String form, Escape (0x1B) replaced with '@' + private static final String[] sBasicTables = { + // GSM 7 bit default alphabet + "@\u00a3$\u00a5\u00e8\u00e9\u00f9\u00ec\u00f2\u00c7\n\u00d8\u00f8\r\u00c5\u00e5\u0394_" + + "\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e@\u00c6\u00e6\u00df\u00c9" + + " !\"#\u00a4%&'()*+,-./0123456789:;<=>?\u00a1ABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c4\u00d6" + + "\u00d1\u00dc\u00a7\u00bfabcdefghijklmnopqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0", + + // Turkish locking shift table + "@\u00a3$\u00a5\u20ac\u00e9\u00f9\u0131\u00f2\u00c7\n\u011e\u011f\r\u00c5\u00e5\u0394_" + + "\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e@\u015e\u015f\u00df\u00c9" + + " !\"#\u00a4%&'()*+,-./0123456789:;<=>?\u0130ABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c4\u00d6" + + "\u00d1\u00dc\u00a7\u00e7abcdefghijklmnopqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0", + + // no locking shift table defined for Spanish + "", + + // Portuguese locking shift table + "@\u00a3$\u00a5\u00ea\u00e9\u00fa\u00ed\u00f3\u00e7\n\u00d4\u00f4\r\u00c1\u00e1\u0394_" + + "\u00aa\u00c7\u00c0\u221e^\\\u20ac\u00d3|@\u00c2\u00e2\u00ca\u00c9 !\"#\u00ba%&'()" + + "*+,-./0123456789:;<=>?\u00cdABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c3\u00d5\u00da\u00dc" + + "\u00a7~abcdefghijklmnopqrstuvwxyz\u00e3\u00f5`\u00fc\u00e0" + }; + + @SmallTest + public void testFragmentText() throws Exception { + boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() == + TelephonyManager.PHONE_TYPE_GSM); + + // Valid 160 character 7-bit text. + String text = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890"; + GsmAlphabet.TextEncodingDetails ted = SmsMessage.calculateLength(text, false); + assertEquals(1, ted.msgCount); + assertEquals(160, ted.codeUnitCount); + assertEquals(1, ted.codeUnitSize); + assertEquals(0, ted.languageTable); + assertEquals(0, ted.languageShiftTable); + if (isGsmPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); + assertEquals(1, fragments.size()); + } + + // Valid 161 character 7-bit text. + text = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901"; + ted = SmsMessage.calculateLength(text, false); + assertEquals(2, ted.msgCount); + assertEquals(161, ted.codeUnitCount); + assertEquals(1, ted.codeUnitSize); + assertEquals(0, ted.languageTable); + assertEquals(0, ted.languageShiftTable); + if (isGsmPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); + assertEquals(2, fragments.size()); + assertEquals(text, fragments.get(0) + fragments.get(1)); + assertEquals(153, fragments.get(0).length()); + assertEquals(8, fragments.get(1).length()); + } + } + + @SmallTest + public void testFragmentTurkishText() throws Exception { + boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() == + TelephonyManager.PHONE_TYPE_GSM); + + int[] oldTables = GsmAlphabet.getEnabledSingleShiftTables(); + int[] turkishTable = { 1 }; + GsmAlphabet.setEnabledSingleShiftTables(turkishTable); + + // Valid 77 character text with Turkish characters. + String text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" + + "ĞŞİğşıĞŞİğşıĞŞİğş"; + GsmAlphabet.TextEncodingDetails ted = SmsMessage.calculateLength(text, false); + assertEquals(1, ted.msgCount); + assertEquals(154, ted.codeUnitCount); + assertEquals(1, ted.codeUnitSize); + assertEquals(0, ted.languageTable); + assertEquals(1, ted.languageShiftTable); + if (isGsmPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); + assertEquals(1, fragments.size()); + assertEquals(text, fragments.get(0)); + assertEquals(77, fragments.get(0).length()); + } + + // Valid 78 character text with Turkish characters. + text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" + + "ĞŞİğşıĞŞİğşıĞŞİğşı"; + ted = SmsMessage.calculateLength(text, false); + assertEquals(2, ted.msgCount); + assertEquals(156, ted.codeUnitCount); + assertEquals(1, ted.codeUnitSize); + assertEquals(0, ted.languageTable); + assertEquals(1, ted.languageShiftTable); + if (isGsmPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); + assertEquals(2, fragments.size()); + assertEquals(text, fragments.get(0) + fragments.get(1)); + assertEquals(74, fragments.get(0).length()); + assertEquals(4, fragments.get(1).length()); + } + + // Valid 160 character text with Turkish characters. + text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" + + "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğ" + + "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı"; + ted = SmsMessage.calculateLength(text, false); + assertEquals(3, ted.msgCount); + assertEquals(320, ted.codeUnitCount); + assertEquals(1, ted.codeUnitSize); + assertEquals(0, ted.languageTable); + assertEquals(1, ted.languageShiftTable); + if (isGsmPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); + assertEquals(3, fragments.size()); + assertEquals(text, fragments.get(0) + fragments.get(1) + fragments.get(2)); + assertEquals(74, fragments.get(0).length()); + assertEquals(74, fragments.get(1).length()); + assertEquals(12, fragments.get(2).length()); + } + + GsmAlphabet.setEnabledSingleShiftTables(oldTables); + } + + + @SmallTest + public void testDecode() throws Exception { + decodeSingle(0); // default table + decodeSingle(1); // Turkish locking shift table + decodeSingle(3); // Portuguese locking shift table + } + + private void decodeSingle(int language) throws Exception { + byte[] septets = new byte[(7 * 128 + 7) / 8]; + + int bitOffset = 0; + + for (int i = 0; i < 128; i++) { + int v; + if (i == 0x1b) { + // extended escape char + v = 0; + } else { + v = i; + } + + int byteOffset = bitOffset / 8; + int shift = bitOffset % 8; + + septets[byteOffset] |= v << shift; + + if (shift > 1) { + septets[byteOffset + 1] = (byte) (v >> (8 - shift)); + } + + bitOffset += 7; + } + + String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, 128, 0, language, 0); + byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded, language, 0); + + assertEquals(sBasicTables[language], decoded); + + // reEncoded has the count septets byte at the front + assertEquals(septets.length + 1, reEncoded.length); + + for (int i = 0; i < septets.length; i++) { + assertEquals(septets[i], reEncoded[i + 1]); + } + } + + private static final int GSM_ESCAPE_CHARACTER = 0x1b; + + private static final String[] sExtendedTables = { + // GSM 7 bit default alphabet extension table + "\f^{}\\[~]|\u20ac", + + // Turkish single shift extension table + "\f^{}\\[~]|\u011e\u0130\u015e\u00e7\u20ac\u011f\u0131\u015f", + + // Spanish single shift extension table + "\u00e7\f^{}\\[~]|\u00c1\u00cd\u00d3\u00da\u00e1\u20ac\u00ed\u00f3\u00fa", + + // Portuguese single shift extension table + "\u00ea\u00e7\f\u00d4\u00f4\u00c1\u00e1\u03a6\u0393^\u03a9\u03a0\u03a8\u03a3\u0398\u00ca" + + "{}\\[~]|\u00c0\u00cd\u00d3\u00da\u00c3\u00d5\u00c2\u20ac\u00ed\u00f3\u00fa\u00e3" + + "\u00f5\u00e2" + }; + + private static final int[][] sExtendedTableIndexes = { + {0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x65}, + {0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x47, 0x49, 0x53, 0x63, + 0x65, 0x67, 0x69, 0x73}, + {0x09, 0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x49, 0x4f, + 0x55, 0x61, 0x65, 0x69, 0x6f, 0x75}, + {0x05, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1f, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x49, + 0x4f, 0x55, 0x5b, 0x5c, 0x61, 0x65, 0x69, 0x6f, 0x75, 0x7b, 0x7c, 0x7f} + }; + + @SmallTest + public void testDecodeExtended() throws Exception { + for (int language = 0; language < 3; language++) { + int[] tableIndex = sExtendedTableIndexes[language]; + int numSeptets = tableIndex.length * 2; // two septets per extended char + byte[] septets = new byte[(7 * numSeptets + 7) / 8]; + + int bitOffset = 0; + + for (int v : tableIndex) { + // escape character + int byteOffset = bitOffset / 8; + int shift = bitOffset % 8; + + septets[byteOffset] |= GSM_ESCAPE_CHARACTER << shift; + + if (shift > 1) { + septets[byteOffset + 1] = (byte) (GSM_ESCAPE_CHARACTER >> (8 - shift)); + } + + bitOffset += 7; + + // extended table index + byteOffset = bitOffset / 8; + shift = bitOffset % 8; + + septets[byteOffset] |= v << shift; + + if (shift > 1) { + septets[byteOffset + 1] = (byte) (v >> (8 - shift)); + } + + bitOffset += 7; + } + + String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, + 0, language); + byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded, 0, language); + + assertEquals(sExtendedTables[language], decoded); + + // reEncoded has the count septets byte at the front + assertEquals(septets.length + 1, reEncoded.length); + + for (int i = 0; i < septets.length; i++) { + assertEquals(septets[i], reEncoded[i + 1]); + } + } + } + + @SmallTest + public void testDecodeExtendedFallback() throws Exception { + // verify that unmapped characters in extension table fall back to locking shift table + for (int language = 0; language < 3; language++) { + int[] tableIndex = sExtendedTableIndexes[language]; + int numChars = 128 - tableIndex.length; + int numSeptets = numChars * 2; // two septets per extended char + byte[] septets = new byte[(7 * numSeptets + 7) / 8]; + + int tableOffset = 0; + int bitOffset = 0; + + StringBuilder defaultTable = new StringBuilder(128); + StringBuilder turkishTable = new StringBuilder(128); + StringBuilder portugueseTable = new StringBuilder(128); + + for (char c = 0; c < 128; c++) { + // skip characters that are present in the current extension table + if (tableOffset < tableIndex.length && tableIndex[tableOffset] == c) { + tableOffset++; + continue; + } + + // escape character + int byteOffset = bitOffset / 8; + int shift = bitOffset % 8; + + septets[byteOffset] |= GSM_ESCAPE_CHARACTER << shift; + + if (shift > 1) { + septets[byteOffset + 1] = (byte) (GSM_ESCAPE_CHARACTER >> (8 - shift)); + } + + bitOffset += 7; + + // extended table index + byteOffset = bitOffset / 8; + shift = bitOffset % 8; + + septets[byteOffset] |= c << shift; + + if (shift > 1) { + septets[byteOffset + 1] = (byte) (c >> (8 - shift)); + } + + bitOffset += 7; + + if (c == GsmAlphabet.GSM_EXTENDED_ESCAPE) { + // double Escape maps to space character + defaultTable.append(' '); + turkishTable.append(' '); + portugueseTable.append(' '); + } else { + // other unmapped chars map to the default or locking shift table + defaultTable.append(sBasicTables[0].charAt(c)); + turkishTable.append(sBasicTables[1].charAt(c)); + portugueseTable.append(sBasicTables[3].charAt(c)); + } + } + + String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, + 0, language); + + assertEquals(defaultTable.toString(), decoded); + + decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 1, language); + assertEquals(turkishTable.toString(), decoded); + + decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 3, language); + assertEquals(portugueseTable.toString(), decoded); + } + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/IccServiceTableTest.java b/tests/telephonytests/src/com/android/internal/telephony/IccServiceTableTest.java new file mode 100644 index 0000000..c89f33a --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/IccServiceTableTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Test IccServiceTable class. + */ +public class IccServiceTableTest extends AndroidTestCase { + + static class TestIccServiceTable extends IccServiceTable { + public enum TestIccService { + SERVICE1, + SERVICE2, + SERVICE3, + SERVICE4 + } + + public TestIccServiceTable(byte[] table) { + super(table); + } + + public boolean isAvailable(TestIccService service) { + return super.isAvailable(service.ordinal()); + } + + @Override + protected String getTag() { + return "TestIccServiceTable"; + } + + @Override + protected Object[] getValues() { + return TestIccService.values(); + } + } + + @SmallTest + public void testIccServiceTable() { + byte[] noServices = {0x00}; + byte[] service1 = {0x01}; + byte[] service4 = {0x08}; + byte[] allServices = {0x0f}; + + TestIccServiceTable testTable1 = new TestIccServiceTable(noServices); + assertFalse(testTable1.isAvailable(TestIccServiceTable.TestIccService.SERVICE1)); + assertFalse(testTable1.isAvailable(TestIccServiceTable.TestIccService.SERVICE2)); + assertFalse(testTable1.isAvailable(TestIccServiceTable.TestIccService.SERVICE3)); + assertFalse(testTable1.isAvailable(TestIccServiceTable.TestIccService.SERVICE4)); + + TestIccServiceTable testTable2 = new TestIccServiceTable(service1); + assertTrue(testTable2.isAvailable(TestIccServiceTable.TestIccService.SERVICE1)); + assertFalse(testTable2.isAvailable(TestIccServiceTable.TestIccService.SERVICE2)); + assertFalse(testTable2.isAvailable(TestIccServiceTable.TestIccService.SERVICE3)); + assertFalse(testTable2.isAvailable(TestIccServiceTable.TestIccService.SERVICE4)); + + TestIccServiceTable testTable3 = new TestIccServiceTable(service4); + assertFalse(testTable3.isAvailable(TestIccServiceTable.TestIccService.SERVICE1)); + assertFalse(testTable3.isAvailable(TestIccServiceTable.TestIccService.SERVICE2)); + assertFalse(testTable3.isAvailable(TestIccServiceTable.TestIccService.SERVICE3)); + assertTrue(testTable3.isAvailable(TestIccServiceTable.TestIccService.SERVICE4)); + + TestIccServiceTable testTable4 = new TestIccServiceTable(allServices); + assertTrue(testTable4.isAvailable(TestIccServiceTable.TestIccService.SERVICE1)); + assertTrue(testTable4.isAvailable(TestIccServiceTable.TestIccService.SERVICE2)); + assertTrue(testTable4.isAvailable(TestIccServiceTable.TestIccService.SERVICE3)); + assertTrue(testTable4.isAvailable(TestIccServiceTable.TestIccService.SERVICE4)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/IntRangeManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/IntRangeManagerTest.java new file mode 100644 index 0000000..79dca39 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/IntRangeManagerTest.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.AndroidTestCase; + +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; + +import java.util.ArrayList; + +/** + * Test cases for the IntRangeManager class. + */ +public class IntRangeManagerTest extends AndroidTestCase { + + private static final int SMS_CB_CODE_SCHEME_MIN = 0; + private static final int SMS_CB_CODE_SCHEME_MAX = 255; + + private static final int FLAG_START_UPDATE_CALLED = 0x01; + private static final int FLAG_ADD_RANGE_CALLED = 0x02; + private static final int FLAG_FINISH_UPDATE_CALLED = 0x04; + + private static final int ALL_FLAGS_SET = FLAG_START_UPDATE_CALLED | FLAG_ADD_RANGE_CALLED | + FLAG_FINISH_UPDATE_CALLED; + + /** Dummy IntRangeManager for testing. */ + class TestIntRangeManager extends IntRangeManager { + ArrayList<SmsBroadcastConfigInfo> mConfigList = + new ArrayList<SmsBroadcastConfigInfo>(); + + int flags; + boolean finishUpdateReturnValue = true; + + /** + * Called when the list of enabled ranges has changed. This will be + * followed by zero or more calls to {@link #addRange} followed by + * a call to {@link #finishUpdate}. + */ + protected void startUpdate() { + mConfigList.clear(); + flags |= FLAG_START_UPDATE_CALLED; + } + + /** + * Called after {@link #startUpdate} to indicate a range of enabled + * values. + * @param startId the first id included in the range + * @param endId the last id included in the range + */ + protected void addRange(int startId, int endId, boolean selected) { + mConfigList.add(new SmsBroadcastConfigInfo(startId, endId, + SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected)); + flags |= FLAG_ADD_RANGE_CALLED; + } + + /** + * Called to indicate the end of a range update started by the + * previous call to {@link #startUpdate}. + */ + protected boolean finishUpdate() { + flags |= FLAG_FINISH_UPDATE_CALLED; + return finishUpdateReturnValue; + } + + /** Reset the object for the next test case. */ + void reset() { + flags = 0; + mConfigList.clear(); + } + } + + public void testEmptyRangeManager() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("expecting empty configlist", 0, testManager.mConfigList.size()); + } + + private void checkConfigInfo(SmsBroadcastConfigInfo info, int fromServiceId, + int toServiceId, int fromCodeScheme, int toCodeScheme, boolean selected) { + assertEquals("fromServiceId", fromServiceId, info.getFromServiceId()); + assertEquals("toServiceId", toServiceId, info.getToServiceId()); + assertEquals("fromCodeScheme", fromCodeScheme, info.getFromCodeScheme()); + assertEquals("toCodeScheme", toCodeScheme, info.getToCodeScheme()); + assertEquals("selected", selected, info.isSelected()); + } + + public void testAddSingleChannel() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range", testManager.enableRange(123, 123, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 123, 123, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 123, 123, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + } + + public void testRemoveSingleChannel() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertTrue("enabling range", testManager.enableRange(123, 123, "client1")); + assertEquals("flags after enable", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + testManager.reset(); + assertTrue("disabling range", testManager.disableRange(123, 123, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 123, 123, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", FLAG_START_UPDATE_CALLED | FLAG_FINISH_UPDATE_CALLED, + testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } + + public void testRemoveBadChannel() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertFalse("disabling missing range", testManager.disableRange(123, 123, "client1")); + assertEquals("flags after test", 0, testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } + + public void testAddTwoChannels() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(100, 120, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 120, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(200, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 200, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 120, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 200, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + } + + public void testOverlappingChannels() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 201, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 1", testManager.disableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 149, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("disabling range 2", testManager.disableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", FLAG_START_UPDATE_CALLED | FLAG_FINISH_UPDATE_CALLED, + testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } + + public void testOverlappingChannels2() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 201, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 2", testManager.disableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 201, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 1", testManager.disableRange(100, 200, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 100, 200, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + } + + public void testMultipleOverlappingChannels() { + TestIntRangeManager testManager = new TestIntRangeManager(); + assertEquals("flags before test", 0, testManager.flags); + assertTrue("enabling range 1", testManager.enableRange(67, 9999, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 67, 9999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 2", testManager.enableRange(150, 250, "client2")); + assertEquals("flags after test", 0, testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + testManager.reset(); + assertTrue("enabling range 3", testManager.enableRange(25, 75, "client3")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 66, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 4", testManager.enableRange(12, 500, "client4")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 24, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("enabling range 5", testManager.enableRange(8000, 9998, "client5")); + assertEquals("flags after test", 0, testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + testManager.reset(); + assertTrue("enabling range 6", testManager.enableRange(50000, 65535, "client6")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 9999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 1", testManager.disableRange(67, 9999, "client1")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 501, 7999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + checkConfigInfo(testManager.mConfigList.get(1), 9999, 9999, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 3, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 500, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 8000, 9998, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(2), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 4", testManager.disableRange(12, 500, "client4")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 3, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 12, 24, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + checkConfigInfo(testManager.mConfigList.get(1), 76, 149, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + checkConfigInfo(testManager.mConfigList.get(2), 251, 500, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 4, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(2), 8000, 9998, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(3), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 5", testManager.disableRange(8000, 9998, "client5")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 8000, 9998, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 3, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(2), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 6", testManager.disableRange(50000, 65535, "client6")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 50000, 65535, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 2, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + checkConfigInfo(testManager.mConfigList.get(1), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 2", testManager.disableRange(150, 250, "client2")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 150, 250, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, true); + testManager.reset(); + assertTrue("disabling range 3", testManager.disableRange(25, 75, "client3")); + assertEquals("flags after test", ALL_FLAGS_SET, testManager.flags); + assertEquals("configlist size", 1, testManager.mConfigList.size()); + checkConfigInfo(testManager.mConfigList.get(0), 25, 75, SMS_CB_CODE_SCHEME_MIN, + SMS_CB_CODE_SCHEME_MAX, false); + testManager.reset(); + assertTrue("updating ranges", testManager.updateRanges()); + assertEquals("flags after test", FLAG_START_UPDATE_CALLED | FLAG_FINISH_UPDATE_CALLED, + testManager.flags); + assertEquals("configlist size", 0, testManager.mConfigList.size()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java new file mode 100644 index 0000000..868c76d --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.MccTable; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.util.Log; + +public class MccTableTest extends AndroidTestCase { + private final static String LOG_TAG = "GSM"; + + @SmallTest + public void testTimeZone() throws Exception { + assertEquals(MccTable.defaultTimeZoneForMcc(208), "ECT"); + assertEquals(MccTable.defaultTimeZoneForMcc(232), "Europe/Vienna"); + assertEquals(MccTable.defaultTimeZoneForMcc(655), "Africa/Johannesburg"); + assertEquals(MccTable.defaultTimeZoneForMcc(440), "Asia/Tokyo"); + assertEquals(MccTable.defaultTimeZoneForMcc(441), "Asia/Tokyo"); + assertEquals(MccTable.defaultTimeZoneForMcc(525), "Asia/Singapore"); + assertEquals(MccTable.defaultTimeZoneForMcc(240), null); // tz not defined, hence default + assertEquals(MccTable.defaultTimeZoneForMcc(0), null); // mcc not defined, hence default + assertEquals(MccTable.defaultTimeZoneForMcc(2000), null); // mcc not defined, hence default + } + + @SmallTest + public void testCountryCode() throws Exception { + assertEquals(MccTable.countryCodeForMcc(270), "lu"); + assertEquals(MccTable.countryCodeForMcc(202), "gr"); + assertEquals(MccTable.countryCodeForMcc(750), "fk"); + assertEquals(MccTable.countryCodeForMcc(646), "mg"); + assertEquals(MccTable.countryCodeForMcc(314), "us"); + assertEquals(MccTable.countryCodeForMcc(300), ""); // mcc not defined, hence default + assertEquals(MccTable.countryCodeForMcc(0), ""); // mcc not defined, hence default + assertEquals(MccTable.countryCodeForMcc(2000), ""); // mcc not defined, hence default + } + + @SmallTest + public void testLang() throws Exception { + assertEquals(MccTable.defaultLanguageForMcc(311), "en"); + assertEquals(MccTable.defaultLanguageForMcc(232), "de"); + assertEquals(MccTable.defaultLanguageForMcc(230), "cs"); + assertEquals(MccTable.defaultLanguageForMcc(204), "nl"); + assertEquals(MccTable.defaultLanguageForMcc(274), null); // lang not defined, hence default + assertEquals(MccTable.defaultLanguageForMcc(0), null); // mcc not defined, hence default + assertEquals(MccTable.defaultLanguageForMcc(2000), null); // mcc not defined, hence default + } + + @SmallTest + public void testSmDigits() throws Exception { + assertEquals(MccTable.smallestDigitsMccForMnc(312), 3); + assertEquals(MccTable.smallestDigitsMccForMnc(430), 2); + assertEquals(MccTable.smallestDigitsMccForMnc(365), 3); + assertEquals(MccTable.smallestDigitsMccForMnc(536), 2); + assertEquals(MccTable.smallestDigitsMccForMnc(352), 2); // sd not defined, hence default + assertEquals(MccTable.smallestDigitsMccForMnc(0), 2); // mcc not defined, hence default + assertEquals(MccTable.smallestDigitsMccForMnc(2000), 2); // mcc not defined, hence default + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java new file mode 100644 index 0000000..b63dc71 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony; + +import android.os.Parcel; +import android.test.AndroidTestCase; +import android.telephony.NeighboringCellInfo; +import android.test. suitebuilder.annotation.SmallTest; + +import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; +import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS; + +public class NeighboringCellInfoTest extends AndroidTestCase { + @SmallTest + public void testConstructor() { + int rssi = 31; + NeighboringCellInfo nc; + + nc = new NeighboringCellInfo(rssi, "FFFFFFF", NETWORK_TYPE_EDGE); + assertEquals(NETWORK_TYPE_EDGE, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(0xfff, nc.getLac()); + assertEquals(0xffff, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); + + nc = new NeighboringCellInfo(rssi, "1FF", NETWORK_TYPE_UMTS); + assertEquals(NETWORK_TYPE_UMTS, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getLac()); + assertEquals(0x1ff, nc.getPsc()); + + nc = new NeighboringCellInfo(rssi, "1FF", NETWORK_TYPE_UNKNOWN); + assertEquals(NETWORK_TYPE_UNKNOWN, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getLac()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); + } + + @SmallTest + public void testParcel() { + int rssi = 20; + + NeighboringCellInfo nc = new NeighboringCellInfo(rssi, "12345678", NETWORK_TYPE_GPRS); + assertEquals(NETWORK_TYPE_GPRS, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(0x1234, nc.getLac()); + assertEquals(0x5678, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); + + Parcel p = Parcel.obtain(); + p.setDataPosition(0); + nc.writeToParcel(p, 0); + + p.setDataPosition(0); + NeighboringCellInfo nw = new NeighboringCellInfo(p); + assertEquals(NETWORK_TYPE_GPRS, nw.getNetworkType()); + assertEquals(rssi, nw.getRssi()); + assertEquals(0x1234, nw.getLac()); + assertEquals(0x5678, nw.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nw.getPsc()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java new file mode 100644 index 0000000..db670f8 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.SpannableStringBuilder; +import android.telephony.PhoneNumberUtils; + +public class PhoneNumberUtilsTest extends AndroidTestCase { + + @SmallTest + public void testExtractNetworkPortion() throws Exception { + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortion("+17005554141") + ); + + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortion("+1 (700).555-4141") + ); + + assertEquals( + "17005554141", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141") + ); + + // This may seem wrong, but it's probably ok + assertEquals( + "17005554141*#", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141*#") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN,1234") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN;1234") + ); + + // An MMI string is unperterbed, even though it contains a + // (valid in this case) embedded + + assertEquals( + "**21**17005554141#", + PhoneNumberUtils.extractNetworkPortion("**21**+17005554141#") + //TODO this is the correct result, although the above + //result has been returned since change 31776 + //"**21**+17005554141#" + ); + + assertEquals("", PhoneNumberUtils.extractNetworkPortion("")); + + assertEquals("", PhoneNumberUtils.extractNetworkPortion(",1234")); + + byte [] b = new byte[20]; + b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x80; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x90; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("+17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("+17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + byte[] bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("+17005550020"); + assertEquals(7, bRet.length); + for (int i = 0; i < 7; i++) { + assertEquals(b[i], bRet[i]); + } + + bRet = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength("+17005550020"); + assertEquals(8, bRet.length); + assertEquals(bRet[0], 7); + for (int i = 1; i < 8; i++) { + assertEquals(b[i - 1], bRet[i]); + } + + bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("7005550020"); + assertEquals("7005550020", + PhoneNumberUtils.calledPartyBCDToString(bRet, 0, bRet.length)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0; + assertEquals("17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0; + assertEquals("+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; + assertEquals("*21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2B; b[2] = (byte) 0xB1; + assertEquals("#21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; + assertEquals("*21#+", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB; + assertEquals("**21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 4)); + + b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB; + assertEquals("**21#+", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 4)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xB0; + assertEquals("*99*17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xB0; + assertEquals("*99*+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A; + b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00; + b[8] = (byte) 0x02; b[9] = (byte) 0xFB; + assertEquals("**21*17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 10)); + + b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A; + b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00; + b[8] = (byte) 0x02; b[9] = (byte) 0xFB; + assertEquals("**21*+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 10)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xA1; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xF0; + assertEquals("*21*17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xF0; + assertEquals("*21#+17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + assertNull(PhoneNumberUtils.extractNetworkPortion(null)); + assertNull(PhoneNumberUtils.extractPostDialPortion(null)); + assertTrue(PhoneNumberUtils.compare(null, null)); + assertFalse(PhoneNumberUtils.compare(null, "123")); + assertFalse(PhoneNumberUtils.compare("123", null)); + assertNull(PhoneNumberUtils.toCallerIDMinMatch(null)); + assertNull(PhoneNumberUtils.getStrippedReversed(null)); + assertNull(PhoneNumberUtils.stringFromStringAndTOA(null, 1)); + } + + @SmallTest + public void testExtractNetworkPortionAlt() throws Exception { + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortionAlt("+17005554141") + ); + + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortionAlt("+1 (700).555-4141") + ); + + assertEquals( + "17005554141", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-4141") + ); + + // This may seem wrong, but it's probably ok + assertEquals( + "17005554141*#", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-4141*#") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-41NN") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-41NN,1234") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-41NN;1234") + ); + + // An MMI string is unperterbed, even though it contains a + // (valid in this case) embedded + + assertEquals( + "**21**+17005554141#", + PhoneNumberUtils.extractNetworkPortionAlt("**21**+17005554141#") + ); + + assertEquals( + "*31#+447966164208", + PhoneNumberUtils.extractNetworkPortionAlt("*31#+447966164208") + ); + + assertEquals( + "*31#+447966164208", + PhoneNumberUtils.extractNetworkPortionAlt("*31# (+44) 79 6616 4208") + ); + + assertEquals("", PhoneNumberUtils.extractNetworkPortionAlt("")); + + assertEquals("", PhoneNumberUtils.extractNetworkPortionAlt(",1234")); + + assertNull(PhoneNumberUtils.extractNetworkPortionAlt(null)); + } + + @SmallTest + public void testB() throws Exception { + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+17005554141")); + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-4141")); + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN")); + assertEquals(",1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN,1234")); + assertEquals(";1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1234")); + assertEquals(";1234,;N", + PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1-2.34 ,;N")); + } + + @SmallTest + public void testCompare() throws Exception { + // this is odd + assertFalse(PhoneNumberUtils.compare("", "")); + + assertTrue(PhoneNumberUtils.compare("911", "911")); + assertFalse(PhoneNumberUtils.compare("911", "18005550911")); + assertTrue(PhoneNumberUtils.compare("5555", "5555")); + assertFalse(PhoneNumberUtils.compare("5555", "180055555555")); + + assertTrue(PhoneNumberUtils.compare("+17005554141", "+17005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141,1234")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "17005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "7005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "5554141")); + assertTrue(PhoneNumberUtils.compare("17005554141", "5554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "01117005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "0017005554141")); + assertTrue(PhoneNumberUtils.compare("17005554141", "0017005554141")); + + + assertTrue(PhoneNumberUtils.compare("+17005554141", "**31#+17005554141")); + + assertFalse(PhoneNumberUtils.compare("+1 999 7005554141", "+1 7005554141")); + assertTrue(PhoneNumberUtils.compare("011 1 7005554141", "7005554141")); + + assertFalse(PhoneNumberUtils.compare("011 11 7005554141", "+17005554141")); + + assertFalse(PhoneNumberUtils.compare("+17005554141", "7085882300")); + + assertTrue(PhoneNumberUtils.compare("+44 207 792 3490", "0 207 792 3490")); + + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "00 207 792 3490")); + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "011 207 792 3490")); + + /***** FIXME's ******/ + // + // MMI header should be ignored + assertFalse(PhoneNumberUtils.compare("+17005554141", "**31#17005554141")); + + // It's too bad this is false + // +44 (0) 207 792 3490 is not a dialable number + // but it is commonly how European phone numbers are written + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "+44 (0) 207 792 3490")); + + // The japanese international prefix, for example, messes us up + // But who uses a GSM phone in Japan? + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "010 44 207 792 3490")); + + // The Australian one messes us up too + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "0011 44 207 792 3490")); + + // The Russian trunk prefix messes us up, as does current + // Russian area codes (which bein with 0) + + assertFalse(PhoneNumberUtils.compare("+7(095)9100766", "8(095)9100766")); + + // 444 is not a valid country code, but + // matchIntlPrefixAndCC doesnt know this + assertTrue(PhoneNumberUtils.compare("+444 207 792 3490", "0 207 792 3490")); + + // compare SMS short code + assertTrue(PhoneNumberUtils.compare("404-04", "40404")); + } + + + @SmallTest + public void testToCallerIDIndexable() throws Exception { + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("17005554141")); + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141")); + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141,1234")); + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141;1234")); + + //this seems wrong, or at least useless + assertEquals("NN14555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-41NN")); + + //<shrug> -- these are all not useful, but not terribly wrong + assertEquals("", PhoneNumberUtils.toCallerIDMinMatch("")); + assertEquals("0032", PhoneNumberUtils.toCallerIDMinMatch("2300")); + assertEquals("0032+", PhoneNumberUtils.toCallerIDMinMatch("+2300")); + assertEquals("#130#*", PhoneNumberUtils.toCallerIDMinMatch("*#031#")); + } + + @SmallTest + public void testGetIndexable() throws Exception { + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141")); + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141,1234")); + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141;1234")); + + //this seems wrong, or at least useless + assertEquals("NN145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-41NN")); + + //<shrug> -- these are all not useful, but not terribly wrong + assertEquals("", PhoneNumberUtils.getStrippedReversed("")); + assertEquals("0032", PhoneNumberUtils.getStrippedReversed("2300")); + assertEquals("0032+", PhoneNumberUtils.getStrippedReversed("+2300")); + assertEquals("#130#*", PhoneNumberUtils.getStrippedReversed("*#031#")); + } + + @SmallTest + public void testNanpFormatting() { + SpannableStringBuilder number = new SpannableStringBuilder(); + number.append("8005551212"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-1212", number.toString()); + + number.clear(); + number.append("800555121"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-121", number.toString()); + + number.clear(); + number.append("555-1212"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("555-1212", number.toString()); + + number.clear(); + number.append("800-55512"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-12", number.toString()); + + number.clear(); + number.append("46645"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("46645", number.toString()); + } + + @SmallTest + public void testConvertKeypadLettersToDigits() { + assertEquals("1-800-4664-411", + PhoneNumberUtils.convertKeypadLettersToDigits("1-800-GOOG-411")); + assertEquals("18004664411", + PhoneNumberUtils.convertKeypadLettersToDigits("1800GOOG411")); + assertEquals("1-800-466-4411", + PhoneNumberUtils.convertKeypadLettersToDigits("1-800-466-4411")); + assertEquals("18004664411", + PhoneNumberUtils.convertKeypadLettersToDigits("18004664411")); + assertEquals("222-333-444-555-666-7777-888-9999", + PhoneNumberUtils.convertKeypadLettersToDigits( + "ABC-DEF-GHI-JKL-MNO-PQRS-TUV-WXYZ")); + assertEquals("222-333-444-555-666-7777-888-9999", + PhoneNumberUtils.convertKeypadLettersToDigits( + "abc-def-ghi-jkl-mno-pqrs-tuv-wxyz")); + assertEquals("(800) 222-3334", + PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG")); + } + + // To run this test, the device has to be registered with network + public void testCheckAndProcessPlusCode() { + assertEquals("0118475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000")); + assertEquals("18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+18475797000")); + assertEquals("0111234567", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+1234567")); + assertEquals("01123456700000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+23456700000")); + assertEquals("01111875767800", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+11875767800")); + assertEquals("8475797000,18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+18475231753")); + assertEquals("0118475797000,18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000,+18475231753")); + assertEquals("8475797000;0118469312345", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;+8469312345")); + assertEquals("8475797000,0111234567", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+1234567")); + assertEquals("847597000;01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847597000;+11875767000")); + assertEquals("8475797000,,0118469312345", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,+8469312345")); + assertEquals("8475797000;,0118469312345", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+8469312345")); + assertEquals("8475797000,;18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+18475231753")); + assertEquals("8475797000;,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+11875767000")); + assertEquals("8475797000,;01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+11875767000")); + assertEquals("8475797000,,,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,,+11875767000")); + assertEquals("8475797000;,,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,,+11875767000")); + assertEquals("+;,8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+;,8475797000")); + assertEquals("8475797000,", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,")); + assertEquals("847+579-7000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847+579-7000")); + assertEquals(",8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode(",8475797000")); + assertEquals(";;8475797000,,", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode(";;8475797000,,")); + assertEquals("+this+is$weird;,+", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+this+is$weird;,+")); + assertEquals("", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("")); + assertNull(PhoneNumberUtils.cdmaCheckAndProcessPlusCode(null)); + } + + @SmallTest + public void testCheckAndProcessPlusCodeByNumberFormat() { + assertEquals("18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_NANP)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_JAPAN)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_UNKNOWN)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_JAPAN,PhoneNumberUtils.FORMAT_JAPAN)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_UNKNOWN,PhoneNumberUtils.FORMAT_UNKNOWN)); + } + + /** + * Basic checks for the VoiceMail number. + */ + @SmallTest + public void testWithNumberNotEqualToVoiceMail() throws Exception { + assertFalse(PhoneNumberUtils.isVoiceMailNumber("911")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber("tel:911")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber("")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber(null)); + // This test fails on a device without a sim card + /*TelephonyManager mTelephonyManager = + (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE); + String mVoiceMailNumber = mTelephonyManager.getDefault().getVoiceMailNumber(); + assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber)); + */ + } + + @SmallTest + public void testFormatNumberToE164() { + // Note: ISO 3166-1 only allows upper case country codes. + assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "US")); + assertNull(PhoneNumberUtils.formatNumberToE164("1234567", "US")); + assertEquals("+18004664114", PhoneNumberUtils.formatNumberToE164("800-GOOG-114", "US")); + } + + @SmallTest + public void testFormatNumber() { + assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US")); + assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "US")); + assertEquals("011 86 10 8888 0000", + PhoneNumberUtils.formatNumber("011861088880000", "US")); + assertEquals("010 8888 0000", PhoneNumberUtils.formatNumber("01088880000", "CN")); + // formatNumber doesn't format alpha numbers, but keep them as they are. + assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US")); + } + + @SmallTest + public void testFormatNumber_LeadingStarAndHash() { + // Numbers with a leading '*' or '#' should be left unchanged. + assertEquals("*650 2910000", PhoneNumberUtils.formatNumber("*650 2910000", "US")); + assertEquals("#650 2910000", PhoneNumberUtils.formatNumber("#650 2910000", "US")); + assertEquals("*#650 2910000", PhoneNumberUtils.formatNumber("*#650 2910000", "US")); + assertEquals("#*650 2910000", PhoneNumberUtils.formatNumber("#*650 2910000", "US")); + assertEquals("#650*2910000", PhoneNumberUtils.formatNumber("#650*2910000", "US")); + assertEquals("#650*2910000", PhoneNumberUtils.formatNumber("#650*2910000", "US")); + assertEquals("##650 2910000", PhoneNumberUtils.formatNumber("##650 2910000", "US")); + assertEquals("**650 2910000", PhoneNumberUtils.formatNumber("**650 2910000", "US")); + } + + @SmallTest + public void testNormalizeNumber() { + assertEquals("6502910000", PhoneNumberUtils.normalizeNumber("650 2910000")); + assertEquals("1234567", PhoneNumberUtils.normalizeNumber("12,3#4*567")); + assertEquals("8004664114", PhoneNumberUtils.normalizeNumber("800-GOOG-114")); + assertEquals("+16502910000", PhoneNumberUtils.normalizeNumber("+1 650 2910000")); + } + + @SmallTest + public void testFormatDailabeNumber() { + // Using the phoneNumberE164's country code + assertEquals("(650) 291-0000", + PhoneNumberUtils.formatNumber("6502910000", "+16502910000", "CN")); + // Using the default country code for a phone number containing the IDD + assertEquals("011 86 10 8888 0000", + PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "US")); + assertEquals("00 86 10 8888 0000", + PhoneNumberUtils.formatNumber("00861088880000", "+861088880000", "GB")); + assertEquals("+86 10 8888 0000", + PhoneNumberUtils.formatNumber("+861088880000", "+861088880000", "GB")); + // Wrong default country, so no formatting is done + assertEquals("011861088880000", + PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "GB")); + // The phoneNumberE164 is null + assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("6502910000", null, "US")); + // The given number has a country code. + assertEquals("+1 650-291-0000", PhoneNumberUtils.formatNumber("+16502910000", null, "CN")); + // The given number was formatted. + assertEquals("650-291-0000", PhoneNumberUtils.formatNumber("650-291-0000", null, "US")); + // A valid Polish number should be formatted. + assertEquals("506 128 687", PhoneNumberUtils.formatNumber("506128687", null, "PL")); + // An invalid Polish number should be left as it is. Note Poland doesn't use '0' as a + // national prefix; therefore, the leading '0' makes the number invalid. + assertEquals("0506128687", PhoneNumberUtils.formatNumber("0506128687", null, "PL")); + // Wrong default country, so no formatting is done + assertEquals("011861088880000", + PhoneNumberUtils.formatNumber("011861088880000", "", "GB")); + } + + @SmallTest + public void testIsEmergencyNumber() { + // There are two parallel sets of tests here: one for the + // regular isEmergencyNumber() method, and the other for + // isPotentialEmergencyNumber(). + // + // (The difference is that isEmergencyNumber() will return true + // only if the specified number exactly matches an actual + // emergency number, but isPotentialEmergencyNumber() will + // return true if the specified number simply starts with the + // same digits as any actual emergency number.) + + // Tests for isEmergencyNumber(): + assertTrue(PhoneNumberUtils.isEmergencyNumber("911", "US")); + assertTrue(PhoneNumberUtils.isEmergencyNumber("112", "US")); + // The next two numbers are not valid phone numbers in the US, + // so do not count as emergency numbers (but they *are* "potential" + // emergency numbers; see below.) + assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345", "US")); + assertFalse(PhoneNumberUtils.isEmergencyNumber("11212345", "US")); + // A valid mobile phone number from Singapore shouldn't be classified as an emergency number + // in Singapore, as 911 is not an emergency number there. + assertFalse(PhoneNumberUtils.isEmergencyNumber("91121234", "SG")); + // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number + // in Brazil, as 112 is not an emergency number there. + assertFalse(PhoneNumberUtils.isEmergencyNumber("1121234567", "BR")); + // A valid local phone number from Brazil shouldn't be classified as an emergency number in + // Brazil. + assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345", "BR")); + + // Tests for isPotentialEmergencyNumber(): + // These first two are obviously emergency numbers: + assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("911", "US")); + assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("112", "US")); + // The next two numbers are not valid phone numbers in the US, but can be used to trick the + // system to dial 911 and 112, which are emergency numbers in the US. For the purpose of + // addressing that, they are also classified as "potential" emergency numbers in the US. + assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "US")); + assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("11212345", "US")); + + // A valid mobile phone number from Singapore shouldn't be classified as an emergency number + // in Singapore, as 911 is not an emergency number there. + // This test fails on devices that have ecclist property preloaded with 911. + // assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG")); + + // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number + // in Brazil, as 112 is not an emergency number there. + assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("1121234567", "BR")); + // A valid local phone number from Brazil shouldn't be classified as an emergency number in + // Brazil. + assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "BR")); + } + + @SmallTest + public void testStripSeparators() { + // Smoke tests which should never fail. + assertEquals("1234567890", PhoneNumberUtils.stripSeparators("1234567890")); + assertEquals("911", PhoneNumberUtils.stripSeparators("911")); + assertEquals("112", PhoneNumberUtils.stripSeparators("112")); + + // Separators should be removed, while '+' or any other digits should not. + assertEquals("+16502910000", PhoneNumberUtils.stripSeparators("+1 (650) 291-0000")); + + // WAIT, PAUSE should *not* be stripped + assertEquals("+16502910000,300;", + PhoneNumberUtils.stripSeparators("+1 (650) 291-0000, 300;")); + } + + @SmallTest + public void testConvertAndStrip() { + // Smoke tests which should never fail. + assertEquals("1234567890", PhoneNumberUtils.convertAndStrip("1234567890")); + assertEquals("911", PhoneNumberUtils.convertAndStrip("911")); + assertEquals("112", PhoneNumberUtils.convertAndStrip("112")); + + // It should convert keypad characters into digits, and strip separators + assertEquals("22233344455566677778889999", + PhoneNumberUtils.convertAndStrip("ABC DEF GHI JKL MNO PQR STUV WXYZ")); + + // Test real cases. + assertEquals("18004664411", PhoneNumberUtils.convertAndStrip("1-800-GOOG-411")); + assertEquals("8002223334", PhoneNumberUtils.convertAndStrip("(800) ABC-DEFG")); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java new file mode 100644 index 0000000..a6a0fce --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony; + +import android.telephony.PhoneNumberFormattingTextWatcher; +import android.test.AndroidTestCase; +import android.text.Editable; +import android.text.Selection; +import android.text.SpannableStringBuilder; +import android.text.TextWatcher; + +public class PhoneNumberWatcherTest extends AndroidTestCase { + public void testAppendChars() { + final String multiChars = "65012345"; + final String formatted1 = "(650) 123-45"; + TextWatcher textWatcher = getTextWatcher(); + SpannableStringBuilder number = new SpannableStringBuilder(); + // Append more than one chars + textWatcher.beforeTextChanged(number, 0, 0, multiChars.length()); + number.append(multiChars); + Selection.setSelection(number, number.length()); + textWatcher.onTextChanged(number, 0, 0, number.length()); + textWatcher.afterTextChanged(number); + assertEquals(formatted1, number.toString()); + assertEquals(formatted1.length(), Selection.getSelectionEnd(number)); + // Append one chars + final char appendChar = '6'; + final String formatted2 = "(650) 123-456"; + int len = number.length(); + textWatcher.beforeTextChanged(number, number.length(), 0, 1); + number.append(appendChar); + Selection.setSelection(number, number.length()); + textWatcher.onTextChanged(number, len, 0, 1); + textWatcher.afterTextChanged(number); + assertEquals(formatted2, number.toString()); + assertEquals(formatted2.length(), Selection.getSelectionEnd(number)); + } + + public void testRemoveLastChars() { + final String init = "65012345678"; + final String result1 = "(650) 123-4567"; + TextWatcher textWatcher = getTextWatcher(); + // Remove the last char. + SpannableStringBuilder number = new SpannableStringBuilder(init); + int len = number.length(); + textWatcher.beforeTextChanged(number, len - 1, 1, 0); + number.delete(len - 1, len); + Selection.setSelection(number, number.length()); + textWatcher.onTextChanged(number, number.length() - 1, 1, 0); + textWatcher.afterTextChanged(number); + assertEquals(result1, number.toString()); + assertEquals(result1.length(), Selection.getSelectionEnd(number)); + // Remove last 5 chars + final String result2 = "650-123"; + textWatcher.beforeTextChanged(number, number.length() - 4, 4, 0); + number.delete(number.length() - 5, number.length()); + Selection.setSelection(number, number.length()); + textWatcher.onTextChanged(number, number.length(), 4, 0); + textWatcher.afterTextChanged(number); + assertEquals(result2, number.toString()); + assertEquals(result2.length(), Selection.getSelectionEnd(number)); + } + + public void testInsertChars() { + final String init = "650-23"; + final String expected1 = "650-123"; + TextWatcher textWatcher = getTextWatcher(); + + // Insert one char + SpannableStringBuilder number = new SpannableStringBuilder(init); + textWatcher.beforeTextChanged(number, 3, 0, 1); + number.insert(3, "1"); // 6501-23 + Selection.setSelection(number, 4); // make the cursor at right of 1 + textWatcher.onTextChanged(number, 3, 0, 1); + textWatcher.afterTextChanged(number); + assertEquals(expected1, number.toString()); + // the cursor should still at the right of '1' + assertEquals(5, Selection.getSelectionEnd(number)); + + // Insert multiple chars + final String expected2 = "(650) 145-6723"; + textWatcher.beforeTextChanged(number, 5, 0, 4); + number.insert(5, "4567"); // change to 650-1456723 + Selection.setSelection(number, 9); // the cursor is at the right of '7'. + textWatcher.onTextChanged(number, 7, 0, 4); + textWatcher.afterTextChanged(number); + assertEquals(expected2, number.toString()); + // the cursor should be still at the right of '7' + assertEquals(12, Selection.getSelectionEnd(number)); + } + + public void testStopFormatting() { + final String init = "(650) 123"; + final String expected1 = "(650) 123 4"; + TextWatcher textWatcher = getTextWatcher(); + + // Append space + SpannableStringBuilder number = new SpannableStringBuilder(init); + textWatcher.beforeTextChanged(number, 9, 0, 2); + number.insert(9, " 4"); // (6501) 23 4 + Selection.setSelection(number, number.length()); // make the cursor at right of 4 + textWatcher.onTextChanged(number, 9, 0, 2); + textWatcher.afterTextChanged(number); + assertEquals(expected1, number.toString()); + // the cursor should still at the right of '1' + assertEquals(expected1.length(), Selection.getSelectionEnd(number)); + + // Delete a ')' + final String expected2 ="(650 123"; + textWatcher = getTextWatcher(); + number = new SpannableStringBuilder(init); + textWatcher.beforeTextChanged(number, 4, 1, 0); + number.delete(4, 5); // (6501 23 4 + Selection.setSelection(number, 5); // make the cursor at right of 1 + textWatcher.onTextChanged(number, 4, 1, 0); + textWatcher.afterTextChanged(number); + assertEquals(expected2, number.toString()); + // the cursor should still at the right of '1' + assertEquals(5, Selection.getSelectionEnd(number)); + + // Insert a hyphen + final String expected3 ="(650) 12-3"; + textWatcher = getTextWatcher(); + number = new SpannableStringBuilder(init); + textWatcher.beforeTextChanged(number, 8, 0, 1); + number.insert(8, "-"); // (650) 12-3 + Selection.setSelection(number, 9); // make the cursor at right of - + textWatcher.onTextChanged(number, 8, 0, 1); + textWatcher.afterTextChanged(number); + assertEquals(expected3, number.toString()); + // the cursor should still at the right of '-' + assertEquals(9, Selection.getSelectionEnd(number)); + } + + public void testRestartFormatting() { + final String init = "(650) 123"; + final String expected1 = "(650) 123 4"; + TextWatcher textWatcher = getTextWatcher(); + + // Append space + SpannableStringBuilder number = new SpannableStringBuilder(init); + textWatcher.beforeTextChanged(number, 9, 0, 2); + number.insert(9, " 4"); // (650) 123 4 + Selection.setSelection(number, number.length()); // make the cursor at right of 4 + textWatcher.onTextChanged(number, 9, 0, 2); + textWatcher.afterTextChanged(number); + assertEquals(expected1, number.toString()); + // the cursor should still at the right of '4' + assertEquals(expected1.length(), Selection.getSelectionEnd(number)); + + // Clear the current string, and start formatting again. + int len = number.length(); + textWatcher.beforeTextChanged(number, 0, len, 0); + number.delete(0, len); + textWatcher.onTextChanged(number, 0, len, 0); + textWatcher.afterTextChanged(number); + + final String expected2 = "650-1234"; + number = new SpannableStringBuilder(init); + textWatcher.beforeTextChanged(number, 9, 0, 1); + number.insert(9, "4"); // (650) 1234 + Selection.setSelection(number, number.length()); // make the cursor at right of 4 + textWatcher.onTextChanged(number, 9, 0, 1); + textWatcher.afterTextChanged(number); + assertEquals(expected2, number.toString()); + // the cursor should still at the right of '4' + assertEquals(expected2.length(), Selection.getSelectionEnd(number)); + } + + public void testTextChangedByOtherTextWatcher() { + final TextWatcher cleanupTextWatcher = new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + s.clear(); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + } + }; + final String init = "(650) 123"; + final String expected1 = ""; + TextWatcher textWatcher = getTextWatcher(); + + SpannableStringBuilder number = new SpannableStringBuilder(init); + textWatcher.beforeTextChanged(number, 5, 0, 1); + number.insert(5, "4"); // (6504) 123 + Selection.setSelection(number, 5); // make the cursor at right of 4 + textWatcher.onTextChanged(number, 5, 0, 1); + number.setSpan(cleanupTextWatcher, 0, number.length(), 0); + textWatcher.afterTextChanged(number); + assertEquals(expected1, number.toString()); + } + + /** + * Test the case where some other component is auto-completing what the user is typing + */ + public void testAutoCompleteWithFormattedNumber() { + String init = "650-1"; + String expected = "+1-650-123-4567"; // Different formatting than ours + testReplacement(init, expected, expected); + } + + /** + * Test the case where some other component is auto-completing what the user is typing + */ + public void testAutoCompleteWithFormattedNameAndNumber() { + String init = "650-1"; + String expected = "Test User <650-123-4567>"; + testReplacement(init, expected, expected); + } + + /** + * Test the case where some other component is auto-completing what the user is typing + */ + public void testAutoCompleteWithNumericNameAndNumber() { + String init = "650"; + String expected = "2nd Test User <650-123-4567>"; + testReplacement(init, expected, expected); + } + + /** + * Test the case where some other component is auto-completing what the user is typing + */ + public void testAutoCompleteWithUnformattedNumber() { + String init = "650-1"; + String expected = "6501234567"; + testReplacement(init, expected, expected); + } + + /** + * Test the case where some other component is auto-completing what the user is typing, where + * the deleted text doesn't have any formatting and neither does the replacement text: in this + * case the replacement text should be formatted by the PhoneNumberFormattingTextWatcher. + */ + public void testAutoCompleteUnformattedWithUnformattedNumber() { + String init = "650"; + String replacement = "6501234567"; + String expected = "(650) 123-4567"; + testReplacement(init, replacement, expected); + + String init2 = "650"; + String replacement2 = "16501234567"; + String expected2 = "1 650-123-4567"; + testReplacement(init2, replacement2, expected2); + } + + /** + * Helper method for testing replacing the entire string with another string + * @param init The initial string + * @param expected + */ + private void testReplacement(String init, String replacement, String expected) { + TextWatcher textWatcher = getTextWatcher(); + + SpannableStringBuilder number = new SpannableStringBuilder(init); + + // Replace entire text with the given values + textWatcher.beforeTextChanged(number, 0, init.length(), replacement.length()); + number.replace(0, init.length(), replacement, 0, replacement.length()); + Selection.setSelection(number, replacement.length()); // move the cursor to the end + textWatcher.onTextChanged(number, 0, init.length(), replacement.length()); + textWatcher.afterTextChanged(number); + + assertEquals(expected, number.toString()); + // the cursor should be still at the end + assertEquals(expected.length(), Selection.getSelectionEnd(number)); + } + + private TextWatcher getTextWatcher() { + return new PhoneNumberFormattingTextWatcher("US"); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java new file mode 100644 index 0000000..8a66614 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.suitebuilder.annotation.MediumTest; +import com.android.internal.telephony.TestPhoneNotifier; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.test.SimulatedRadioControl; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.Iterator; + +/** + * {@hide} + */ +public class SMSDispatcherTest extends AndroidTestCase { + @MediumTest + public void testCMT1() throws Exception { + SmsMessage sms; + SmsHeader header; + + String[] lines = new String[2]; + + lines[0] = "+CMT: ,158"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B" + + "8423F000035502010106276170706C69636174696F6E2F766E642E776170" + + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F" + + "7547514D4141424C3641414141536741415A4B554141414141008D908918" + + "802B31363530323438363137392F545950453D504C4D4E008A808E028000" + + "88058103093A8083687474703A2F2F36"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(sms.getUserData()); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 85); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 1); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @MediumTest + public void testCMT2() throws Exception { + SmsMessage sms; + SmsHeader header; + + String[] lines = new String[2]; + + lines[0] = "+CMT: ,77"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F" + + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141" + + "424C3641414141536741415A4B55414141414100"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(sms.getUserData()); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 85); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 2); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @MediumTest + public void testEfRecord() throws Exception { + SmsMessage sms; + + String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3" + + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1" + + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e" + + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874" + + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb" + + "eff8bc7ecfeffbffffffffffffffffffffffffffff"; + byte[] data = IccUtils.hexStringToBytes(s); + + sms = SmsMessage.createFromEfRecord(1, data); + assertNotNull(sms.getMessageBody()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java b/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java new file mode 100644 index 0000000..609e768 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.ServiceManager; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.List; + +import junit.framework.TestCase; + +@Suppress +public class SimPhoneBookTest extends TestCase { + + public void testBasic() throws Exception { + IIccPhoneBook simPhoneBook = + IIccPhoneBook.Stub.asInterface(ServiceManager.getService("simphonebook")); + assertNotNull(simPhoneBook); + + int size[] = simPhoneBook.getAdnRecordsSize(IccConstants.EF_ADN); + assertNotNull(size); + assertEquals(3, size.length); + assertEquals(size[0] * size[2], size[1]); + assertTrue(size[2] >= 100); + + List<AdnRecord> adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + // do it twice cause the second time shall read from cache only + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + assertNotNull(adnRecordList); + + // Test for phone book update + int adnIndex, listIndex = 0; + AdnRecord originalAdn = null; + // We need to maintain the state of the SIM before and after the test. + // Since this test doesn't mock the SIM we try to get a valid ADN record, + // for 3 tries and if this fails, we bail out. + for (adnIndex = 3 ; adnIndex >= 1; adnIndex--) { + listIndex = adnIndex - 1; // listIndex is zero based. + originalAdn = adnRecordList.get(listIndex); + assertNotNull("Original Adn is Null.", originalAdn); + assertNotNull("Original Adn alpha tag is null.", originalAdn.getAlphaTag()); + assertNotNull("Original Adn number is null.", originalAdn.getNumber()); + + if (originalAdn.getNumber().length() > 0 && + originalAdn.getAlphaTag().length() > 0) { + break; + } + } + if (adnIndex == 0) return; + + AdnRecord emptyAdn = new AdnRecord("", ""); + AdnRecord firstAdn = new AdnRecord("John", "4085550101"); + AdnRecord secondAdn = new AdnRecord("Andy", "6505550102"); + String pin2 = null; + + // udpate by index + boolean success = simPhoneBook.updateAdnRecordsInEfByIndex(IccConstants.EF_ADN, + firstAdn.getAlphaTag(), firstAdn.getNumber(), adnIndex, pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + AdnRecord tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(firstAdn.isEqual(tmpAdn)); + + // replace by search + success = simPhoneBook.updateAdnRecordsInEfBySearch(IccConstants.EF_ADN, + firstAdn.getAlphaTag(), firstAdn.getNumber(), + secondAdn.getAlphaTag(), secondAdn.getNumber(), pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertFalse(firstAdn.isEqual(tmpAdn)); + assertTrue(secondAdn.isEqual(tmpAdn)); + + // erase be search + success = simPhoneBook.updateAdnRecordsInEfBySearch(IccConstants.EF_ADN, + secondAdn.getAlphaTag(), secondAdn.getNumber(), + emptyAdn.getAlphaTag(), emptyAdn.getNumber(), pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(tmpAdn.isEmpty()); + + // restore the orginial adn + success = simPhoneBook.updateAdnRecordsInEfByIndex(IccConstants.EF_ADN, + originalAdn.getAlphaTag(), originalAdn.getNumber(), adnIndex, + pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(originalAdn.isEqual(tmpAdn)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java new file mode 100644 index 0000000..1609680 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.ServiceManager; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.List; + +import junit.framework.TestCase; + +public class SimSmsTest extends TestCase { + + @MediumTest + @Suppress // TODO: suppress this test for now since it doesn't work on the emulator + public void testBasic() throws Exception { + + ISms sms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + assertNotNull(sms); + + List<SmsRawData> records = sms.getAllMessagesFromIccEf(); + assertNotNull(records); + assertTrue(records.size() >= 0); + + int firstNullIndex = -1; + int firstValidIndex = -1; + byte[] pdu = null; + for (int i = 0; i < records.size(); i++) { + SmsRawData data = records.get(i); + if (data != null && firstValidIndex == -1) { + firstValidIndex = i; + pdu = data.getBytes(); + } + if (data == null && firstNullIndex == -1) { + firstNullIndex = i; + } + if (firstNullIndex != -1 && firstValidIndex != -1) { + break; + } + } + if (firstNullIndex == -1 || firstValidIndex == -1) + return; + assertNotNull(pdu); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java new file mode 100644 index 0000000..ef62d85 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.gsm.SimTlv; +import com.android.internal.telephony.IccUtils; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + + +public class SimUtilsTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + byte[] data, data2; + + /* + * bcdToString() + */ + + // An EF[ICCID] record + data = IccUtils.hexStringToBytes("981062400510444868f2"); + assertEquals("8901260450014484862", IccUtils.bcdToString(data, 0, data.length)); + + // skip the first and last bytes + assertEquals("0126045001448486", IccUtils.bcdToString(data, 1, data.length - 2)); + + // Stops on invalid BCD value + data = IccUtils.hexStringToBytes("98E062400510444868f2"); + assertEquals("890", IccUtils.bcdToString(data, 0, data.length)); + + // skip the high nibble 'F' since some PLMNs have it + data = IccUtils.hexStringToBytes("98F062400510444868f2"); + assertEquals("890260450014484862", IccUtils.bcdToString(data, 0, data.length)); + + /* + * gsmBcdByteToInt() + */ + + assertEquals(98, IccUtils.gsmBcdByteToInt((byte) 0x89)); + + // Out of range is treated as 0 + assertEquals(8, IccUtils.gsmBcdByteToInt((byte) 0x8c)); + + /* + * cdmaBcdByteToInt() + */ + + assertEquals(89, IccUtils.cdmaBcdByteToInt((byte) 0x89)); + + // Out of range is treated as 0 + assertEquals(80, IccUtils.cdmaBcdByteToInt((byte) 0x8c)); + + /* + * adnStringFieldToString() + */ + + + data = IccUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff"); + // Again, skip prepended 0 + // (this is an EF[ADN] record) + assertEquals("Voice Mail", IccUtils.adnStringFieldToString(data, 1, data.length - 15)); + + data = IccUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF"); + // (this is from an EF[ADN] record) + assertEquals("\u9673\u539A\u5764/M", IccUtils.adnStringFieldToString(data, 0, data.length)); + + data = IccUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF"); + // (this is made up to test since I don't have a real one) + assertEquals("Vo\u00ECce M\u00E0il", IccUtils.adnStringFieldToString(data, 0, data.length)); + + data = IccUtils.hexStringToBytes("820505302D82d32d31"); + // Example from 3GPP TS 11.11 V18.1.3.0 annex B + assertEquals("-\u0532\u0583-1", IccUtils.adnStringFieldToString(data, 0, data.length)); + } + +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java new file mode 100644 index 0000000..b848657 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.telephony.SmsMessage; +import android.telephony.TelephonyManager; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import com.android.internal.telephony.SmsConstants; + +import java.util.Random; + +/** + * Test cases to verify selection of the optimal 7 bit encoding tables + * (for all combinations of enabled national language tables) for messages + * containing Turkish, Spanish, Portuguese, Greek, and other symbols + * present in the GSM default and national language tables defined in + * 3GPP TS 23.038. Also verifies correct SMS encoding for CDMA, which only + * supports the GSM 7 bit default alphabet, ASCII 8 bit, and UCS-2. + * Tests both encoding variations: unsupported characters mapped to space, + * and unsupported characters force entire message to UCS-2. + */ +public class SmsMessageBodyTest extends AndroidTestCase { + private static final String TAG = "SmsMessageBodyTest"; + + // ASCII chars in the GSM 7 bit default alphabet + private static final String sAsciiChars = "@$_ !\"#%&'()*+,-./0123456789" + + ":;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n\r"; + + // Unicode chars in the GSM 7 bit default alphabet and both locking shift tables + private static final String sGsmDefaultChars = "\u00a3\u00a5\u00e9\u00c7\u0394\u00c9" + + "\u00dc\u00a7\u00fc\u00e0"; + + // Unicode chars in the GSM 7 bit default table and Turkish locking shift tables + private static final String sGsmDefaultAndTurkishTables = "\u00f9\u00f2\u00c5\u00e5\u00df" + + "\u00a4\u00c4\u00d6\u00d1\u00e4\u00f6\u00f1"; + + // Unicode chars in the GSM 7 bit default table but not the locking shift tables + private static final String sGsmDefaultTableOnly = "\u00e8\u00ec\u00d8\u00f8\u00c6\u00e6" + + "\u00a1\u00bf"; + + // ASCII chars in the GSM default extension table + private static final String sGsmExtendedAsciiChars = "{}[]\f"; + + // chars in GSM default extension table and Portuguese locking shift table + private static final String sGsmExtendedPortugueseLocking = "^\\|~"; + + // Euro currency symbol + private static final String sGsmExtendedEuroSymbol = "\u20ac"; + + // CJK ideographs, Hiragana, Katakana, full width letters, Cyrillic, etc. + private static final String sUnicodeChars = "\u4e00\u4e01\u4e02\u4e03" + + "\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d" + + "\u4e0e\u4e0f\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048" + + "\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8" + + "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18" + + "\uff70\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78" + + "\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408" + + "\u00a2\u00a9\u00ae\u2122"; + + // chars in Turkish single shift and locking shift tables + private static final String sTurkishChars = "\u0131\u011e\u011f\u015e\u015f\u0130"; + + // chars in Spanish single shift table and Portuguese single and locking shift tables + private static final String sPortugueseAndSpanishChars = "\u00c1\u00e1\u00cd\u00ed" + + "\u00d3\u00f3\u00da\u00fa"; + + // chars in all national language tables but not in the standard GSM alphabets + private static final String sNationalLanguageTablesOnly = "\u00e7"; + + // chars in Portuguese single shift and locking shift tables + private static final String sPortugueseChars = "\u00ea\u00d4\u00f4\u00c0\u00c2\u00e2" + + "\u00ca\u00c3\u00d5\u00e3\u00f5"; + + // chars in Portuguese locking shift table only + private static final String sPortugueseLockingShiftChars = "\u00aa\u221e\u00ba`"; + + // Greek letters in GSM alphabet missing from Portuguese locking and single shift tables + private static final String sGreekLettersNotInPortugueseTables = "\u039b\u039e"; + + // Greek letters in GSM alphabet and Portuguese single shift (but not locking shift) table + private static final String sGreekLettersInPortugueseShiftTable = + "\u03a6\u0393\u03a9\u03a0\u03a8\u03a3\u0398"; + + // List of classes of characters in SMS tables + private static final String[] sCharacterClasses = { + sGsmExtendedAsciiChars, + sGsmExtendedPortugueseLocking, + sGsmDefaultChars, + sGsmDefaultAndTurkishTables, + sGsmDefaultTableOnly, + sGsmExtendedEuroSymbol, + sUnicodeChars, + sTurkishChars, + sPortugueseChars, + sPortugueseLockingShiftChars, + sPortugueseAndSpanishChars, + sGreekLettersNotInPortugueseTables, + sGreekLettersInPortugueseShiftTable, + sNationalLanguageTablesOnly, + sAsciiChars + }; + + private static final int sNumCharacterClasses = sCharacterClasses.length; + + // For each character class, whether it is present in a particular char table. + // First three entries are locking shift tables, followed by four single shift tables + private static final boolean[][] sCharClassPresenceInTables = { + // ASCII chars in all GSM extension tables + {false, false, false, true, true, true, true}, + // ASCII chars in all GSM extension tables and Portuguese locking shift table + {false, false, true, true, true, true, true}, + // non-ASCII chars in GSM default alphabet and all locking tables + {true, true, true, false, false, false, false}, + // non-ASCII chars in GSM default alphabet and Turkish locking shift table + {true, true, false, false, false, false, false}, + // non-ASCII chars in GSM default alphabet table only + {true, false, false, false, false, false, false}, + // Euro symbol is present in several tables + {false, true, true, true, true, true, true}, + // Unicode characters not present in any 7 bit tables + {false, false, false, false, false, false, false}, + // Characters specific to Turkish language + {false, true, false, false, true, false, false}, + // Characters in Portuguese single shift and locking shift tables + {false, false, true, false, false, false, true}, + // Characters in Portuguese locking shift table only + {false, false, true, false, false, false, false}, + // Chars in Spanish single shift and Portuguese single and locking shift tables + {false, false, true, false, false, true, true}, + // Greek letters in GSM default alphabet missing from Portuguese tables + {true, true, false, false, false, false, false}, + // Greek letters in GSM alphabet and Portuguese single shift table + {true, true, false, false, false, false, true}, + // Chars in all national language tables but not the standard GSM tables + {false, true, true, false, true, true, true}, + // ASCII chars in GSM default alphabet + {true, true, true, false, false, false, false} + }; + + private static final int sTestLengthCount = 12; + + private static final int[] sSeptetTestLengths = + { 0, 1, 2, 80, 159, 160, 161, 240, 305, 306, 307, 320}; + + private static final int[] sUnicodeTestLengths = + { 0, 1, 2, 35, 69, 70, 71, 100, 133, 134, 135, 160}; + + private static final int[] sTestMsgCounts = + { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3}; + + private static final int[] sSeptetUnitsRemaining = + {160, 159, 158, 80, 1, 0, 145, 66, 1, 0, 152, 139}; + + private static final int[] sUnicodeUnitsRemaining = + { 70, 69, 68, 35, 1, 0, 63, 34, 1, 0, 66, 41}; + + // Combinations of enabled GSM national language single shift tables + private static final int[][] sEnabledSingleShiftTables = { + {}, // GSM default alphabet only + {1}, // Turkish (single shift only) + {1}, // Turkish (single and locking shift) + {2}, // Spanish + {3}, // Portuguese (single shift only) + {3}, // Portuguese (single and locking shift) + {1, 2}, // Turkish + Spanish (single shift only) + {1, 2}, // Turkish + Spanish (single and locking shift) + {1, 3}, // Turkish + Portuguese (single shift only) + {1, 3}, // Turkish + Portuguese (single and locking shift) + {2, 3}, // Spanish + Portuguese (single shift only) + {2, 3}, // Spanish + Portuguese (single and locking shift) + {1, 2, 3}, // Turkish, Spanish, Portuguese (single shift only) + {1, 2, 3}, // Turkish, Spanish, Portuguese (single and locking shift) + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} // all language tables + }; + + // Combinations of enabled GSM national language locking shift tables + private static final int[][] sEnabledLockingShiftTables = { + {}, // GSM default alphabet only + {}, // Turkish (single shift only) + {1}, // Turkish (single and locking shift) + {}, // Spanish (no locking shift table) + {}, // Portuguese (single shift only) + {3}, // Portuguese (single and locking shift) + {}, // Turkish + Spanish (single shift only) + {1}, // Turkish + Spanish (single and locking shift) + {}, // Turkish + Portuguese (single shift only) + {1, 3}, // Turkish + Portuguese (single and locking shift) + {}, // Spanish + Portuguese (single shift only) + {3}, // Spanish + Portuguese (single and locking shift) + {}, // Turkish, Spanish, Portuguese (single shift only) + {1, 3}, // Turkish, Spanish, Portuguese (single and locking shift) + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} // all language tables + }; + + // LanguagePair counter indexes to check for each entry above + private static final int[][] sLanguagePairIndexesByEnabledIndex = { + {0}, // default tables only + {0, 1}, // Turkish (single shift only) + {0, 1, 4, 5}, // Turkish (single and locking shift) + {0, 2}, // Spanish + {0, 3}, // Portuguese (single shift only) + {0, 3, 8, 11}, // Portuguese (single and locking shift) + {0, 1, 2}, // Turkish + Spanish (single shift only) + {0, 1, 2, 4, 5, 6}, // Turkish + Spanish (single and locking shift) + {0, 1, 3}, // Turkish + Portuguese (single shift only) + {0, 1, 3, 4, 5, 7, 8, 9, 11}, // Turkish + Portuguese (single and locking shift) + {0, 2, 3}, // Spanish + Portuguese (single shift only) + {0, 2, 3, 8, 10, 11}, // Spanish + Portuguese (single and locking shift) + {0, 1, 2, 3}, // all languages (single shift only) + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, // all languages (single and locking shift) + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} // all languages (no Indic chars in test) + }; + + /** + * User data header requires one octet for length. Count as one septet, because + * all combinations of header elements below will have at least one free bit + * when padding to the nearest septet boundary. + */ + private static final int UDH_SEPTET_COST_LENGTH = 1; + + /** + * Using a non-default language locking shift table OR single shift table + * requires a user data header of 3 octets, or 4 septets, plus UDH length. + */ + private static final int UDH_SEPTET_COST_ONE_SHIFT_TABLE = 4; + + /** + * Using a non-default language locking shift table AND single shift table + * requires a user data header of 6 octets, or 7 septets, plus UDH length. + */ + private static final int UDH_SEPTET_COST_TWO_SHIFT_TABLES = 7; + + /** + * Multi-part messages require a user data header of 5 octets, or 6 septets, + * plus UDH length. + */ + private static final int UDH_SEPTET_COST_CONCATENATED_MESSAGE = 6; + + @SmallTest + public void testCalcLengthAscii() throws Exception { + StringBuilder sb = new StringBuilder(320); + int[] values = {0, 0, 0, SmsConstants.ENCODING_7BIT, 0, 0}; + int startPos = 0; + int asciiCharsLen = sAsciiChars.length(); + + for (int i = 0; i < sTestLengthCount; i++) { + int len = sSeptetTestLengths[i]; + assertTrue(sb.length() <= len); + + while (sb.length() < len) { + int addCount = len - sb.length(); + int endPos = (asciiCharsLen - startPos > addCount) ? + (startPos + addCount) : asciiCharsLen; + sb.append(sAsciiChars, startPos, endPos); + startPos = (endPos == asciiCharsLen) ? 0 : endPos; + } + assertEquals(len, sb.length()); + + String testStr = sb.toString(); + values[0] = sTestMsgCounts[i]; + values[1] = len; + values[2] = sSeptetUnitsRemaining[i]; + + callGsmLengthMethods(testStr, false, values); + callGsmLengthMethods(testStr, true, values); + callCdmaLengthMethods(testStr, false, values); + callCdmaLengthMethods(testStr, true, values); + } + } + + @SmallTest + public void testCalcLengthUnicode() throws Exception { + StringBuilder sb = new StringBuilder(160); + int[] values = {0, 0, 0, SmsConstants.ENCODING_16BIT, 0, 0}; + int[] values7bit = {1, 0, 0, SmsConstants.ENCODING_7BIT, 0, 0}; + int startPos = 0; + int unicodeCharsLen = sUnicodeChars.length(); + + // start with length 1: empty string uses ENCODING_7BIT + for (int i = 1; i < sTestLengthCount; i++) { + int len = sUnicodeTestLengths[i]; + assertTrue(sb.length() <= len); + + while (sb.length() < len) { + int addCount = len - sb.length(); + int endPos = (unicodeCharsLen - startPos > addCount) ? + (startPos + addCount) : unicodeCharsLen; + sb.append(sUnicodeChars, startPos, endPos); + startPos = (endPos == unicodeCharsLen) ? 0 : endPos; + } + assertEquals(len, sb.length()); + + String testStr = sb.toString(); + values[0] = sTestMsgCounts[i]; + values[1] = len; + values[2] = sUnicodeUnitsRemaining[i]; + values7bit[1] = len; + values7bit[2] = SmsConstants.MAX_USER_DATA_SEPTETS - len; + + callGsmLengthMethods(testStr, false, values); + callCdmaLengthMethods(testStr, false, values); + callGsmLengthMethods(testStr, true, values7bit); + callCdmaLengthMethods(testStr, true, values7bit); + } + } + + private static class LanguagePair { + // index is 2 for Portuguese locking shift because there is no Spanish locking shift table + private final int langTableIndex; + private final int langShiftTableIndex; + int length; + int missingChars7bit; + + LanguagePair(int langTable, int langShiftTable) { + langTableIndex = langTable; + langShiftTableIndex = langShiftTable; + } + + void clear() { + length = 0; + missingChars7bit = 0; + } + + void addChar(boolean[] charClassTableRow) { + if (charClassTableRow[langTableIndex]) { + length++; + } else if (charClassTableRow[3 + langShiftTableIndex]) { + length += 2; + } else { + length++; // use ' ' for unmapped char in 7 bit only mode + missingChars7bit++; + } + } + } + + private static class CounterHelper { + LanguagePair[] mCounters; + int[] mStatsCounters; + int mUnicodeCounter; + + CounterHelper() { + mCounters = new LanguagePair[12]; + mStatsCounters = new int[12]; + for (int i = 0; i < 12; i++) { + mCounters[i] = new LanguagePair(i/4, i%4); + } + } + + void clear() { + // Note: don't clear stats counters + for (int i = 0; i < 12; i++) { + mCounters[i].clear(); + } + } + + void addChar(int charClass) { + boolean[] charClassTableRow = sCharClassPresenceInTables[charClass]; + for (int i = 0; i < 12; i++) { + mCounters[i].addChar(charClassTableRow); + } + } + + void fillData(int enabledLangsIndex, boolean use7bitOnly, int[] values, int length) { + int[] languagePairs = sLanguagePairIndexesByEnabledIndex[enabledLangsIndex]; + int minNumSeptets = Integer.MAX_VALUE; + int minNumSeptetsWithHeader = Integer.MAX_VALUE; + int minNumMissingChars = Integer.MAX_VALUE; + int langIndex = -1; + int langShiftIndex = -1; + for (int i : languagePairs) { + LanguagePair pair = mCounters[i]; + int udhLength = 0; + if (i != 0) { + udhLength = UDH_SEPTET_COST_LENGTH; + if (i < 4 || i % 4 == 0) { + udhLength += UDH_SEPTET_COST_ONE_SHIFT_TABLE; + } else { + udhLength += UDH_SEPTET_COST_TWO_SHIFT_TABLES; + } + } + int numSeptetsWithHeader; + if (pair.length > (SmsConstants.MAX_USER_DATA_SEPTETS - udhLength)) { + if (udhLength == 0) { + udhLength = UDH_SEPTET_COST_LENGTH; + } + udhLength += UDH_SEPTET_COST_CONCATENATED_MESSAGE; + int septetsPerPart = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength; + int msgCount = (pair.length + septetsPerPart - 1) / septetsPerPart; + numSeptetsWithHeader = udhLength * msgCount + pair.length; + } else { + numSeptetsWithHeader = udhLength + pair.length; + } + + if (use7bitOnly) { + if (pair.missingChars7bit < minNumMissingChars || (pair.missingChars7bit == + minNumMissingChars && numSeptetsWithHeader < minNumSeptetsWithHeader)) { + minNumSeptets = pair.length; + minNumSeptetsWithHeader = numSeptetsWithHeader; + minNumMissingChars = pair.missingChars7bit; + langIndex = pair.langTableIndex; + langShiftIndex = pair.langShiftTableIndex; + } + } else { + if (pair.missingChars7bit == 0 && numSeptetsWithHeader < minNumSeptetsWithHeader) { + minNumSeptets = pair.length; + minNumSeptetsWithHeader = numSeptetsWithHeader; + langIndex = pair.langTableIndex; + langShiftIndex = pair.langShiftTableIndex; + } + } + } + if (langIndex == -1) { + // nothing matches, use values for Unicode + int byteCount = length * 2; + if (byteCount > SmsConstants.MAX_USER_DATA_BYTES) { + values[0] = (byteCount + SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER - 1) / + SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; + values[2] = ((values[0] * SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER) - + byteCount) / 2; + } else { + values[0] = 1; + values[2] = (SmsConstants.MAX_USER_DATA_BYTES - byteCount) / 2; + } + values[1] = length; + values[3] = SmsConstants.ENCODING_16BIT; + values[4] = 0; + values[5] = 0; + mUnicodeCounter++; + } else { + int udhLength = 0; + if (langIndex != 0 || langShiftIndex != 0) { + udhLength = UDH_SEPTET_COST_LENGTH; + if (langIndex == 0 || langShiftIndex == 0) { + udhLength += UDH_SEPTET_COST_ONE_SHIFT_TABLE; + } else { + udhLength += UDH_SEPTET_COST_TWO_SHIFT_TABLES; + } + } + int msgCount; + if (minNumSeptets > (SmsConstants.MAX_USER_DATA_SEPTETS - udhLength)) { + if (udhLength == 0) { + udhLength = UDH_SEPTET_COST_LENGTH; + } + udhLength += UDH_SEPTET_COST_CONCATENATED_MESSAGE; + int septetsPerPart = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength; + msgCount = (minNumSeptets + septetsPerPart - 1) / septetsPerPart; + } else { + msgCount = 1; + } + values[0] = msgCount; + values[1] = minNumSeptets; + values[2] = (values[0] * (SmsConstants.MAX_USER_DATA_SEPTETS - udhLength)) - + minNumSeptets; + values[3] = SmsConstants.ENCODING_7BIT; + values[4] = (langIndex == 2 ? 3 : langIndex); // Portuguese is code 3, index 2 + values[5] = langShiftIndex; + assertEquals("minNumSeptetsWithHeader", minNumSeptetsWithHeader, + udhLength * msgCount + minNumSeptets); + mStatsCounters[langIndex * 4 + langShiftIndex]++; + } + } + + void printStats() { + Log.d(TAG, "Unicode selection count: " + mUnicodeCounter); + for (int i = 0; i < 12; i++) { + Log.d(TAG, "Language pair index " + i + " count: " + mStatsCounters[i]); + } + } + } + + @LargeTest + public void testCalcLengthMixed7bit() throws Exception { + StringBuilder sb = new StringBuilder(320); + CounterHelper ch = new CounterHelper(); + Random r = new Random(0x4321); // use the same seed for reproducibility + int[] expectedValues = new int[6]; + int[] origLockingShiftTables = GsmAlphabet.getEnabledLockingShiftTables(); + int[] origSingleShiftTables = GsmAlphabet.getEnabledSingleShiftTables(); + int enabledLanguagesTestCases = sEnabledSingleShiftTables.length; + long startTime = System.currentTimeMillis(); + + // Repeat for 10 test runs + for (int run = 0; run < 10; run++) { + sb.setLength(0); + ch.clear(); + int unicodeOnlyCount = 0; + + // Test incrementally from 1 to 320 character random messages + for (int i = 1; i < 320; i++) { + // 1% chance to add from each special character class, else add an ASCII char + int charClass = r.nextInt(100); + if (charClass >= sNumCharacterClasses) { + charClass = sNumCharacterClasses - 1; // last class is ASCII + } + int classLength = sCharacterClasses[charClass].length(); + char nextChar = sCharacterClasses[charClass].charAt(r.nextInt(classLength)); + sb.append(nextChar); + ch.addChar(charClass); + +// if (i % 20 == 0) { +// Log.d(TAG, "test string: " + sb); +// } + + // Test string against all combinations of enabled languages + boolean unicodeOnly = true; + for (int j = 0; j < enabledLanguagesTestCases; j++) { + GsmAlphabet.setEnabledSingleShiftTables(sEnabledSingleShiftTables[j]); + GsmAlphabet.setEnabledLockingShiftTables(sEnabledLockingShiftTables[j]); + ch.fillData(j, false, expectedValues, i); + if (expectedValues[3] == SmsConstants.ENCODING_7BIT) { + unicodeOnly = false; + } + callGsmLengthMethods(sb, false, expectedValues); + // test 7 bit only mode + ch.fillData(j, true, expectedValues, i); + callGsmLengthMethods(sb, true, expectedValues); + } + // after 10 iterations with a Unicode-only string, skip to next test string + // so we can spend more time testing strings that do encode into 7 bits. + if (unicodeOnly && ++unicodeOnlyCount == 10) { +// Log.d(TAG, "Unicode only: skipping to next test string"); + break; + } + } + } + ch.printStats(); + Log.d(TAG, "Completed in " + (System.currentTimeMillis() - startTime) + " ms"); + GsmAlphabet.setEnabledLockingShiftTables(origLockingShiftTables); + GsmAlphabet.setEnabledSingleShiftTables(origSingleShiftTables); + } + + private void callGsmLengthMethods(CharSequence msgBody, boolean use7bitOnly, + int[] expectedValues) + { + // deprecated GSM-specific method + int[] values = android.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly); + assertEquals("msgCount", expectedValues[0], values[0]); + assertEquals("codeUnitCount", expectedValues[1], values[1]); + assertEquals("codeUnitsRemaining", expectedValues[2], values[2]); + assertEquals("codeUnitSize", expectedValues[3], values[3]); + + int activePhone = TelephonyManager.getDefault().getPhoneType(); + if (TelephonyManager.PHONE_TYPE_GSM == activePhone) { + values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly); + assertEquals("msgCount", expectedValues[0], values[0]); + assertEquals("codeUnitCount", expectedValues[1], values[1]); + assertEquals("codeUnitsRemaining", expectedValues[2], values[2]); + assertEquals("codeUnitSize", expectedValues[3], values[3]); + } + + GsmAlphabet.TextEncodingDetails ted = + com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly); + assertEquals("msgCount", expectedValues[0], ted.msgCount); + assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount); + assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining); + assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize); + assertEquals("languageTable", expectedValues[4], ted.languageTable); + assertEquals("languageShiftTable", expectedValues[5], ted.languageShiftTable); + } + + private void callCdmaLengthMethods(CharSequence msgBody, boolean use7bitOnly, + int[] expectedValues) + { + int activePhone = TelephonyManager.getDefault().getPhoneType(); + if (TelephonyManager.PHONE_TYPE_CDMA == activePhone) { + int[] values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly); + assertEquals("msgCount", expectedValues[0], values[0]); + assertEquals("codeUnitCount", expectedValues[1], values[1]); + assertEquals("codeUnitsRemaining", expectedValues[2], values[2]); + assertEquals("codeUnitSize", expectedValues[3], values[3]); + } + + GsmAlphabet.TextEncodingDetails ted = + com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly); + assertEquals("msgCount", expectedValues[0], ted.msgCount); + assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount); + assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining); + assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize); + + ted = com.android.internal.telephony.cdma.sms.BearerData.calcTextEncodingDetails(msgBody, use7bitOnly); + assertEquals("msgCount", expectedValues[0], ted.msgCount); + assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount); + assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining); + assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java new file mode 100644 index 0000000..3757017 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java @@ -0,0 +1,219 @@ +/** + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.RetryManager; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class TelephonyUtilsTest extends TestCase { + + /** + * After first creating the RetryManager + * isRetryNeeded should be false and the time 0 + */ + @SmallTest + public void testRetryManagerEmpty() throws Exception { + RetryManager rm = new RetryManager(); + + assertEquals(0, rm.getRetryCount()); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.increaseRetryCount(); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.setRetryCount(123); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + assertTrue(rm.isRetryForever()); + assertTrue(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.setRetryCount(2); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + } + + /** + * A simple test and that randomization is doing something. + */ + @SmallTest + public void testRetryManagerSimplest() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure(1, 500, 10)); + int loops = 10; + int count = 0; + for (int i = 0; i < loops; i++) { + assertTrue(rm.isRetryNeeded()); + int time = rm.getRetryTimer(); + assertTrue((time >= 500) && (time < 600)); + if (time == 500) { + count++; + } + } + assertFalse(count == loops); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + rm.setRetryCount(0); + assertTrue(rm.isRetryNeeded()); + } + + /** + * Test multiple values using simple configuration. + */ + @SmallTest + public void testRetryManagerSimple() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure(3, 1000, 0)); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + assertEquals(rm.getRetryTimer(), 1000); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + } + + /** + * Test string configuration, simplest + */ + @SmallTest + public void testRetryManageSimpleString() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure("101")); + assertTrue(rm.isRetryNeeded()); + assertEquals(101, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + } + + /** + * Test infinite retires + */ + @SmallTest + public void testRetryManageInfinite() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure("1000,2000,3000,max_retries=infinite")); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(2000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + // All others are 3000 and isRetryNeeded is always true + for (int i=0; i < 100; i++) { + assertEquals(3000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + } + } + + /** + * Test string configuration using all options and with quotes. + */ + @SmallTest + public void testRetryManageString() throws Exception { + RetryManager rm = new RetryManager(); + int time; + + assertTrue(rm.configure( + "\"max_retries=4, default_randomization=100,1000, 2000 :200 , 3000\"")); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 1000) && (time < 1100)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 2000) && (time < 2200)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 3000) && (time < 3100)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 3000) && (time < 3100)); + + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + } + + /** + * Test string configuration using all options. + */ + @SmallTest + public void testRetryManageForever() throws Exception { + RetryManager rm = new RetryManager(); + int time; + + assertTrue(rm.configure("1000, 2000, 3000")); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(0, rm.getRetryCount()); + assertEquals(1000, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + rm.increaseRetryCount(); + rm.increaseRetryCount(); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertTrue(rm.isRetryForever()); + assertEquals(3, rm.getRetryCount()); + assertEquals(3000, rm.getRetryTimer()); + + rm.setRetryCount(1); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(1, rm.getRetryCount()); + assertEquals(2000, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + assertTrue(rm.isRetryNeeded()); + assertTrue(rm.isRetryForever()); + rm.resetRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(0, rm.getRetryCount()); + assertEquals(1000, rm.getRetryTimer()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java b/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java new file mode 100644 index 0000000..b8f0568 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import android.telephony.CellInfo; + +/** + * Stub class used for unit tests + */ + +public class TestPhoneNotifier implements PhoneNotifier { + public TestPhoneNotifier() { + } + + public void notifyPhoneState(Phone sender) { + } + + public void notifyServiceState(Phone sender) { + } + + public void notifyCellLocation(Phone sender) { + } + + public void notifySignalStrength(Phone sender) { + } + + public void notifyMessageWaitingChanged(Phone sender) { + } + + public void notifyCallForwardingChanged(Phone sender) { + } + + public void notifyDataConnection(Phone sender, String reason, String apnType) { + } + + public void notifyDataConnection(Phone sender, String reason, String apnType, + PhoneConstants.DataState state) { + } + + public void notifyDataConnectionFailed(Phone sender, String reason, String apnType) { + } + + public void notifyDataActivity(Phone sender) { + } + + public void notifyOtaspChanged(Phone sender, int otaspMode) { + } + + public void notifyCellInfo(Phone sender, CellInfo cellInfo) { + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/Wap230WspContentTypeTest.java b/tests/telephonytests/src/com/android/internal/telephony/Wap230WspContentTypeTest.java new file mode 100644 index 0000000..d31b294 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/Wap230WspContentTypeTest.java @@ -0,0 +1,853 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.WspTypeDecoder; +import com.android.internal.util.HexDump; + +import java.io.ByteArrayOutputStream; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +public class Wap230WspContentTypeTest extends TestCase { + + public static final Map<Integer, String> WELL_KNOWN_SHORT_MIME_TYPES + = new HashMap<Integer, String>(); + public static final Map<Integer, String> WELL_KNOWN_LONG_MIME_TYPES + = new HashMap<Integer, String>(); + public static final Map<Integer, String> WELL_KNOWN_PARAMETERS + = new HashMap<Integer, String>(); + + static { + WELL_KNOWN_SHORT_MIME_TYPES.put(0x00, "*/*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x01, "text/*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x02, "text/html"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x03, "text/plain"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x04, "text/x-hdml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x05, "text/x-ttml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x06, "text/x-vCalendar"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x07, "text/x-vCard"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x08, "text/vnd.wap.wml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x09, "text/vnd.wap.wmlscript"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x0A, "text/vnd.wap.wta-event"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x0B, "multipart/*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x0C, "multipart/mixed"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x0D, "multipart/form-data"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x0E, "multipart/byterantes"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x0F, "multipart/alternative"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x10, "application/*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x11, "application/java-vm"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x12, "application/x-www-form-urlencoded"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x13, "application/x-hdmlc"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x14, "application/vnd.wap.wmlc"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x15, "application/vnd.wap.wmlscriptc"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x16, "application/vnd.wap.wta-eventc"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x17, "application/vnd.wap.uaprof"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x18, "application/vnd.wap.wtls-ca-certificate"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x19, "application/vnd.wap.wtls-user-certificate"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x1A, "application/x-x509-ca-cert"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x1B, "application/x-x509-user-cert"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x1C, "image/*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x1D, "image/gif"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x1E, "image/jpeg"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x1F, "image/tiff"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x20, "image/png"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x21, "image/vnd.wap.wbmp"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x22, "application/vnd.wap.multipart.*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x23, "application/vnd.wap.multipart.mixed"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x24, "application/vnd.wap.multipart.form-data"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x25, "application/vnd.wap.multipart.byteranges"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x26, "application/vnd.wap.multipart.alternative"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x27, "application/xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x28, "text/xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x29, "application/vnd.wap.wbxml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x2A, "application/x-x968-cross-cert"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x2B, "application/x-x968-ca-cert"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x2C, "application/x-x968-user-cert"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x2D, "text/vnd.wap.si"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x2E, "application/vnd.wap.sic"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x2F, "text/vnd.wap.sl"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x30, "application/vnd.wap.slc"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x31, "text/vnd.wap.co"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x32, "application/vnd.wap.coc"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x33, "application/vnd.wap.multipart.related"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x34, "application/vnd.wap.sia"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x35, "text/vnd.wap.connectivity-xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x36, "application/vnd.wap.connectivity-wbxml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x37, "application/pkcs7-mime"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x38, "application/vnd.wap.hashed-certificate"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x39, "application/vnd.wap.signed-certificate"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x3A, "application/vnd.wap.cert-response"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x3B, "application/xhtml+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x3C, "application/wml+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x3D, "text/css"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x3E, "application/vnd.wap.mms-message"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x3F, "application/vnd.wap.rollover-certificate"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x40, "application/vnd.wap.locc+wbxml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x41, "application/vnd.wap.loc+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x42, "application/vnd.syncml.dm+wbxml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x43, "application/vnd.syncml.dm+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x44, "application/vnd.syncml.notification"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x45, "application/vnd.wap.xhtml+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x46, "application/vnd.wv.csp.cir"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x47, "application/vnd.oma.dd+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x48, "application/vnd.oma.drm.message"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x49, "application/vnd.oma.drm.content"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x4A, "application/vnd.oma.drm.rights+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x4B, "application/vnd.oma.drm.rights+wbxml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x4C, "application/vnd.wv.csp+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x4D, "application/vnd.wv.csp+wbxml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x4E, "application/vnd.syncml.ds.notification"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x4F, "audio/*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x50, "video/*"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x51, "application/vnd.oma.dd2+xml"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x52, "application/mikey"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x53, "application/vnd.oma.dcd"); + WELL_KNOWN_SHORT_MIME_TYPES.put(0x54, "application/vnd.oma.dcdc"); + + WELL_KNOWN_LONG_MIME_TYPES.put(0x0201, "application/vnd.uplanet.cacheop-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0202, "application/vnd.uplanet.signal"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0203, "application/vnd.uplanet.alert-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0204, "application/vnd.uplanet.list-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0205, "application/vnd.uplanet.listcmd-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0206, "application/vnd.uplanet.channel-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0207, "application/vnd.uplanet.provisioning-status-uri"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0208, "x-wap.multipart/vnd.uplanet.header-set"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0209, "application/vnd.uplanet.bearer-choice-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x020A, "application/vnd.phonecom.mmc-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x020B, "application/vnd.nokia.syncset+wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x020C, "image/x-up-wpng"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0300, "application/iota.mmc-wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0301, "application/iota.mmc-xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0302, "application/vnd.syncml+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0303, "application/vnd.syncml+wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0304, "text/vnd.wap.emn+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0305, "text/calendar"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0306, "application/vnd.omads-email+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0307, "application/vnd.omads-file+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0308, "application/vnd.omads-folder+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0309, "text/directory;profile=vCard"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x030A, "application/vnd.wap.emn+wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x030B, "application/vnd.nokia.ipdc-purchase-response"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x030C, "application/vnd.motorola.screen3+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x030D, "application/vnd.motorola.screen3+gzip"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x030E, "application/vnd.cmcc.setting+wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x030F, "application/vnd.cmcc.bombing+wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0310, "application/vnd.docomo.pf"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0311, "application/vnd.docomo.ub"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0312, "application/vnd.omaloc-supl-init"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0313, "application/vnd.oma.group-usage-list+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0314, "application/oma-directory+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0315, "application/vnd.docomo.pf2"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0316, "application/vnd.oma.drm.roap-trigger+wbxml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0317, "application/vnd.sbm.mid2"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0318, "application/vnd.wmf.bootstrap"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x0319, "application/vnc.cmcc.dcd+xml"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x031A, "application/vnd.sbm.cid"); + WELL_KNOWN_LONG_MIME_TYPES.put(0x031B, "application/vnd.oma.bcast.provisioningtrigger"); + + WELL_KNOWN_PARAMETERS.put(0x00, "Q"); + WELL_KNOWN_PARAMETERS.put(0x01, "Charset"); + WELL_KNOWN_PARAMETERS.put(0x02, "Level"); + WELL_KNOWN_PARAMETERS.put(0x03, "Type"); + WELL_KNOWN_PARAMETERS.put(0x07, "Differences"); + WELL_KNOWN_PARAMETERS.put(0x08, "Padding"); + WELL_KNOWN_PARAMETERS.put(0x09, "Type"); + WELL_KNOWN_PARAMETERS.put(0x0E, "Max-Age"); + WELL_KNOWN_PARAMETERS.put(0x10, "Secure"); + WELL_KNOWN_PARAMETERS.put(0x11, "SEC"); + WELL_KNOWN_PARAMETERS.put(0x12, "MAC"); + WELL_KNOWN_PARAMETERS.put(0x13, "Creation-date"); + WELL_KNOWN_PARAMETERS.put(0x14, "Modification-date"); + WELL_KNOWN_PARAMETERS.put(0x15, "Read-date"); + WELL_KNOWN_PARAMETERS.put(0x16, "Size"); + WELL_KNOWN_PARAMETERS.put(0x17, "Name"); + WELL_KNOWN_PARAMETERS.put(0x18, "Filename"); + WELL_KNOWN_PARAMETERS.put(0x19, "Start"); + WELL_KNOWN_PARAMETERS.put(0x1A, "Start-info"); + WELL_KNOWN_PARAMETERS.put(0x1B, "Comment"); + WELL_KNOWN_PARAMETERS.put(0x1C, "Domain"); + WELL_KNOWN_PARAMETERS.put(0x1D, "Path"); + + } + + final int WSP_DEFINED_SHORT_MIME_TYPE_COUNT = 85; + final int WSP_DEFINED_LONG_MIME_TYPE_COUNT = 85; + + private static final byte WSP_STRING_TERMINATOR = 0x00; + private static final byte WSP_SHORT_INTEGER_MASK = (byte) 0x80; + private static final byte WSP_LENGTH_QUOTE = 0x1F; + private static final byte WSP_QUOTE = 0x22; + + private static final short LONG_MIME_TYPE_OMA_DIRECTORY_XML = 0x0314; + private static final short LONG_MIME_TYPE_UNASSIGNED = 0x052C; + + private static final byte SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE = 0x3F; + private static final byte SHORT_MIME_TYPE_UNASSIGNED = 0x60; + + private static final String STRING_MIME_TYPE_ROLLOVER_CERTIFICATE + = "application/vnd.wap.rollover-certificate"; + + private static final byte TYPED_PARAM_Q = 0x00; + private static final byte TYPED_PARAM_DOMAIN = 0x1C; + private static final byte PARAM_UNASSIGNED = 0x42; + private static final byte PARAM_NO_VALUE = 0x00; + private static final byte TYPED_PARAM_SEC = 0x11; + private static final byte TYPED_PARAM_MAC = 0x12; + + public void testHasExpectedNumberOfShortMimeTypes() { + assertEquals(WSP_DEFINED_SHORT_MIME_TYPE_COUNT, WELL_KNOWN_SHORT_MIME_TYPES.size()); + } + + public void testHasExpectedNumberOfLongMimeTypes() { + assertEquals(WSP_DEFINED_LONG_MIME_TYPE_COUNT, WELL_KNOWN_LONG_MIME_TYPES.size()); + } + + public void testWellKnownShortIntegerMimeTypeValues() { + + for (int value : Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.keySet()) { + WspTypeDecoder unit = new WspTypeDecoder( + HexDump.toByteArray((byte) (value | WSP_SHORT_INTEGER_MASK))); + assertTrue(unit.decodeContentType(0)); + String mimeType = unit.getValueString(); + int wellKnownValue = (int) unit.getValue32(); + assertEquals(Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.get(value), mimeType); + assertEquals(value, wellKnownValue); + assertEquals(1, unit.getDecodedDataLength()); + } + } + + public void testWellKnownLongIntegerMimeTypeValues() { + byte headerLength = 3; + byte typeLength = 2; + for (int value : Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.keySet()) { + byte[] data = new byte[10]; + data[0] = headerLength; + data[1] = typeLength; + data[2] = (byte) (value >> 8); + data[3] = (byte) (value & 0xFF); + WspTypeDecoder unit = new WspTypeDecoder(data); + assertTrue(unit.decodeContentType(0)); + String mimeType = unit.getValueString(); + int wellKnownValue = (int) unit.getValue32(); + assertEquals(Wap230WspContentTypeTest.WELL_KNOWN_SHORT_MIME_TYPES.get(value), mimeType); + assertEquals(value, wellKnownValue); + assertEquals(4, unit.getDecodedDataLength()); + } + } + + public void testDecodeReturnsFalse_WhenOnlyAZeroBytePresent() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x00); + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertFalse(unit.decodeContentType(0)); + } + + public void testConstrainedMediaExtensionMedia() throws Exception { + + String testType = "application/wibble"; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(testType.getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + String mimeType = unit.getValueString(); + assertEquals(testType, mimeType); + assertEquals(-1, unit.getValue32()); + assertEquals(19, unit.getDecodedDataLength()); + } + + public void testGeneralFormShortLengthExtensionMedia() throws Exception { + + String testType = "12345678901234567890123456789"; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(testType.length() + 1); + out.write(testType.getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + assertEquals(testType, mimeType); + assertEquals(-1, unit.getValue32()); + assertEquals(31, unit.getDecodedDataLength()); + } + + public void testGeneralFormShortLengthWellKnownShortInteger() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x01); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + assertEquals(2, unit.getDecodedDataLength()); + + } + + public void testGeneralFormShortLengthWellKnownShortIntegerWithUnknownValue() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x01); + out.write(SHORT_MIME_TYPE_UNASSIGNED | WSP_SHORT_INTEGER_MASK); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + assertNull(mimeType); + assertEquals(SHORT_MIME_TYPE_UNASSIGNED, unit.getValue32()); + assertEquals(2, unit.getDecodedDataLength()); + + } + + public void testGeneralFormShortLengthWellKnownLongInteger() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(0x03); // header length + out.write(0x02); // type length (2 octets) + out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML >> 8); + out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML & 0xFF); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals("application/oma-directory+xml", mimeType); + assertEquals(LONG_MIME_TYPE_OMA_DIRECTORY_XML, unit.getValue32()); + assertEquals(4, unit.getDecodedDataLength()); + } + + public void testGeneralFormShortLengthWellKnownLongIntegerWithUnknownValue() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(0x03); // Value-length, short-length + out.write(0x02); // long-integer length (2 octets) + out.write(LONG_MIME_TYPE_UNASSIGNED >> 8); + out.write(LONG_MIME_TYPE_UNASSIGNED & 0xFF); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertNull(mimeType); + assertEquals(LONG_MIME_TYPE_UNASSIGNED, unit.getValue32()); + assertEquals(4, unit.getDecodedDataLength()); + + } + + public void testGeneralFormLengthQuoteWellKnownShortInteger() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(WSP_LENGTH_QUOTE); + out.write(0x01); // Length as UINTVAR + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + assertEquals(3, unit.getDecodedDataLength()); + + } + + public void testGeneralFormLengthQuoteWellKnownShortIntegerWithUnknownValue() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(WSP_LENGTH_QUOTE); + out.write(0x01); // Length as UINTVAR + out.write(SHORT_MIME_TYPE_UNASSIGNED | WSP_SHORT_INTEGER_MASK); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + assertNull(mimeType); + assertEquals(SHORT_MIME_TYPE_UNASSIGNED, unit.getValue32()); + assertEquals(3, unit.getDecodedDataLength()); + } + + public void testGeneralFormLengthQuoteWellKnownLongInteger() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(WSP_LENGTH_QUOTE); + out.write(0x03); // Length as UINTVAR + out.write(0x02); // long-integer length (2 octets) + out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML >> 8); + out.write(LONG_MIME_TYPE_OMA_DIRECTORY_XML & 0xFF); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals("application/oma-directory+xml", mimeType); + assertEquals(LONG_MIME_TYPE_OMA_DIRECTORY_XML, unit.getValue32()); + assertEquals(5, unit.getDecodedDataLength()); + + } + + public void testGeneralFormLengthQuoteWellKnownLongIntegerWithUnknownValue() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(WSP_LENGTH_QUOTE); + out.write(0x03); // Length as UINTVAR + out.write(0x02); // long-integer length (2 octets) + out.write(LONG_MIME_TYPE_UNASSIGNED >> 8); + out.write(LONG_MIME_TYPE_UNASSIGNED & 0xFF); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertNull(mimeType); + assertEquals(LONG_MIME_TYPE_UNASSIGNED, unit.getValue32()); + assertEquals(5, unit.getDecodedDataLength()); + + } + + public void testGeneralFormLengthQuoteExtensionMedia() throws Exception { + + String testType = "application/wibble"; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(WSP_LENGTH_QUOTE); + out.write(testType.length() + 1); // Length as UINTVAR + + out.write(testType.getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(testType, mimeType); + assertEquals(-1, unit.getValue32()); + assertEquals(21, unit.getDecodedDataLength()); + + } + + public void testGeneralFormLengthQuoteExtensionMediaWithNiceLongMimeType() throws Exception { + + String testType = + "01234567890123456789012345678901234567890123456789012345678901234567890123456789" + +"01234567890123456789012345678901234567890123456789012345678901234567890123456789"; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + out.write(WSP_LENGTH_QUOTE); + out.write(0x81); // Length as UINTVAR (161 decimal, 0xA1), 2 bytes + out.write(0x21); + + out.write(testType.getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(testType, mimeType); + assertEquals(-1, unit.getValue32()); + assertEquals(164, unit.getDecodedDataLength()); + + } + + public void testConstrainedMediaExtensionMediaWithSpace() throws Exception { + + String testType = " application/wibble"; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(testType.getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(testType, mimeType); + assertEquals(-1, unit.getValue32()); + assertEquals(20, unit.getDecodedDataLength()); + + } + + public void testTypedParamWellKnownShortIntegerNoValue() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x03); // Value-length, short-length + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(TYPED_PARAM_DOMAIN | WSP_SHORT_INTEGER_MASK); + out.write(PARAM_NO_VALUE); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + + assertEquals(4, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals(null, params.get("Domain")); + + } + + public void testTypedParamWellKnownShortIntegerTokenText() throws Exception { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x14); // Value-length, short-length + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(TYPED_PARAM_DOMAIN | WSP_SHORT_INTEGER_MASK); + out.write("wdstechnology.com".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + + assertEquals(out.toByteArray().length, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("wdstechnology.com", params.get("Domain")); + + } + + public void testTypedParamWellKnownLongIntegerTokenText() throws Exception { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x15); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(0x01); + out.write(TYPED_PARAM_DOMAIN); + out.write("wdstechnology.com".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + + assertEquals(22, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("wdstechnology.com", params.get("Domain")); + + } + + public void testTypedParamWellKnownShortIntegerQuotedText() throws Exception { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x15); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(TYPED_PARAM_DOMAIN | WSP_SHORT_INTEGER_MASK); + out.write(WSP_QUOTE); + out.write("wdstechnology.com".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(0x3F, unit.getValue32()); + assertEquals(22, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("wdstechnology.com", params.get("Domain")); + + } + + public void testTypedParamWellKnownShortIntegerCompactIntegerValue() { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x3); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(TYPED_PARAM_SEC | WSP_SHORT_INTEGER_MASK); + out.write(0x01 | WSP_SHORT_INTEGER_MASK); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(0x3F, unit.getValue32()); + assertEquals(4, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("1", params.get("SEC")); + + } + + public void testTypedParamWellKnownShortIntegerMultipleParameters() throws Exception { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x0B); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(TYPED_PARAM_SEC | WSP_SHORT_INTEGER_MASK); + out.write(0x01 | WSP_SHORT_INTEGER_MASK); + out.write(TYPED_PARAM_MAC | WSP_SHORT_INTEGER_MASK); + out.write(WSP_QUOTE); + out.write("imapc".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + assertEquals(12, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("1", params.get("SEC")); + assertEquals("imapc", params.get("MAC")); + } + + public void testUntypedParamIntegerValueShortInteger() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x0A); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write("MYPARAM".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); // EOS + out.write(0x45 | WSP_SHORT_INTEGER_MASK); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + assertEquals(11, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("69", params.get("MYPARAM")); + } + + public void testUntypedParamIntegerValueLongInteger() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x0C); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write("MYPARAM".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + out.write(0x02); // Short Length + out.write(0x42); // Long Integer byte 1 + out.write(0x69); // Long Integer byte 2 + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(0x3F, unit.getValue32()); + assertEquals(13, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("17001", params.get("MYPARAM")); + } + + public void testUntypedParamTextNoValue() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x0A); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write("MYPARAM".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + out.write(PARAM_NO_VALUE); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + assertEquals(11, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals(null, params.get("MYPARAM")); + + } + + public void testUntypedParamTextTokenText() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x11); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write("MYPARAM".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + out.write("myvalue".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + assertEquals(18, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("myvalue", params.get("MYPARAM")); + } + + public void testUntypedParamTextQuotedString() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x11); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write("MYPARAM".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + out.write(WSP_QUOTE); + out.write("myvalue".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + assertEquals(19, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("myvalue", params.get("MYPARAM")); + + } + + public void testDecodesReturnsFalse_ForParamWithMissingValue() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x09); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write("MYPARAM".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertFalse(unit.decodeContentType(0)); + } + + public void testTypedParamTextQValue() { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x04); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(TYPED_PARAM_Q); + out.write(0x83); // Q value byte 1 + out.write(0x31); // Q value byte 2 + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(0x3F, unit.getValue32()); + assertEquals(5, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("433", params.get("Q")); + + } + + public void testTypedParamUnassignedWellKnownShortIntegerTokenText() throws Exception { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x14); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(PARAM_UNASSIGNED | WSP_SHORT_INTEGER_MASK); + out.write("wdstechnology.com".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + + assertEquals(21, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("wdstechnology.com", params.get("unassigned/0x42")); + + } + + public void testTypedParamUnassignedWellKnownLongIntegerTokenText() throws Exception { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x15); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(0x01); // Short-length of well-known parameter token + out.write(PARAM_UNASSIGNED); + out.write("wdstechnology.com".getBytes("US-ASCII")); + out.write(WSP_STRING_TERMINATOR); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertTrue(unit.decodeContentType(0)); + + String mimeType = unit.getValueString(); + + assertEquals(STRING_MIME_TYPE_ROLLOVER_CERTIFICATE, mimeType); + assertEquals(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE, unit.getValue32()); + + assertEquals(22, unit.getDecodedDataLength()); + + Map<String, String> params = unit.getContentParameters(); + assertEquals("wdstechnology.com", params.get("unassigned/0x42")); + } + + public void testDecodesReturnsFalse_WhenParamValueNotTerminated() throws Exception { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x15); + out.write(SHORT_MIME_TYPE_ROLLOVER_CERTIFICATE | WSP_SHORT_INTEGER_MASK); + out.write(0x01); + out.write(PARAM_UNASSIGNED); + out.write("wdstechnology.com".getBytes("US-ASCII")); + + WspTypeDecoder unit = new WspTypeDecoder(out.toByteArray()); + assertFalse(unit.decodeContentType(0)); + } +}
\ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java new file mode 100644 index 0000000..d2faceb --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java @@ -0,0 +1,746 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.os.Parcel; +import android.telephony.SmsCbCmasInfo; +import android.telephony.SmsCbMessage; +import android.telephony.cdma.CdmaSmsCbProgramData; +import android.test.AndroidTestCase; +import android.util.Log; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.cdma.sms.BearerData; +import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; +import com.android.internal.telephony.cdma.sms.SmsEnvelope; +import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.util.BitwiseOutputStream; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * Test cases for basic SmsCbMessage operation for CDMA. + */ +public class CdmaSmsCbTest extends AndroidTestCase { + + /* Copy of private subparameter identifier constants from BearerData class. */ + private static final byte SUBPARAM_MESSAGE_IDENTIFIER = (byte) 0x00; + private static final byte SUBPARAM_USER_DATA = (byte) 0x01; + private static final byte SUBPARAM_PRIORITY_INDICATOR = (byte) 0x08; + private static final byte SUBPARAM_LANGUAGE_INDICATOR = (byte) 0x0D; + private static final byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12; + + /** + * Initialize a Parcel for an incoming CDMA cell broadcast. The caller will write the + * bearer data and then convert it to an SmsMessage. + * @param serviceCategory the CDMA service category + * @return the initialized Parcel + */ + private static Parcel createBroadcastParcel(int serviceCategory) { + Parcel p = Parcel.obtain(); + + p.writeInt(SmsEnvelope.TELESERVICE_NOT_SET); + p.writeByte((byte) 1); // non-zero for MESSAGE_TYPE_BROADCAST + p.writeInt(serviceCategory); + + // dummy address (RIL may generate a different dummy address for broadcasts) + p.writeInt(CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); // sAddress.digit_mode + p.writeInt(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); // sAddress.number_mode + p.writeInt(CdmaSmsAddress.TON_UNKNOWN); // sAddress.number_type + p.writeInt(CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY); // sAddress.number_plan + p.writeByte((byte) 0); // sAddress.number_of_digits + p.writeInt((byte) 0); // sSubAddress.subaddressType + p.writeByte((byte) 0); // sSubAddress.odd + p.writeByte((byte) 0); // sSubAddress.number_of_digits + return p; + } + + /** + * Initialize a BitwiseOutputStream with the CDMA bearer data subparameters except for + * user data. The caller will append the user data and add it to the parcel. + * @param messageId the 16-bit message identifier + * @param priority message priority + * @param language message language code + * @return the initialized BitwiseOutputStream + */ + private static BitwiseOutputStream createBearerDataStream(int messageId, int priority, + int language) throws BitwiseOutputStream.AccessException { + BitwiseOutputStream bos = new BitwiseOutputStream(10); + bos.write(8, SUBPARAM_MESSAGE_IDENTIFIER); + bos.write(8, 3); // length: 3 bytes + bos.write(4, BearerData.MESSAGE_TYPE_DELIVER); + bos.write(8, ((messageId >>> 8) & 0xff)); + bos.write(8, (messageId & 0xff)); + bos.write(1, 0); // no User Data Header + bos.write(3, 0); // reserved + + if (priority != -1) { + bos.write(8, SUBPARAM_PRIORITY_INDICATOR); + bos.write(8, 1); // length: 1 byte + bos.write(2, (priority & 0x03)); + bos.write(6, 0); // reserved + } + + if (language != -1) { + bos.write(8, SUBPARAM_LANGUAGE_INDICATOR); + bos.write(8, 1); // length: 1 byte + bos.write(8, (language & 0xff)); + } + + return bos; + } + + /** + * Write the bearer data array to the parcel, then return a new SmsMessage from the parcel. + * @param p the parcel containing the CDMA SMS headers + * @param bearerData the bearer data byte array to append to the parcel + * @return the new SmsMessage created from the parcel + */ + private static SmsMessage createMessageFromParcel(Parcel p, byte[] bearerData) { + p.writeInt(bearerData.length); + for (byte b : bearerData) { + p.writeByte(b); + } + p.setDataPosition(0); // reset position for reading + SmsMessage message = SmsMessage.newFromParcel(p); + p.recycle(); + return message; + } + + /** + * Create a parcel for an incoming CMAS broadcast, then return a new SmsMessage created + * from the parcel. + * @param serviceCategory the CDMA service category + * @param messageId the 16-bit message identifier + * @param priority message priority + * @param language message language code + * @param body message body + * @param cmasCategory CMAS category (or -1 to skip adding CMAS type 1 elements record) + * @param responseType CMAS response type + * @param severity CMAS severity + * @param urgency CMAS urgency + * @param certainty CMAS certainty + * @return the newly created SmsMessage object + */ + private static SmsMessage createCmasSmsMessage(int serviceCategory, int messageId, int priority, + int language, int encoding, String body, int cmasCategory, int responseType, + int severity, int urgency, int certainty) throws Exception { + BitwiseOutputStream cmasBos = new BitwiseOutputStream(10); + cmasBos.write(8, 0); // CMAE protocol version 0 + + if (body != null) { + cmasBos.write(8, 0); // Type 0 elements (alert text) + encodeBody(encoding, body, true, cmasBos); + } + + if (cmasCategory != SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN) { + cmasBos.write(8, 1); // Type 1 elements + cmasBos.write(8, 4); // length: 4 bytes + cmasBos.write(8, (cmasCategory & 0xff)); + cmasBos.write(8, (responseType & 0xff)); + cmasBos.write(4, (severity & 0x0f)); + cmasBos.write(4, (urgency & 0x0f)); + cmasBos.write(4, (certainty & 0x0f)); + cmasBos.write(4, 0); // pad to octet boundary + } + + byte[] cmasUserData = cmasBos.toByteArray(); + + Parcel p = createBroadcastParcel(serviceCategory); + BitwiseOutputStream bos = createBearerDataStream(messageId, priority, language); + + bos.write(8, SUBPARAM_USER_DATA); + bos.write(8, cmasUserData.length + 2); // add 2 bytes for msg_encoding and num_fields + bos.write(5, UserData.ENCODING_OCTET); + bos.write(8, cmasUserData.length); + bos.writeByteArray(cmasUserData.length * 8, cmasUserData); + bos.write(3, 0); // pad to byte boundary + + return createMessageFromParcel(p, bos.toByteArray()); + } + + /** + * Create a parcel for an incoming CDMA cell broadcast, then return a new SmsMessage created + * from the parcel. + * @param serviceCategory the CDMA service category + * @param messageId the 16-bit message identifier + * @param priority message priority + * @param language message language code + * @param encoding user data encoding method + * @param body the message body + * @return the newly created SmsMessage object + */ + private static SmsMessage createBroadcastSmsMessage(int serviceCategory, int messageId, + int priority, int language, int encoding, String body) throws Exception { + Parcel p = createBroadcastParcel(serviceCategory); + BitwiseOutputStream bos = createBearerDataStream(messageId, priority, language); + + bos.write(8, SUBPARAM_USER_DATA); + encodeBody(encoding, body, false, bos); + + return createMessageFromParcel(p, bos.toByteArray()); + } + + /** + * Append the message length, encoding, and body to the BearerData output stream. + * This is used for writing the User Data subparameter for non-CMAS broadcasts and for + * writing the alert text for CMAS broadcasts. + * @param encoding one of the CDMA UserData encoding values + * @param body the message body + * @param isCmasRecord true if this is a CMAS type 0 elements record; false for user data + * @param bos the BitwiseOutputStream to write to + * @throws Exception on any encoding error + */ + private static void encodeBody(int encoding, String body, boolean isCmasRecord, + BitwiseOutputStream bos) throws Exception { + if (encoding == UserData.ENCODING_7BIT_ASCII || encoding == UserData.ENCODING_IA5) { + int charCount = body.length(); + int recordBits = (charCount * 7) + 5; // add 5 bits for char set field + int recordOctets = (recordBits + 7) / 8; // round up to octet boundary + int padBits = (recordOctets * 8) - recordBits; + + if (!isCmasRecord) { + recordOctets++; // add 8 bits for num_fields + } + + bos.write(8, recordOctets); + bos.write(5, (encoding & 0x1f)); + + if (!isCmasRecord) { + bos.write(8, charCount); + } + + for (int i = 0; i < charCount; i++) { + bos.write(7, body.charAt(i)); + } + + bos.write(padBits, 0); // pad to octet boundary + } else if (encoding == UserData.ENCODING_GSM_7BIT_ALPHABET + || encoding == UserData.ENCODING_GSM_DCS) { + // convert to 7-bit packed encoding with septet count in index 0 of byte array + byte[] encodedBody = GsmAlphabet.stringToGsm7BitPacked(body); + + int charCount = encodedBody[0]; // septet count + int recordBits = (charCount * 7) + 5; // add 5 bits for char set field + int recordOctets = (recordBits + 7) / 8; // round up to octet boundary + int padBits = (recordOctets * 8) - recordBits; + + if (!isCmasRecord) { + recordOctets++; // add 8 bits for num_fields + if (encoding == UserData.ENCODING_GSM_DCS) { + recordOctets++; // add 8 bits for DCS (message type) + } + } + + bos.write(8, recordOctets); + bos.write(5, (encoding & 0x1f)); + + if (!isCmasRecord && encoding == UserData.ENCODING_GSM_DCS) { + bos.write(8, 0); // GSM DCS: 7 bit default alphabet, no msg class + } + + if (!isCmasRecord) { + bos.write(8, charCount); + } + byte[] bodySeptets = Arrays.copyOfRange(encodedBody, 1, encodedBody.length); + bos.writeByteArray(charCount * 7, bodySeptets); + bos.write(padBits, 0); // pad to octet boundary + } else if (encoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) { + // 6 bit packed encoding with 0x20 offset (ASCII 0x20 - 0x60) + int charCount = body.length(); + int recordBits = (charCount * 6) + 21; // add 21 bits for header fields + int recordOctets = (recordBits + 7) / 8; // round up to octet boundary + int padBits = (recordOctets * 8) - recordBits; + + bos.write(8, recordOctets); + + bos.write(5, (encoding & 0x1f)); + bos.write(8, UserData.IS91_MSG_TYPE_SHORT_MESSAGE); + bos.write(8, charCount); + + for (int i = 0; i < charCount; i++) { + bos.write(6, ((int) body.charAt(i) - 0x20)); + } + + bos.write(padBits, 0); // pad to octet boundary + } else { + byte[] encodedBody; + switch (encoding) { + case UserData.ENCODING_UNICODE_16: + encodedBody = body.getBytes("UTF-16BE"); + break; + + case UserData.ENCODING_SHIFT_JIS: + encodedBody = body.getBytes("Shift_JIS"); + break; + + case UserData.ENCODING_KOREAN: + encodedBody = body.getBytes("KSC5601"); + break; + + case UserData.ENCODING_LATIN_HEBREW: + encodedBody = body.getBytes("ISO-8859-8"); + break; + + case UserData.ENCODING_LATIN: + default: + encodedBody = body.getBytes("ISO-8859-1"); + break; + } + int charCount = body.length(); // use actual char count for num fields + int recordOctets = encodedBody.length + 1; // add 1 byte for encoding and pad bits + if (!isCmasRecord) { + recordOctets++; // add 8 bits for num_fields + } + bos.write(8, recordOctets); + bos.write(5, (encoding & 0x1f)); + if (!isCmasRecord) { + bos.write(8, charCount); + } + bos.writeByteArray(encodedBody.length * 8, encodedBody); + bos.write(3, 0); // pad to octet boundary + } + } + + private static final String TEST_TEXT = "This is a test CDMA cell broadcast message..." + + "678901234567890123456789012345678901234567890"; + + private static final String PRES_ALERT = + "THE PRESIDENT HAS ISSUED AN EMERGENCY ALERT. CHECK LOCAL MEDIA FOR MORE DETAILS"; + + private static final String EXTREME_ALERT = "FLASH FLOOD WARNING FOR SOUTH COCONINO COUNTY" + + " - NORTH CENTRAL ARIZONA UNTIL 415 PM MST"; + + private static final String SEVERE_ALERT = "SEVERE WEATHER WARNING FOR SOMERSET COUNTY" + + " - NEW JERSEY UNTIL 415 PM MST"; + + private static final String AMBER_ALERT = + "AMBER ALERT:Mountain View,CA VEH'07 Blue Honda Civic CA LIC 5ABC123"; + + private static final String MONTHLY_TEST_ALERT = "This is a test of the emergency alert system." + + " This is only a test. 89012345678901234567890"; + + private static final String IS91_TEXT = "IS91 SHORT MSG"; // max length 14 chars + + /** + * Verify that the SmsCbMessage has the correct values for CDMA. + * @param cbMessage the message to test + */ + private static void verifyCbValues(SmsCbMessage cbMessage) { + assertEquals(SmsCbMessage.MESSAGE_FORMAT_3GPP2, cbMessage.getMessageFormat()); + assertEquals(SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, cbMessage.getGeographicalScope()); + assertEquals(false, cbMessage.isEtwsMessage()); // ETWS on CDMA not currently supported + } + + private static void doTestNonEmergencyBroadcast(int encoding) throws Exception { + SmsMessage msg = createBroadcastSmsMessage(123, 456, BearerData.PRIORITY_NORMAL, + BearerData.LANGUAGE_ENGLISH, encoding, TEST_TEXT); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + verifyCbValues(cbMessage); + assertEquals(123, cbMessage.getServiceCategory()); + assertEquals(456, cbMessage.getSerialNumber()); + assertEquals(SmsCbMessage.MESSAGE_PRIORITY_NORMAL, cbMessage.getMessagePriority()); + assertEquals("en", cbMessage.getLanguageCode()); + assertEquals(TEST_TEXT, cbMessage.getMessageBody()); + assertEquals(false, cbMessage.isEmergencyMessage()); + assertEquals(false, cbMessage.isCmasMessage()); + } + + public void testNonEmergencyBroadcast7bitAscii() throws Exception { + doTestNonEmergencyBroadcast(UserData.ENCODING_7BIT_ASCII); + } + + public void testNonEmergencyBroadcast7bitGsm() throws Exception { + doTestNonEmergencyBroadcast(UserData.ENCODING_GSM_7BIT_ALPHABET); + } + + public void testNonEmergencyBroadcast16bitUnicode() throws Exception { + doTestNonEmergencyBroadcast(UserData.ENCODING_UNICODE_16); + } + + public void testNonEmergencyBroadcastIs91Extended() throws Exception { + // IS-91 doesn't support language or priority subparameters, max 14 chars text + SmsMessage msg = createBroadcastSmsMessage(987, 654, -1, -1, + UserData.ENCODING_IS91_EXTENDED_PROTOCOL, IS91_TEXT); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + verifyCbValues(cbMessage); + assertEquals(987, cbMessage.getServiceCategory()); + assertEquals(654, cbMessage.getSerialNumber()); + assertEquals(SmsCbMessage.MESSAGE_PRIORITY_NORMAL, cbMessage.getMessagePriority()); + assertEquals(null, cbMessage.getLanguageCode()); + assertEquals(IS91_TEXT, cbMessage.getMessageBody()); + assertEquals(false, cbMessage.isEmergencyMessage()); + assertEquals(false, cbMessage.isCmasMessage()); + } + + private static void doTestCmasBroadcast(int serviceCategory, int messageClass, String body) + throws Exception { + SmsMessage msg = createCmasSmsMessage( + serviceCategory, 1234, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, + UserData.ENCODING_7BIT_ASCII, body, -1, -1, -1, -1, -1); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + verifyCbValues(cbMessage); + assertEquals(serviceCategory, cbMessage.getServiceCategory()); + assertEquals(1234, cbMessage.getSerialNumber()); + assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority()); + assertEquals("en", cbMessage.getLanguageCode()); + assertEquals(body, cbMessage.getMessageBody()); + assertEquals(true, cbMessage.isEmergencyMessage()); + assertEquals(true, cbMessage.isCmasMessage()); + SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); + assertEquals(messageClass, cmasInfo.getMessageClass()); + assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN, cmasInfo.getCategory()); + assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, cmasInfo.getResponseType()); + assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN, cmasInfo.getSeverity()); + assertEquals(SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, cmasInfo.getUrgency()); + assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN, cmasInfo.getCertainty()); + } + + public void testCmasPresidentialAlert() throws Exception { + doTestCmasBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, + SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT, PRES_ALERT); + } + + public void testCmasExtremeAlert() throws Exception { + doTestCmasBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, + SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT, EXTREME_ALERT); + } + + public void testCmasSevereAlert() throws Exception { + doTestCmasBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, + SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT, SEVERE_ALERT); + } + + public void testCmasAmberAlert() throws Exception { + doTestCmasBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, + SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY, AMBER_ALERT); + } + + public void testCmasTestMessage() throws Exception { + doTestCmasBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, + SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST, MONTHLY_TEST_ALERT); + } + + public void testCmasExtremeAlertType1Elements() throws Exception { + SmsMessage msg = createCmasSmsMessage(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, + 5678, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, + UserData.ENCODING_7BIT_ASCII, EXTREME_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_ENV, + SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR, SmsCbCmasInfo.CMAS_SEVERITY_SEVERE, + SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + verifyCbValues(cbMessage); + assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, + cbMessage.getServiceCategory()); + assertEquals(5678, cbMessage.getSerialNumber()); + assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority()); + assertEquals("en", cbMessage.getLanguageCode()); + assertEquals(EXTREME_ALERT, cbMessage.getMessageBody()); + assertEquals(true, cbMessage.isEmergencyMessage()); + assertEquals(true, cbMessage.isCmasMessage()); + SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); + assertEquals(SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT, cmasInfo.getMessageClass()); + assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_ENV, cmasInfo.getCategory()); + assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR, cmasInfo.getResponseType()); + assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_SEVERE, cmasInfo.getSeverity()); + assertEquals(SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, cmasInfo.getUrgency()); + assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY, cmasInfo.getCertainty()); + } + + // VZW requirement is to discard message with unsupported charset. Verify that we return null + // for this unsupported character set. + public void testCmasUnsupportedCharSet() throws Exception { + SmsMessage msg = createCmasSmsMessage(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, + 12345, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, + UserData.ENCODING_GSM_DCS, EXTREME_ALERT, -1, -1, -1, -1, -1); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + assertNull("expected null for unsupported charset", cbMessage); + } + + // VZW requirement is to discard message with unsupported charset. Verify that we return null + // for this unsupported character set. + public void testCmasUnsupportedCharSet2() throws Exception { + SmsMessage msg = createCmasSmsMessage(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, + 67890, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, + UserData.ENCODING_KOREAN, EXTREME_ALERT, -1, -1, -1, -1, -1); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + assertNull("expected null for unsupported charset", cbMessage); + } + + // VZW requirement is to discard message without record type 0. The framework will decode it + // and the app will discard it. + public void testCmasNoRecordType0() throws Exception { + SmsMessage msg = createCmasSmsMessage( + SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 1234, + BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, + UserData.ENCODING_7BIT_ASCII, null, -1, -1, -1, -1, -1); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + verifyCbValues(cbMessage); + assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, + cbMessage.getServiceCategory()); + assertEquals(1234, cbMessage.getSerialNumber()); + assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority()); + assertEquals("en", cbMessage.getLanguageCode()); + assertEquals(null, cbMessage.getMessageBody()); + assertEquals(true, cbMessage.isEmergencyMessage()); + assertEquals(true, cbMessage.isCmasMessage()); + SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); + assertEquals(SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT, cmasInfo.getMessageClass()); + assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN, cmasInfo.getCategory()); + assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, cmasInfo.getResponseType()); + assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN, cmasInfo.getSeverity()); + assertEquals(SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, cmasInfo.getUrgency()); + assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN, cmasInfo.getCertainty()); + } + + // Make sure we don't throw an exception if we feed completely random data to BearerStream. + public void testRandomBearerStreamData() { + Random r = new Random(54321); + for (int run = 0; run < 1000; run++) { + int len = r.nextInt(140); + byte[] data = new byte[len]; + for (int i = 0; i < len; i++) { + data[i] = (byte) r.nextInt(256); + } + // Log.d("CdmaSmsCbTest", "trying random bearer data run " + run + " length " + len); + try { + int category = 0x0ff0 + r.nextInt(32); // half CMAS, half non-CMAS + Parcel p = createBroadcastParcel(category); + SmsMessage msg = createMessageFromParcel(p, data); + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + // with random input, cbMessage will almost always be null (log when it isn't) + if (cbMessage != null) { + Log.d("CdmaSmsCbTest", "success: " + cbMessage); + } + } catch (Exception e) { + Log.d("CdmaSmsCbTest", "exception thrown", e); + fail("Exception in decoder at run " + run + " length " + len + ": " + e); + } + } + } + + // Make sure we don't throw an exception if we put random data in the UserData subparam. + public void testRandomUserData() { + Random r = new Random(94040); + for (int run = 0; run < 1000; run++) { + int category = 0x0ff0 + r.nextInt(32); // half CMAS, half non-CMAS + Parcel p = createBroadcastParcel(category); + int len = r.nextInt(140); + // Log.d("CdmaSmsCbTest", "trying random user data run " + run + " length " + len); + + try { + BitwiseOutputStream bos = createBearerDataStream(r.nextInt(65536), r.nextInt(4), + r.nextInt(256)); + + bos.write(8, SUBPARAM_USER_DATA); + bos.write(8, len); + + for (int i = 0; i < len; i++) { + bos.write(8, r.nextInt(256)); + } + + SmsMessage msg = createMessageFromParcel(p, bos.toByteArray()); + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + } catch (Exception e) { + Log.d("CdmaSmsCbTest", "exception thrown", e); + fail("Exception in decoder at run " + run + " length " + len + ": " + e); + } + } + } + + /** + * Initialize a Parcel for incoming Service Category Program Data teleservice. The caller will + * write the bearer data and then convert it to an SmsMessage. + * @return the initialized Parcel + */ + private static Parcel createServiceCategoryProgramDataParcel() { + Parcel p = Parcel.obtain(); + + p.writeInt(SmsEnvelope.TELESERVICE_SCPT); + p.writeByte((byte) 0); // non-zero for MESSAGE_TYPE_BROADCAST + p.writeInt(0); + + // dummy address (RIL may generate a different dummy address for broadcasts) + p.writeInt(CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); // sAddress.digit_mode + p.writeInt(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); // sAddress.number_mode + p.writeInt(CdmaSmsAddress.TON_UNKNOWN); // sAddress.number_type + p.writeInt(CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY); // sAddress.number_plan + p.writeByte((byte) 0); // sAddress.number_of_digits + p.writeInt((byte) 0); // sSubAddress.subaddressType + p.writeByte((byte) 0); // sSubAddress.odd + p.writeByte((byte) 0); // sSubAddress.number_of_digits + return p; + } + + private static final String CAT_EXTREME_THREAT = "Extreme Threat to Life and Property"; + private static final String CAT_SEVERE_THREAT = "Severe Threat to Life and Property"; + private static final String CAT_AMBER_ALERTS = "AMBER Alerts"; + + public void testServiceCategoryProgramDataAddCategory() throws Exception { + Parcel p = createServiceCategoryProgramDataParcel(); + BitwiseOutputStream bos = createBearerDataStream(123, -1, -1); + + int categoryNameLength = CAT_EXTREME_THREAT.length(); + int subparamLengthBits = (53 + (categoryNameLength * 7)); + int subparamLengthBytes = (subparamLengthBits + 7) / 8; + int subparamPadBits = (subparamLengthBytes * 8) - subparamLengthBits; + + bos.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA); + bos.write(8, subparamLengthBytes); + bos.write(5, UserData.ENCODING_7BIT_ASCII); + + bos.write(4, CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY); + bos.write(8, (SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT >>> 8)); + bos.write(8, (SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT & 0xff)); + bos.write(8, BearerData.LANGUAGE_ENGLISH); + bos.write(8, 100); // max messages + bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT); + + bos.write(8, categoryNameLength); + for (int i = 0; i < categoryNameLength; i++) { + bos.write(7, CAT_EXTREME_THREAT.charAt(i)); + } + bos.write(subparamPadBits, 0); + + SmsMessage msg = createMessageFromParcel(p, bos.toByteArray()); + assertNotNull(msg); + msg.parseSms(); + List<CdmaSmsCbProgramData> programDataList = msg.getSmsCbProgramData(); + assertNotNull(programDataList); + assertEquals(1, programDataList.size()); + CdmaSmsCbProgramData programData = programDataList.get(0); + assertEquals(CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY, programData.getOperation()); + assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, programData.getCategory()); + assertEquals(CAT_EXTREME_THREAT, programData.getCategoryName()); + assertEquals("en", programData.getLanguageCode()); + assertEquals(100, programData.getMaxMessages()); + assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT, programData.getAlertOption()); + } + + public void testServiceCategoryProgramDataDeleteTwoCategories() throws Exception { + Parcel p = createServiceCategoryProgramDataParcel(); + BitwiseOutputStream bos = createBearerDataStream(456, -1, -1); + + int category1NameLength = CAT_SEVERE_THREAT.length(); + int category2NameLength = CAT_AMBER_ALERTS.length(); + + int subparamLengthBits = (101 + (category1NameLength * 7) + (category2NameLength * 7)); + int subparamLengthBytes = (subparamLengthBits + 7) / 8; + int subparamPadBits = (subparamLengthBytes * 8) - subparamLengthBits; + + bos.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA); + bos.write(8, subparamLengthBytes); + bos.write(5, UserData.ENCODING_7BIT_ASCII); + + bos.write(4, CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY); + bos.write(8, (SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT >>> 8)); + bos.write(8, (SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT & 0xff)); + bos.write(8, BearerData.LANGUAGE_ENGLISH); + bos.write(8, 0); // max messages + bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT); + + bos.write(8, category1NameLength); + for (int i = 0; i < category1NameLength; i++) { + bos.write(7, CAT_SEVERE_THREAT.charAt(i)); + } + + bos.write(4, CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY); + bos.write(8, (SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY >>> 8)); + bos.write(8, (SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY & 0xff)); + bos.write(8, BearerData.LANGUAGE_ENGLISH); + bos.write(8, 0); // max messages + bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT); + + bos.write(8, category2NameLength); + for (int i = 0; i < category2NameLength; i++) { + bos.write(7, CAT_AMBER_ALERTS.charAt(i)); + } + + bos.write(subparamPadBits, 0); + + SmsMessage msg = createMessageFromParcel(p, bos.toByteArray()); + assertNotNull(msg); + msg.parseSms(); + List<CdmaSmsCbProgramData> programDataList = msg.getSmsCbProgramData(); + assertNotNull(programDataList); + assertEquals(2, programDataList.size()); + + CdmaSmsCbProgramData programData = programDataList.get(0); + assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation()); + assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, programData.getCategory()); + assertEquals(CAT_SEVERE_THREAT, programData.getCategoryName()); + assertEquals("en", programData.getLanguageCode()); + assertEquals(0, programData.getMaxMessages()); + assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption()); + + programData = programDataList.get(1); + assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation()); + assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, + programData.getCategory()); + assertEquals(CAT_AMBER_ALERTS, programData.getCategoryName()); + assertEquals("en", programData.getLanguageCode()); + assertEquals(0, programData.getMaxMessages()); + assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption()); + } + + private static final byte[] CMAS_TEST_BEARER_DATA = { + 0x00, 0x03, 0x1C, 0x78, 0x00, 0x01, 0x59, 0x02, (byte) 0xB8, 0x00, 0x02, 0x10, (byte) 0xAA, + 0x68, (byte) 0xD3, (byte) 0xCD, 0x06, (byte) 0x9E, 0x68, 0x30, (byte) 0xA0, (byte) 0xE9, + (byte) 0x97, (byte) 0x9F, 0x44, 0x1B, (byte) 0xF3, 0x20, (byte) 0xE9, (byte) 0xA3, + 0x2A, 0x08, 0x7B, (byte) 0xF6, (byte) 0xED, (byte) 0xCB, (byte) 0xCB, 0x1E, (byte) 0x9C, + 0x3B, 0x10, 0x4D, (byte) 0xDF, (byte) 0x8B, 0x4E, + (byte) 0xCC, (byte) 0xA8, 0x20, (byte) 0xEC, (byte) 0xCB, (byte) 0xCB, (byte) 0xA2, 0x0A, + 0x7E, 0x79, (byte) 0xF4, (byte) 0xCB, (byte) 0xB5, 0x72, 0x0A, (byte) 0x9A, 0x34, + (byte) 0xF3, 0x41, (byte) 0xA7, (byte) 0x9A, 0x0D, (byte) 0xFB, (byte) 0xB6, 0x79, 0x41, + (byte) 0x85, 0x07, 0x4C, (byte) 0xBC, (byte) 0xFA, 0x2E, 0x00, 0x08, 0x20, 0x58, 0x38, + (byte) 0x88, (byte) 0x80, 0x10, 0x54, 0x06, 0x38, 0x20, 0x60, + 0x30, (byte) 0xA8, (byte) 0x81, (byte) 0x90, 0x20, 0x08 + }; + + // Test case for CMAS test message received on the Sprint network. + public void testDecodeRawBearerData() throws Exception { + Parcel p = createBroadcastParcel(SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE); + SmsMessage msg = createMessageFromParcel(p, CMAS_TEST_BEARER_DATA); + + SmsCbMessage cbMessage = msg.parseBroadcastSms(); + assertNotNull("expected non-null for bearer data", cbMessage); + assertEquals("geoScope", cbMessage.getGeographicalScope(), 1); + assertEquals("serialNumber", cbMessage.getSerialNumber(), 51072); + assertEquals("serviceCategory", cbMessage.getServiceCategory(), + SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE); + assertEquals("payload", cbMessage.getMessageBody(), + "This is a test of the Commercial Mobile Alert System. This is only a test."); + + SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); + assertNotNull("expected non-null for CMAS info", cmasInfo); + assertEquals("category", cmasInfo.getCategory(), SmsCbCmasInfo.CMAS_CATEGORY_OTHER); + assertEquals("responseType", cmasInfo.getResponseType(), + SmsCbCmasInfo.CMAS_RESPONSE_TYPE_NONE); + assertEquals("severity", cmasInfo.getSeverity(), SmsCbCmasInfo.CMAS_SEVERITY_SEVERE); + assertEquals("urgency", cmasInfo.getUrgency(), SmsCbCmasInfo.CMAS_URGENCY_EXPECTED); + assertEquals("certainty", cmasInfo.getCertainty(), SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java new file mode 100644 index 0000000..bb37b65 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java @@ -0,0 +1,887 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma.sms; + +import android.telephony.TelephonyManager; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.cdma.SmsMessage; +import com.android.internal.telephony.cdma.sms.BearerData; +import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; +import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; +import com.android.internal.util.BitwiseInputStream; +import com.android.internal.util.BitwiseOutputStream; +import com.android.internal.util.HexDump; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.util.Log; + +import java.util.ArrayList; + +public class CdmaSmsTest extends AndroidTestCase { + private final static String LOG_TAG = "XXX CdmaSmsTest XXX"; + + @SmallTest + public void testCdmaSmsAddrParsing() throws Exception { + CdmaSmsAddress addr = CdmaSmsAddress.parse("6502531000"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 10); + assertEquals(addr.origBytes.length, 10); + byte[] data = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10}; + for (int i = 0; i < data.length; i++) { + assertEquals(addr.origBytes[i], data[i]); + } + addr = CdmaSmsAddress.parse("(650) 253-1000"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 10); + assertEquals(addr.origBytes.length, 10); + byte[] data2 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10}; + for (int i = 0; i < data2.length; i++) { + assertEquals(addr.origBytes[i], data2[i]); + } + addr = CdmaSmsAddress.parse("650.253.1000"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 10); + assertEquals(addr.origBytes.length, 10); + byte[] data5 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10}; + for (int i = 0; i < data2.length; i++) { + assertEquals(addr.origBytes[i], data5[i]); + } + addr = CdmaSmsAddress.parse("(+886) 917 222 555"); + assertEquals(addr.ton, CdmaSmsAddress.TON_INTERNATIONAL_OR_IP); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 12); + assertEquals(addr.origBytes.length, 12); + byte[] data3 = {8, 8, 6, 9, 1, 7, 2, 2, 2, 5, 5, 5}; + for (int i = 0; i < data3.length; i++) { + assertEquals(addr.origBytes[i], data3[i]); + } + addr = CdmaSmsAddress.parse("(650) *253-1000 #600"); + byte[] data4 = {6, 5, 10, 11, 2, 5, 3, 1, 10, 10, 10, 12, 6, 10, 10}; + for (int i = 0; i < data4.length; i++) { + assertEquals(addr.origBytes[i], data4[i]); + } + String input = "x@y.com,a@b.com"; + addr = CdmaSmsAddress.parse(input); + assertEquals(addr.ton, CdmaSmsAddress.TON_NATIONAL_OR_EMAIL); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 15); + assertEquals(addr.origBytes.length, 15); + assertEquals(new String(addr.origBytes), input); + addr = CdmaSmsAddress.parse("foo bar"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 6); + assertEquals(addr.origBytes.length, 6); + assertEquals(new String(addr.origBytes), "foobar"); + addr = CdmaSmsAddress.parse("f\noo\tb a\rr"); + assertEquals(new String(addr.origBytes), "foobar"); + assertEquals(CdmaSmsAddress.parse("f\u0000oo bar"), null); + assertEquals(CdmaSmsAddress.parse("f\u0007oo bar"), null); + assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null); + assertEquals(CdmaSmsAddress.parse("f\u1ECFboo\u001fbar"), null); + assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null); + } + + @SmallTest + public void testUserData7bitGsm() throws Exception { + String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("Test standard SMS", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAscii() throws Exception { + String pdu = "0003100160010610262d5ab500"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("bjjj", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAsciiTwo() throws Exception { + String pdu = "00031001d00109104539b4d052ebb3d0"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("SMS Rulz", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserDataIa5() throws Exception { + String pdu = "00031002100109184539b4d052ebb3d0"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("SMS Rulz", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAsciiFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "Test standard SMS"; + userData.msgEncoding = UserData.ENCODING_7BIT_ASCII; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "Test \u007f standard \u0000 SMS"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals("Test standard SMS", revBearerData.userData.payloadStr); + userData.payloadStr = "Test \n standard \r SMS"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = ""; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitGsmFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "Test standard SMS"; + userData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "1234567"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = ""; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "12345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789012345678901234567890" + + "1234567890"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "Test \u007f illegal \u0000 SMS chars"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals("Test illegal SMS chars", revBearerData.userData.payloadStr); + userData.payloadStr = "More @ testing\nis great^|^~woohoo"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0xEE; + concatRef.msgCount = 2; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + userData.userDataHeader = smsHeader; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + SmsHeader decodedHeader = revBearerData.userData.userDataHeader; + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + } + + @SmallTest + public void testUserDataUtf16Feedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "\u0160u\u1E5B\u0301r\u1ECFg\uD835\uDC1At\u00E9\u4E002\u3042"; + userData.msgEncoding = UserData.ENCODING_UNICODE_16; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.msgEncoding = UserData.ENCODING_OCTET; + userData.msgEncodingSet = false; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "1234567"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = ""; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testMonolithicOne() throws Exception { + String pdu = "0003200010010410168d2002010503060812011101590501c706069706180000000701c108" + + "01c00901800a01e00b01030c01c00d01070e05039acc13880f018011020566"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals(bearerData.messageType, BearerData.MESSAGE_TYPE_SUBMIT); + assertEquals(bearerData.messageId, 1); + assertEquals(bearerData.priority, BearerData.PRIORITY_EMERGENCY); + assertEquals(bearerData.privacy, BearerData.PRIVACY_CONFIDENTIAL); + assertEquals(bearerData.userAckReq, true); + assertEquals(bearerData.readAckReq, true); + assertEquals(bearerData.deliveryAckReq, true); + assertEquals(bearerData.reportReq, false); + assertEquals(bearerData.numberOfMessages, 3); + assertEquals(bearerData.alert, BearerData.ALERT_HIGH_PRIO); + assertEquals(bearerData.language, BearerData.LANGUAGE_HEBREW); + assertEquals(bearerData.callbackNumber.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(bearerData.callbackNumber.numberMode, + CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(bearerData.callbackNumber.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberPlan, CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberOfDigits, 7); + assertEquals(bearerData.callbackNumber.address, "3598271"); + assertEquals(bearerData.displayMode, BearerData.DISPLAY_MODE_USER); + assertEquals(bearerData.depositIndex, 1382); + assertEquals(bearerData.userResponseCode, 5); + assertEquals(bearerData.msgCenterTimeStamp.year, 2008); + assertEquals(bearerData.msgCenterTimeStamp.month, 11); + assertEquals(bearerData.msgCenterTimeStamp.monthDay, 1); + assertEquals(bearerData.msgCenterTimeStamp.hour, 11); + assertEquals(bearerData.msgCenterTimeStamp.minute, 1); + assertEquals(bearerData.msgCenterTimeStamp.second, 59); + assertEquals(bearerData.validityPeriodAbsolute, null); + assertEquals(bearerData.validityPeriodRelative, 193); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.year, 1997); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.month, 5); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.monthDay, 18); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.hour, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.minute, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.second, 0); + assertEquals(bearerData.deferredDeliveryTimeRelative, 199); + assertEquals(bearerData.hasUserDataHeader, false); + assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII); + assertEquals(bearerData.userData.numFields, 2); + assertEquals(bearerData.userData.payloadStr, "hi"); + } + + @SmallTest + public void testMonolithicTwo() throws Exception { + String pdu = "0003200010010410168d200201050306081201110159050192060697061800000007013d0" + + "801c00901800a01e00b01030c01c00d01070e05039acc13880f018011020566"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals(bearerData.messageType, BearerData.MESSAGE_TYPE_SUBMIT); + assertEquals(bearerData.messageId, 1); + assertEquals(bearerData.priority, BearerData.PRIORITY_EMERGENCY); + assertEquals(bearerData.privacy, BearerData.PRIVACY_CONFIDENTIAL); + assertEquals(bearerData.userAckReq, true); + assertEquals(bearerData.readAckReq, true); + assertEquals(bearerData.deliveryAckReq, true); + assertEquals(bearerData.reportReq, false); + assertEquals(bearerData.numberOfMessages, 3); + assertEquals(bearerData.alert, BearerData.ALERT_HIGH_PRIO); + assertEquals(bearerData.language, BearerData.LANGUAGE_HEBREW); + assertEquals(bearerData.callbackNumber.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(bearerData.callbackNumber.numberMode, + CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(bearerData.callbackNumber.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberPlan, CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberOfDigits, 7); + assertEquals(bearerData.callbackNumber.address, "3598271"); + assertEquals(bearerData.displayMode, BearerData.DISPLAY_MODE_USER); + assertEquals(bearerData.depositIndex, 1382); + assertEquals(bearerData.userResponseCode, 5); + assertEquals(bearerData.msgCenterTimeStamp.year, 2008); + assertEquals(bearerData.msgCenterTimeStamp.month, 11); + assertEquals(bearerData.msgCenterTimeStamp.monthDay, 1); + assertEquals(bearerData.msgCenterTimeStamp.hour, 11); + assertEquals(bearerData.msgCenterTimeStamp.minute, 1); + assertEquals(bearerData.msgCenterTimeStamp.second, 59); + assertEquals(bearerData.validityPeriodAbsolute, null); + assertEquals(bearerData.validityPeriodRelative, 61); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.year, 1997); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.month, 5); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.monthDay, 18); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.hour, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.minute, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.second, 0); + assertEquals(bearerData.deferredDeliveryTimeRelative, 146); + assertEquals(bearerData.hasUserDataHeader, false); + assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII); + assertEquals(bearerData.userData.numFields, 2); + assertEquals(bearerData.userData.payloadStr, "hi"); + } + + @SmallTest + public void testUserDataHeaderConcatRefFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 55; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0xEE; + concatRef.msgCount = 2; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs, null); + UserData userData = new UserData(); + userData.payloadStr = "User Data Header (UDH) feedback test"; + userData.userDataHeader = smsHeader; + bearerData.userData = userData; + byte[] encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + decodedHeader = revBearerData.userData.userDataHeader; + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs, null); + } + + @SmallTest + public void testUserDataHeaderIllegalConcatRef() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 55; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0x10; + concatRef.msgCount = 0; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.isEightBits = false; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.msgCount = 1; + concatRef.seqNumber = 2; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.msgCount = 1; + concatRef.seqNumber = 0; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.msgCount = 2; + concatRef.seqNumber = 1; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef.msgCount, 2); + assertEquals(decodedHeader.concatRef.seqNumber, 1); + } + + @SmallTest + public void testUserDataHeaderMixedFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 42; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0x34; + concatRef.msgCount = 5; + concatRef.seqNumber = 2; + concatRef.isEightBits = false; + SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs(); + portAddrs.destPort = 88; + portAddrs.origPort = 66; + portAddrs.areEightBits = false; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + smsHeader.portAddrs = portAddrs; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs.destPort, portAddrs.destPort); + assertEquals(decodedHeader.portAddrs.origPort, portAddrs.origPort); + assertEquals(decodedHeader.portAddrs.areEightBits, portAddrs.areEightBits); + UserData userData = new UserData(); + userData.payloadStr = "User Data Header (UDH) feedback test"; + userData.userDataHeader = smsHeader; + bearerData.userData = userData; + byte[] encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + decodedHeader = revBearerData.userData.userDataHeader; + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs.destPort, portAddrs.destPort); + assertEquals(decodedHeader.portAddrs.origPort, portAddrs.origPort); + assertEquals(decodedHeader.portAddrs.areEightBits, portAddrs.areEightBits); + } + + @SmallTest + public void testReplyOption() throws Exception { + String pdu1 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87450080a0180"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Acknowledgement 1", bd1.userData.payloadStr); + assertEquals(true, bd1.userAckReq); + assertEquals(false, bd1.deliveryAckReq); + assertEquals(false, bd1.readAckReq); + assertEquals(false, bd1.reportReq); + String pdu2 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87490080a0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals("Test Acknowledgement 2", bd2.userData.payloadStr); + assertEquals(false, bd2.userAckReq); + assertEquals(true, bd2.deliveryAckReq); + assertEquals(false, bd2.readAckReq); + assertEquals(false, bd2.reportReq); + String pdu3 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d874d0080a0120"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals("Test Acknowledgement 3", bd3.userData.payloadStr); + assertEquals(false, bd3.userAckReq); + assertEquals(false, bd3.deliveryAckReq); + assertEquals(true, bd3.readAckReq); + assertEquals(false, bd3.reportReq); + String pdu4 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87510080a0110"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals("Test Acknowledgement 4", bd4.userData.payloadStr); + assertEquals(false, bd4.userAckReq); + assertEquals(false, bd4.deliveryAckReq); + assertEquals(false, bd4.readAckReq); + assertEquals(true, bd4.reportReq); + } + + @SmallTest + public void testReplyOptionFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test reply option"; + bearerData.userData = userData; + bearerData.userAckReq = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(true, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.userAckReq = false; + bearerData.deliveryAckReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(true, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.deliveryAckReq = false; + bearerData.readAckReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(true, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.readAckReq = false; + bearerData.reportReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(true, revBearerData.reportReq); + } + + @SmallTest + public void testNumberOfMessages() throws Exception { + // Note that the message text below does not properly reflect + // the message count. The author of these messages was + // apparently unaware that the values are bcd encoded, and the + // values being tested against (not the ones in the message + // text) are actually correct. + String pdu1 = "000310409001124896a794e07595f69f199540ea759a0dc8e00b0163"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Voice mail 99", bd1.userData.payloadStr); + assertEquals(63, bd1.numberOfMessages); + String pdu2 = "00031040900113489ea794e07595f69f199540ea759a0988c0600b0164"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals("Test Voice mail 100", bd2.userData.payloadStr); + assertEquals(64, bd2.numberOfMessages); + } + + @SmallTest + public void testCallbackNum() throws Exception { + String pdu1 = "00031040900112488ea794e070d436cb638bc5e035ce2f97900e06910431323334"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Callback nbr", bd1.userData.payloadStr); + assertEquals(CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR, bd1.callbackNumber.digitMode); + assertEquals(CdmaSmsAddress.TON_INTERNATIONAL_OR_IP, bd1.callbackNumber.ton); + assertEquals(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK, bd1.callbackNumber.numberMode); + assertEquals(CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY, bd1.callbackNumber.numberPlan); + assertEquals("1234", bd1.callbackNumber.address); + } + + @SmallTest + public void testCallbackNumDtmf() throws Exception { + String pdu1 = "00031002300109104539b4d052ebb3d00e07052d4c90a55080"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("SMS Rulz", bd1.userData.payloadStr); + assertEquals(CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF, bd1.callbackNumber.digitMode); + assertEquals(CdmaSmsAddress.TON_UNKNOWN, bd1.callbackNumber.ton); + assertEquals(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK, bd1.callbackNumber.numberMode); + assertEquals(CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN, bd1.callbackNumber.numberPlan); + assertEquals("5099214001", bd1.callbackNumber.address); + } + + @SmallTest + public void testCallbackNumFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test callback number"; + bearerData.userData = userData; + CdmaSmsAddress addr = new CdmaSmsAddress(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; + addr.ton = CdmaSmsAddress.TON_NATIONAL_OR_EMAIL; + addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; + addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN; + addr.address = "8005551212"; + addr.numberOfDigits = (byte)addr.address.length(); + bearerData.callbackNumber = addr; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + CdmaSmsAddress revAddr = revBearerData.callbackNumber; + assertEquals(addr.digitMode, revAddr.digitMode); + assertEquals(addr.ton, revAddr.ton); + assertEquals(addr.numberMode, revAddr.numberMode); + assertEquals(addr.numberPlan, revAddr.numberPlan); + assertEquals(addr.numberOfDigits, revAddr.numberOfDigits); + assertEquals(addr.address, revAddr.address); + addr.address = "8*55#1012"; + addr.numberOfDigits = (byte)addr.address.length(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + revAddr = revBearerData.callbackNumber; + assertEquals(addr.digitMode, revAddr.digitMode); + assertEquals(addr.numberOfDigits, revAddr.numberOfDigits); + assertEquals(addr.address, revAddr.address); + } + + @SmallTest + public void testPrivacyIndicator() throws Exception { + String pdu1 = "0003104090010c485f4194dfea34becf61b840090140"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.privacy, BearerData.PRIVACY_RESTRICTED); + String pdu2 = "0003104090010c485f4194dfea34becf61b840090180"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.privacy, BearerData.PRIVACY_CONFIDENTIAL); + String pdu3 = "0003104090010c485f4194dfea34becf61b8400901c0"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.privacy, BearerData.PRIVACY_SECRET); + } + + @SmallTest + public void testPrivacyIndicatorFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test privacy indicator"; + bearerData.userData = userData; + bearerData.privacy = BearerData.PRIVACY_SECRET; + bearerData.privacyIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.privacyIndicatorSet, true); + assertEquals(revBearerData.privacy, BearerData.PRIVACY_SECRET); + bearerData.privacy = BearerData.PRIVACY_RESTRICTED; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.privacy, BearerData.PRIVACY_RESTRICTED); + } + + @SmallTest + public void testMsgDeliveryAlert() throws Exception { + String pdu1 = "0003104090010d4866a794e07055965b91d040300c0100"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.alert, 0); + assertEquals(bd1.userData.payloadStr, "Test Alert 0"); + String pdu2 = "0003104090010d4866a794e07055965b91d140300c0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.alert, 1); + assertEquals(bd2.userData.payloadStr, "Test Alert 1"); + String pdu3 = "0003104090010d4866a794e07055965b91d240300c0180"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.alert, 2); + assertEquals(bd3.userData.payloadStr, "Test Alert 2"); + String pdu4 = "0003104090010d4866a794e07055965b91d340300c01c0"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.alert, 3); + assertEquals(bd4.userData.payloadStr, "Test Alert 3"); + String pdu5 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" + + "69ED979794187665E5D1028EFA7A6840E1062D3D39A900C028000"; + BearerData bd5 = BearerData.decode(HexDump.hexStringToByteArray(pdu5)); + assertEquals(bd5.alert, BearerData.ALERT_MEDIUM_PRIO); + assertEquals(bd5.userData.payloadStr, "test message delivery alert (with 8 bits)"); + String pdu6 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" + + "69ED979794187665E5D1028EFA7A6840C1062D3D39A900C00"; + BearerData bd6 = BearerData.decode(HexDump.hexStringToByteArray(pdu6)); + assertEquals(bd6.userData.payloadStr, "test message delivery alert (with 0 bits)"); + assertEquals(bd6.alertIndicatorSet, false); + } + + @SmallTest + public void testMiscParams() throws Exception { + String pdu1 = "00031002400109104539b4d052ebb3d00c0180"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.alert, BearerData.ALERT_MEDIUM_PRIO); + assertEquals(bd1.userData.payloadStr, "SMS Rulz"); + String pdu2 = "00031002500109104539b4d052ebb3d00801800901c0"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.priority, BearerData.PRIORITY_URGENT); + assertEquals(bd2.privacy, BearerData.PRIVACY_SECRET); + assertEquals(bd2.userData.payloadStr, "SMS Rulz"); + String pdu3 = "00031002600109104539b4d052ebb3d00901400c01c0"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.privacy, BearerData.PRIVACY_RESTRICTED); + assertEquals(bd3.alert, BearerData.ALERT_HIGH_PRIO); + assertEquals(bd3.userData.payloadStr, "SMS Rulz"); + String pdu4 = "00031002700109104539b4d052ebb3d00f0105"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.displayMode, BearerData.DISPLAY_MODE_IMMEDIATE); + assertEquals(bd4.userData.payloadStr, "SMS Rulz"); + } + @SmallTest + public void testMsgDeliveryAlertFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test message delivery alert"; + bearerData.userData = userData; + bearerData.alert = BearerData.ALERT_MEDIUM_PRIO; + bearerData.alertIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.alertIndicatorSet, true); + assertEquals(revBearerData.alert, bearerData.alert); + bearerData.alert = BearerData.ALERT_HIGH_PRIO; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.alertIndicatorSet, true); + assertEquals(revBearerData.alert, bearerData.alert); + } + + @SmallTest + public void testLanguageIndicator() throws Exception { + String pdu1 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0101"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.userData.payloadStr, "Test Language indicator"); + assertEquals(bd1.language, BearerData.LANGUAGE_ENGLISH); + String pdu2 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0106"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.userData.payloadStr, "Test Language indicator"); + assertEquals(bd2.language, BearerData.LANGUAGE_CHINESE); + } + + @SmallTest + public void testLanguageIndicatorFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test language indicator"; + bearerData.userData = userData; + bearerData.language = BearerData.LANGUAGE_ENGLISH; + bearerData.languageIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.languageIndicatorSet, true); + assertEquals(revBearerData.language, bearerData.language); + bearerData.language = BearerData.LANGUAGE_KOREAN; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.languageIndicatorSet, true); + assertEquals(revBearerData.language, bearerData.language); + } + + @SmallTest + public void testDisplayMode() throws Exception { + String pdu1 = "0003104090010c485f4194dfea34becf61b8400f0100"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.displayMode, BearerData.DISPLAY_MODE_IMMEDIATE); + String pdu2 = "0003104090010c485f4194dfea34becf61b8400f0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.displayMode, BearerData.DISPLAY_MODE_DEFAULT); + String pdu3 = "0003104090010c485f4194dfea34becf61b8400f0180"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.displayMode, BearerData.DISPLAY_MODE_USER); + } + + @SmallTest + public void testDisplayModeFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test display mode"; + bearerData.userData = userData; + bearerData.displayMode = BearerData.DISPLAY_MODE_IMMEDIATE; + bearerData.displayModeSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.displayModeSet, true); + assertEquals(revBearerData.displayMode, bearerData.displayMode); + bearerData.displayMode = BearerData.DISPLAY_MODE_USER; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.displayModeSet, true); + assertEquals(revBearerData.displayMode, bearerData.displayMode); + } + + @SmallTest + public void testIs91() throws Exception { + String pdu1 = "000320001001070c2039acc13880"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.callbackNumber.address, "3598271"); + String pdu4 = "000320001001080c283c314724b34e"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.userData.payloadStr, "ABCDEFG"); + } + + @SmallTest + public void testUserDataHeaderWithEightCharMsg() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 55; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0xEE; + concatRef.msgCount = 2; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + UserData userData = new UserData(); + userData.payloadStr = "01234567"; + userData.userDataHeader = smsHeader; + bearerData.userData = userData; + byte[] encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testFragmentText() throws Exception { + boolean isCdmaPhone = (TelephonyManager.getDefault().getPhoneType() == + TelephonyManager.PHONE_TYPE_CDMA); + // Valid 160 character ASCII text. + String text1 = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789["; + TextEncodingDetails ted = SmsMessage.calculateLength(text1, false); + assertEquals(ted.msgCount, 1); + assertEquals(ted.codeUnitCount, 160); + assertEquals(ted.codeUnitSize, 1); + if (isCdmaPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text1); + assertEquals(fragments.size(), 1); + } + + /* + This is not a valid test: we will never encode a single-segment + EMS message. Leaving this here, since we may try to support + this in the future. + + // Valid 160 character GSM text -- the last character is + // non-ASCII, and so this will currently generate a singleton + // EMS message, which is not necessarily supported by Verizon. + String text2 = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789\u00a3"; // Trailing pound-currency sign. + ted = SmsMessage.calculateLength(text2, false); + assertEquals(ted.msgCount, 1); + assertEquals(ted.codeUnitCount, 160); + assertEquals(ted.codeUnitSize, 1); + if (isCdmaPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text2); + assertEquals(fragments.size(), 1); + } + */ + + // *IF* we supported single-segment EMS, this text would result in a + // single fragment with 7-bit encoding. But we don't, so this text + // results in three fragments of 16-bit encoding. + String text2 = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789\u00a3"; // Trailing pound-currency sign. + ted = SmsMessage.calculateLength(text2, false); + assertEquals(3, ted.msgCount); + assertEquals(160, ted.codeUnitCount); + assertEquals(3, ted.codeUnitSize); + if (isCdmaPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text2); + assertEquals(3, fragments.size()); + } + + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java new file mode 100644 index 0000000..699f113 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java @@ -0,0 +1,1933 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF GSMTestHandler.ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.telephony.ServiceState; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.MmiCode; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.gsm.CallFailCause; +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.gsm.GSMTestHandler; +import com.android.internal.telephony.gsm.GsmMmiCode; +import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.test.SimulatedRadioControl; + +import java.util.List; + + +public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase { + private SimulatedRadioControl mRadioControl; + private GSMPhone mGSMPhone; + private GSMTestHandler mGSMTestHandler; + private Handler mHandler; + + private static final int EVENT_PHONE_STATE_CHANGED = 1; + private static final int EVENT_DISCONNECT = 2; + private static final int EVENT_RINGING = 3; + private static final int EVENT_CHANNEL_OPENED = 4; + private static final int EVENT_POST_DIAL = 5; + private static final int EVENT_DONE = 6; + private static final int EVENT_SSN = 7; + private static final int EVENT_MMI_INITIATE = 8; + private static final int EVENT_MMI_COMPLETE = 9; + private static final int EVENT_IN_SERVICE = 10; + private static final int SUPP_SERVICE_FAILED = 11; + private static final int SERVICE_STATE_CHANGED = 12; + private static final int EVENT_OEM_RIL_MESSAGE = 13; + public static final int ANY_MESSAGE = -1; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mGSMTestHandler = new GSMTestHandler(mContext); + + mGSMTestHandler.start(); + synchronized (mGSMTestHandler) { + do { + mGSMTestHandler.wait(); + } while (mGSMTestHandler.getGSMPhone() == null); + } + + mGSMPhone = mGSMTestHandler.getGSMPhone(); + mRadioControl = mGSMTestHandler.getSimulatedCommands(); + + mHandler = mGSMTestHandler.getHandler(); + mGSMPhone.registerForPreciseCallStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null); + mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null); + mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null); + + mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null); + + mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null); + mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null); + mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null); + mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null); + + mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null); + + // wait until we get phone in both voice and data service + Message msg; + ServiceState state; + + do { + msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + state = (ServiceState) ((AsyncResult) msg.obj).result; + } while (state.getState() != ServiceState.STATE_IN_SERVICE); + } + + @Override + protected void tearDown() throws Exception { + mRadioControl.shutdown(); + + mGSMPhone.unregisterForPreciseCallStateChanged(mHandler); + mGSMPhone.unregisterForNewRingingConnection(mHandler); + mGSMPhone.unregisterForDisconnect(mHandler); + mGSMPhone.setOnPostDialCharacter(mHandler, 0, null); + mGSMPhone.unregisterForSuppServiceNotification(mHandler); + mGSMPhone.unregisterForMmiInitiate(mHandler); + mGSMPhone.unregisterForMmiComplete(mHandler); + + mGSMPhone = null; + mRadioControl = null; + mHandler = null; + mGSMTestHandler.cleanup(); + + super.tearDown(); + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + public boolean isPerformanceOnly() { + return false; + } + + + //This test is causing the emulator screen to turn off. I don't understand + //why, but I'm removing it until we can figure it out. + public void brokenTestGeneral() throws Exception { + Connection cn; + Message msg; + AsyncResult ar; + + // IDLE state + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + assertFalse(mGSMPhone.canConference()); + + // One DIALING connection + + mRadioControl.setAutoProgressConnectingCall(false); + + mGSMPhone.dial("+13125551212"); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + + msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + /*do { + mGSMTestHandler.waitForMessage(ANY_MESSAGE); + } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/ + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DIALING, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // One ALERTING connection + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One ACTIVE connection + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One disconnected connection + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + assertFalse(mGSMPhone.canConference()); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing (INCOMING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + assertTrue(cn.isRinging()); + assertEquals(mGSMPhone.getRingingCall(), cn.getCall()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One mobile terminated active call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().size() == 1); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One disconnected (local hangup) call + + try { + Connection conn; + conn = mGSMPhone.getForegroundCall().getConnections().get(0); + conn.hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // One rejected call + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // Ringing call disconnects + + mRadioControl.triggerHangupForeground(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + // One Ringing Call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // One answered call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // one holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // one active call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // One disconnected call in the foreground slot + + mRadioControl.triggerHangupAll(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + // Test missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (msg.what != EVENT_DISCONNECT); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + + // Test incoming not missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + + try { + mGSMPhone.getForegroundCall().hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() + != Call.State.DISCONNECTED); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // + // Test held and hangup held calls + // + + // One ALERTING call + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + mRadioControl.progressConnectingCallState(); + mRadioControl.progressConnectingCallState(); + + // One ACTIVE call + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + // One ACTIVE call, one ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // One HOLDING call, one ACTIVE call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.canConference()); + + // Conference the two + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Hold the multiparty call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Multiparty call on hold, call waiting added + + mRadioControl.triggerRing("18005558355"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertFalse(mGSMPhone.canConference()); + + // Hangup conference call, ringing call still around + mGSMPhone.getBackgroundCall().hangup(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // Reject waiting call + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + } + + public void testOutgoingCallFailImmediately() throws Exception { + Message msg; + + // Test outgoing call fail-immediately edge case + // This happens when a call terminated before ever appearing in a + // call list + // This should land the immediately-failing call in the + // ForegroundCall list as an IDLE call + mRadioControl.setNextDialFailImmediately(true); + + Connection cn = mGSMPhone.dial("+13125551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testHangupOnOutgoing() throws Exception { + Connection cn; + Message msg; + + mRadioControl.setAutoProgressConnectingCall(false); + + // Test 1: local hangup in "DIALING" state + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 2: local hangup in "ALERTING" state + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 3: local immediate hangup before GSM index is + // assigned (CallTracker.hangupPendingMO case) + + mRadioControl.pauseResponses(); + + cn = mGSMPhone.dial("+13125551212"); + + cn.hangup(); + + mRadioControl.resumeResponses(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + + assertEquals(Connection.DisconnectCause.LOCAL, + mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause()); + } + + public void testHangupOnChannelClose() throws Exception { + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getConnections().isEmpty()); + + mRadioControl.shutdown(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + mGSMPhone.clearDisconnected(); + } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty()); + } + + public void testIncallMmiCallDeflection() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallWaiting() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (msg.what != EVENT_RINGING); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // at this point, the active call with number==18005551212 should + // have the gsm index of 2 + + mRadioControl.triggerRing("16505550100"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the call with number==16505550100 should + // have the gsm index of 1 + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE || + mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the active call with number==13125551212 should + // have the gsm index of 2 + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. This should not be allowed, and a + // Supplementary Service notification must be received. + mGSMPhone.handleInCallMmiCommands("11"); + + msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); + assertNotNull("Message Time Out", msg); + assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550100", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. + mGSMPhone.handleInCallMmiCommands("11"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallHold() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // simulate entering 2 followed by SEND: place all active calls + // (if any exist) on hold and accepts the other (held or waiting) + // call + + mGSMPhone.handleInCallMmiCommands("2"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // swap the active and holding calls + mGSMPhone.handleInCallMmiCommands("2"); + + msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // merge the calls + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size()); + + // at this point, we have an active conference call, with + // call(1) = 13125551212 and call(2) = 18005551212 + + // Simulate entering "23" followed by SEND: places all active call + // on hold except call 3. This should fail and a supplementary service + // failed notification should be received. + + mGSMPhone.handleInCallMmiCommands("23"); + + msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); + assertNotNull("Message Time Out", msg); + assertFalse("IncallMmiCallHold: separate should have failed!", msg == null); + + // Simulate entering "21" followed by SEND: places all active call + // on hold except call 1. + mGSMPhone.handleInCallMmiCommands("21"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + } + + public void testIncallMmiMultipartyServices() throws Exception { + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // dial another call + mGSMPhone.dial("18005551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("3"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(1).getAddress()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testCallIndex() throws Exception { + Message msg; + + // establish the first call + mGSMPhone.dial("16505550100"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + String baseNumber = "1650555010"; + + for (int i = 1; i < 6; i++) { + String number = baseNumber + i; + + mGSMPhone.dial(number); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) { + break; + } + + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // create an incoming call, this call should have the call index + // of 7 + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // hangup the background call and accept the ringing call + mGSMPhone.getBackgroundCall().hangup(); + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + mGSMPhone.handleInCallMmiCommands("17"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0). + getAddress()); + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("16"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testPostDialSequences() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,1234;5N8xx"); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("1234;5N8", cn.getRemainingPostDialString()); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('1', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('2', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('3', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('4', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('5', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WILD, ar.userObj); + cn.proceedAfterWildChar(",6;7"); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("6;78", cn.getRemainingPostDialString()); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('6', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('7', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('8', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + // Bogus chars at end should be ignored + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(0, msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.COMPLETE, + cn.getPostDialState()); + assertEquals(Connection.PostDialState.COMPLETE, ar.userObj); + } + + public void testPostDialCancel() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,N"); + mRadioControl.progressConnectingToActive(); + + mRadioControl.progressConnectingToActive(); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(',', msg.arg1); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + cn.cancelPostDial(); + + assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState()); + } + + public void testOutgoingCallFail() throws Exception { + Message msg; + /* + * normal clearing + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING); + mRadioControl.setAutoProgressConnectingCall(false); + + Connection cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * busy + */ + + mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.BUSY, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * congestion + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + + // Unlike the while loops above, this one waits + // for a "phone state changed" message back to "idle" + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (!(msg.what == EVENT_PHONE_STATE_CHANGED + && mGSMPhone.getState() == PhoneConstants.State.IDLE)); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.CONGESTION, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testSSNotification() throws Exception { + // MO + runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE); + runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING); + runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED); + + // MT + runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL); + runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT); + runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED); + } + + private void runTest(int type, int code) { + Message msg; + + mRadioControl.triggerSsn(type, code); + + msg = mGSMTestHandler.waitForMessage(EVENT_SSN); + assertNotNull("Message Time Out", msg); + AsyncResult ar = (AsyncResult) msg.obj; + + assertNull(ar.exception); + + SuppServiceNotification notification = + (SuppServiceNotification) ar.result; + + assertEquals(type, notification.notificationType); + assertEquals(code, notification.code); + } + + public void testUssd() throws Exception { + // Quick hack to work around a race condition in this test: + // We may initiate a USSD MMI before GSMPhone receives its initial + // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this + // event, it will cancel the just issued USSD MMI, which we don't + // want. So sleep a little first. + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + // do nothing + } + + verifyNormal(); + verifyCancel(); + varifyNetworkInitiated(); + } + + private void varifyNetworkInitiated() { + Message msg; + AsyncResult ar; + MmiCode mmi; + + // Receive an incoming NOTIFY + mRadioControl.triggerIncomingUssd("0", "NOTIFY message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and send response + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding..."); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + GsmMmiCode gsmMmi = (GsmMmiCode) mmi; + assertTrue(gsmMmi.isPendingUSSD()); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and cancel + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mmi.cancel(); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + + List mmiList = mGSMPhone.getPendingMmiCodes(); + assertEquals(0, mmiList.size()); + } + + private void verifyNormal() throws CallStateException { + Message msg; + AsyncResult ar; + MmiCode mmi; + + mGSMPhone.dial("#646#"); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + assertEquals(MmiCode.State.COMPLETE, mmi.getState()); + } + + + private void verifyCancel() throws CallStateException { + /** + * This case makes an assumption that dial() will add the USSD + * to the "pending MMI codes" list before it returns. This seems + * like reasonable semantics. It also assumes that the USSD + * request in question won't complete until we get back to the + * event loop, thus cancel() is safe. + */ + Message msg; + + mGSMPhone.dial("#646#"); + + List<? extends MmiCode> pendingMmis = mGSMPhone.getPendingMmiCodes(); + + assertEquals(1, pendingMmis.size()); + + MmiCode mmi = pendingMmis.get(0); + assertTrue(mmi.isCancelable()); + mmi.cancel(); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + AsyncResult ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + } + + public void testRilHooks() throws Exception { + // + // These test cases all assume the RIL OEM hooks + // just echo back their input + // + + Message msg; + AsyncResult ar; + + // null byte array + + mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((byte[]) (ar.result)).length); + assertNull(ar.exception); + + // byte array with data + + mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"), + mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8")); + assertNull(ar.exception); + + // null strings + + mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestStrings(new String[0], + mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((String[]) (ar.result)).length); + assertNull(ar.exception); + + // Strings with data + + String s[] = new String[1]; + + s[0] = "Hello"; + + mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", ((String[]) (ar.result))[0]); + assertEquals(1, ((String[]) (ar.result)).length); + assertNull(ar.exception); + } + + public void testMmi() throws Exception { + mRadioControl.setAutoProgressConnectingCall(false); + + // "valid" MMI sequences + runValidMmi("*#67#", false); + runValidMmi("##43*11#", false); + runValidMmi("#33*1234*11#", false); + runValidMmi("*21*6505551234**5#", false); + runValidMmi("**03**1234*4321*4321#", false); + // pound string + runValidMmi("5308234092307540923#", true); + // short code + runValidMmi("22", true); + // as part of call setup + runValidMmiWithConnect("*31#6505551234"); + + // invalid MMI sequences + runNotMmi("6505551234"); + runNotMmi("1234#*12#34566654"); + runNotMmi("*#*#12#*"); + } + + private void runValidMmi(String dialString, boolean cancelable) throws CallStateException { + Connection c = mGSMPhone.dial(dialString); + assertNull(c); + Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + // Should not be cancelable. + AsyncResult ar = (AsyncResult) msg.obj; + MmiCode mmi = (MmiCode) ar.result; + assertEquals(cancelable, mmi.isCancelable()); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + } + + private void runValidMmiWithConnect(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } + + private void hangup(Connection cn) throws CallStateException { + cn.hangup(); + + mRadioControl.resumeResponses(); + assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT)); + + } + + private void runNotMmi(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java new file mode 100644 index 0000000..fb8a5d9 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.content.Context; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.TestPhoneNotifier; + +/** + * This class creates a HandlerThread which waits for the various messages. + */ +public class GSMTestHandler extends HandlerThread implements Handler.Callback { + + private Handler mHandler; + private Message mCurrentMessage; + + private Boolean mMsgConsumed; + private SimulatedCommands sc; + private GSMPhone mGSMPhone; + private Context mContext; + + private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000; + + public GSMTestHandler(Context context) { + super("GSMPhoneTest"); + mMsgConsumed = false; + mContext = context; + } + + @Override + protected void onLooperPrepared() { + sc = new SimulatedCommands(); + mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true); + mHandler = new Handler(getLooper(), this); + synchronized (this) { + notifyAll(); + } + } + + public boolean handleMessage(Message msg) { + synchronized (this) { + mCurrentMessage = msg; + this.notifyAll(); + while(!mMsgConsumed) { + try { + this.wait(); + } catch (InterruptedException e) {} + } + mMsgConsumed = false; + } + return true; + } + + + public void cleanup() { + Looper looper = getLooper(); + if (looper != null) looper.quit(); + mHandler = null; + } + + public Handler getHandler() { + return mHandler; + } + + public SimulatedCommands getSimulatedCommands() { + return sc; + } + + public GSMPhone getGSMPhone() { + return mGSMPhone; + } + + public Message waitForMessage(int code) { + Message msg; + while(true) { + msg = null; + synchronized (this) { + try { + this.wait(FAIL_TIMEOUT_MILLIS); + } catch (InterruptedException e) { + } + + // Check if timeout has occurred. + if (mCurrentMessage != null) { + // Consume the message + msg = Message.obtain(); + msg.copyFrom(mCurrentMessage); + mCurrentMessage = null; + mMsgConsumed = true; + this.notifyAll(); + } + } + if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg; + } + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsCbTest.java new file mode 100644 index 0000000..82c6944 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsCbTest.java @@ -0,0 +1,758 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.telephony.SmsCbEtwsInfo; +import android.telephony.SmsCbLocation; +import android.telephony.SmsCbMessage; +import android.test.AndroidTestCase; +import android.util.Log; + +import com.android.internal.telephony.IccUtils; + +import java.util.Random; + +/** + * Test cases for basic SmsCbMessage operations + */ +public class GsmSmsCbTest extends AndroidTestCase { + + private static final String TAG = "GsmSmsCbTest"; + + private static final SmsCbLocation sTestLocation = new SmsCbLocation("94040", 1234, 5678); + + private static SmsCbMessage createFromPdu(byte[] pdu) { + try { + SmsCbHeader header = new SmsCbHeader(pdu); + byte[][] pdus = new byte[1][]; + pdus[0] = pdu; + return GsmSmsCbMessage.createSmsCbMessage(header, sTestLocation, pdus); + } catch (IllegalArgumentException e) { + return null; + } + } + + private static void doTestGeographicalScopeValue(byte[] pdu, byte b, int expectedGs) { + pdu[0] = b; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected geographical scope decoded", expectedGs, msg + .getGeographicalScope()); + } + + public void testCreateNullPdu() { + SmsCbMessage msg = createFromPdu(null); + assertNull("createFromPdu(byte[] with null pdu should return null", msg); + } + + public void testCreateTooShortPdu() { + byte[] pdu = new byte[4]; + SmsCbMessage msg = createFromPdu(pdu); + + assertNull("createFromPdu(byte[] with too short pdu should return null", msg); + } + + public void testGetGeographicalScope() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41, + (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6, + (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70, + (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, + (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, + (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75, + (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69, + (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00 + }; + + doTestGeographicalScopeValue(pdu, (byte)0x00, + SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE); + doTestGeographicalScopeValue(pdu, (byte)0x40, SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE); + doTestGeographicalScopeValue(pdu, (byte)0x80, SmsCbMessage.GEOGRAPHICAL_SCOPE_LA_WIDE); + doTestGeographicalScopeValue(pdu, (byte)0xC0, SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE); + } + + public void testGetGeographicalScopeUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40, + + (byte)0x01, + + (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, + (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, + (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C, + (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C, + (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A, + (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, + (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, + (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x34 + }; + + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected geographical scope decoded", + SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE, msg.getGeographicalScope()); + } + + public void testGetMessageBody7Bit() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41, + (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6, + (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70, + (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, + (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, + (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75, + (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69, + (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A GSM default alphabet message with carriage return padding", + msg.getMessageBody()); + } + + public void testGetMessageBody7BitUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40, + + (byte)0x01, + + (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, + (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, + (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C, + (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C, + (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A, + (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, + (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, + (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x34 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A GSM default alphabet message with carriage return padding", + msg.getMessageBody()); + } + + public void testGetMessageBody7BitMultipageUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x01, (byte)0xC0, (byte)0x00, (byte)0x40, + + (byte)0x02, + + (byte)0xC6, (byte)0xB4, (byte)0x7C, (byte)0x4E, (byte)0x07, (byte)0xC1, + (byte)0xC3, (byte)0xE7, (byte)0xF2, (byte)0xAA, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, + (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, + (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x0A, + + (byte)0xD3, (byte)0xF2, (byte)0xF8, (byte)0xED, (byte)0x26, (byte)0x83, + (byte)0xE0, (byte)0xE1, (byte)0x73, (byte)0xB9, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, + (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, + (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x0A + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected multipage 7-bit string decoded", + "First page+Second page", + msg.getMessageBody()); + } + + public void testGetMessageBody7BitFull() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41, + (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6, + (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70, + (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, + (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xC4, (byte)0xE5, + (byte)0xB4, (byte)0xFB, (byte)0x0C, (byte)0x2A, (byte)0xE3, (byte)0xC3, (byte)0x63, + (byte)0x3A, (byte)0x3B, (byte)0x0F, (byte)0xCA, (byte)0xCD, (byte)0x40, (byte)0x63, + (byte)0x74, (byte)0x58, (byte)0x1E, (byte)0x1E, (byte)0xD3, (byte)0xCB, (byte)0xF2, + (byte)0x39, (byte)0x88, (byte)0xFD, (byte)0x76, (byte)0x9F, (byte)0x59, (byte)0xA0, + (byte)0x76, (byte)0x39, (byte)0xEC, (byte)0x4E, (byte)0xBB, (byte)0xCF, (byte)0x20, + (byte)0x3A, (byte)0xBA, (byte)0x2C, (byte)0x2F, (byte)0x83, (byte)0xD2, (byte)0x73, + (byte)0x90, (byte)0xFB, (byte)0x0D, (byte)0x82, (byte)0x87, (byte)0xC9, (byte)0xE4, + (byte)0xB4, (byte)0xFB, (byte)0x1C, (byte)0x02 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals( + "Unexpected 7-bit string decoded", + "A GSM default alphabet message being exactly 93 characters long, " + + "meaning there is no padding!", + msg.getMessageBody()); + } + + public void testGetMessageBody7BitFullUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40, + + (byte)0x01, + + (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, + (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, + (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C, + (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C, + (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xC4, (byte)0xE5, (byte)0xB4, + (byte)0xFB, (byte)0x0C, (byte)0x2A, (byte)0xE3, (byte)0xC3, (byte)0x63, + (byte)0x3A, (byte)0x3B, (byte)0x0F, (byte)0xCA, (byte)0xCD, (byte)0x40, + (byte)0x63, (byte)0x74, (byte)0x58, (byte)0x1E, (byte)0x1E, (byte)0xD3, + (byte)0xCB, (byte)0xF2, (byte)0x39, (byte)0x88, (byte)0xFD, (byte)0x76, + (byte)0x9F, (byte)0x59, (byte)0xA0, (byte)0x76, (byte)0x39, (byte)0xEC, + (byte)0x4E, (byte)0xBB, (byte)0xCF, (byte)0x20, (byte)0x3A, (byte)0xBA, + (byte)0x2C, (byte)0x2F, (byte)0x83, (byte)0xD2, (byte)0x73, (byte)0x90, + (byte)0xFB, (byte)0x0D, (byte)0x82, (byte)0x87, (byte)0xC9, (byte)0xE4, + (byte)0xB4, (byte)0xFB, (byte)0x1C, (byte)0x02, + + (byte)0x52 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals( + "Unexpected 7-bit string decoded", + "A GSM default alphabet message being exactly 93 characters long, " + + "meaning there is no padding!", + msg.getMessageBody()); + } + + public void testGetMessageBody7BitWithLanguage() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x04, (byte)0x11, (byte)0x41, + (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6, + (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70, + (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, + (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, + (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75, + (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69, + (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A GSM default alphabet message with carriage return padding", + msg.getMessageBody()); + + assertEquals("Unexpected language indicator decoded", "es", msg.getLanguageCode()); + } + + public void testGetMessageBody7BitWithLanguageInBody() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x10, (byte)0x11, (byte)0x73, + (byte)0x7B, (byte)0x23, (byte)0x08, (byte)0x3A, (byte)0x4E, (byte)0x9B, (byte)0x20, + (byte)0x72, (byte)0xD9, (byte)0x1C, (byte)0xAE, (byte)0xB3, (byte)0xE9, (byte)0xA0, + (byte)0x30, (byte)0x1B, (byte)0x8E, (byte)0x0E, (byte)0x8B, (byte)0xCB, (byte)0x74, + (byte)0x50, (byte)0xBB, (byte)0x3C, (byte)0x9F, (byte)0x87, (byte)0xCF, (byte)0x65, + (byte)0xD0, (byte)0x3D, (byte)0x4D, (byte)0x47, (byte)0x83, (byte)0xC6, (byte)0x61, + (byte)0xB9, (byte)0x3C, (byte)0x1D, (byte)0x3E, (byte)0x97, (byte)0x41, (byte)0xF2, + (byte)0x32, (byte)0xBD, (byte)0x2E, (byte)0x77, (byte)0x83, (byte)0xE0, (byte)0x61, + (byte)0x32, (byte)0x39, (byte)0xED, (byte)0x3E, (byte)0x37, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A GSM default alphabet message with carriage return padding", + msg.getMessageBody()); + + assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode()); + } + + public void testGetMessageBody7BitWithLanguageInBodyUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x10, + + (byte)0x01, + + (byte)0x73, (byte)0x7B, (byte)0x23, (byte)0x08, (byte)0x3A, (byte)0x4E, + (byte)0x9B, (byte)0x20, (byte)0x72, (byte)0xD9, (byte)0x1C, (byte)0xAE, + (byte)0xB3, (byte)0xE9, (byte)0xA0, (byte)0x30, (byte)0x1B, (byte)0x8E, + (byte)0x0E, (byte)0x8B, (byte)0xCB, (byte)0x74, (byte)0x50, (byte)0xBB, + (byte)0x3C, (byte)0x9F, (byte)0x87, (byte)0xCF, (byte)0x65, (byte)0xD0, + (byte)0x3D, (byte)0x4D, (byte)0x47, (byte)0x83, (byte)0xC6, (byte)0x61, + (byte)0xB9, (byte)0x3C, (byte)0x1D, (byte)0x3E, (byte)0x97, (byte)0x41, + (byte)0xF2, (byte)0x32, (byte)0xBD, (byte)0x2E, (byte)0x77, (byte)0x83, + (byte)0xE0, (byte)0x61, (byte)0x32, (byte)0x39, (byte)0xED, (byte)0x3E, + (byte)0x37, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x37 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A GSM default alphabet message with carriage return padding", + msg.getMessageBody()); + + assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode()); + } + + public void testGetMessageBody8Bit() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x44, (byte)0x11, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41, + (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("8-bit message body should be empty", "", msg.getMessageBody()); + } + + public void testGetMessageBodyUcs2() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x48, (byte)0x11, (byte)0x00, + (byte)0x41, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x55, (byte)0x00, (byte)0x43, + (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x20, (byte)0x00, + (byte)0x6D, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73, + (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65, (byte)0x00, + (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x6E, + (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x69, (byte)0x00, + (byte)0x6E, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x67, + (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x20, (byte)0x04, + (byte)0x34, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68, + (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61, (byte)0x00, + (byte)0x63, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x72, + (byte)0x00, (byte)0x0D, (byte)0x00, (byte)0x0D + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A UCS2 message containing a \u0434 character", msg.getMessageBody()); + } + + public void testGetMessageBodyUcs2Umts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x48, + + (byte)0x01, + + (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x55, + (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x32, + (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x6D, (byte)0x00, (byte)0x65, + (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x61, + (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x20, + (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x6E, + (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x69, + (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E, + (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x61, + (byte)0x00, (byte)0x20, (byte)0x04, (byte)0x34, (byte)0x00, (byte)0x20, + (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68, (byte)0x00, (byte)0x61, + (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x63, + (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x72, + (byte)0x00, (byte)0x0D, (byte)0x00, (byte)0x0D, + + (byte)0x4E + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A UCS2 message containing a \u0434 character", msg.getMessageBody()); + } + + public void testGetMessageBodyUcs2MultipageUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x48, + + (byte)0x02, + + (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x41, + (byte)0x00, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + + (byte)0x06, + + (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x42, + (byte)0x00, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, + + (byte)0x06 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected multipage UCS2 string decoded", + "AAABBB", msg.getMessageBody()); + } + + public void testGetMessageBodyUcs2WithLanguageInBody() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x11, (byte)0x11, (byte)0x78, + (byte)0x3C, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x55, + (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x32, (byte)0x00, + (byte)0x20, (byte)0x00, (byte)0x6D, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x73, + (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x67, (byte)0x00, + (byte)0x65, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F, + (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, (byte)0x00, + (byte)0x69, (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E, + (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x61, (byte)0x00, + (byte)0x20, (byte)0x04, (byte)0x34, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, + (byte)0x00, (byte)0x68, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x72, (byte)0x00, + (byte)0x61, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65, + (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x0D + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A UCS2 message containing a \u0434 character", msg.getMessageBody()); + + assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode()); + } + + public void testGetMessageBodyUcs2WithLanguageInBodyUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x11, + + (byte)0x01, + + (byte)0x78, (byte)0x3C, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20, + (byte)0x00, (byte)0x55, (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53, + (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x6D, + (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73, + (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65, + (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F, + (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, + (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69, + (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20, + (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x20, (byte)0x04, (byte)0x34, + (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68, + (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61, + (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65, + (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x0D, + + (byte)0x50 + }; + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected 7-bit string decoded", + "A UCS2 message containing a \u0434 character", msg.getMessageBody()); + + assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode()); + } + + public void testGetMessageIdentifier() { + byte[] pdu = { + (byte)0xC0, (byte)0x00, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41, + (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6, + (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70, + (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, + (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, + (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75, + (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69, + (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00 + }; + + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected message identifier decoded", 12345, msg.getServiceCategory()); + } + + public void testGetMessageIdentifierUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40, + + (byte)0x01, + + (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, + (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, + (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C, + (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C, + (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A, + (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, + (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, + (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x34 + }; + + SmsCbMessage msg = createFromPdu(pdu); + + assertEquals("Unexpected message identifier decoded", 12345, msg.getServiceCategory()); + } + + public void testGetMessageCode() { + byte[] pdu = { + (byte)0x2A, (byte)0xA5, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41, + (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6, + (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70, + (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, + (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, + (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75, + (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69, + (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00 + }; + + SmsCbMessage msg = createFromPdu(pdu); + int messageCode = (msg.getSerialNumber() & 0x3ff0) >> 4; + + assertEquals("Unexpected message code decoded", 682, messageCode); + } + + public void testGetMessageCodeUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40, + + (byte)0x01, + + (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, + (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, + (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C, + (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C, + (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A, + (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, + (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, + (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x34 + }; + + SmsCbMessage msg = createFromPdu(pdu); + int messageCode = (msg.getSerialNumber() & 0x3ff0) >> 4; + + assertEquals("Unexpected message code decoded", 682, messageCode); + } + + public void testGetUpdateNumber() { + byte[] pdu = { + (byte)0x2A, (byte)0xA5, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41, + (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6, + (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70, + (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, + (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, + (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75, + (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69, + (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00 + }; + + SmsCbMessage msg = createFromPdu(pdu); + int updateNumber = msg.getSerialNumber() & 0x000f; + + assertEquals("Unexpected update number decoded", 5, updateNumber); + } + + public void testGetUpdateNumberUmts() { + byte[] pdu = { + (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40, + + (byte)0x01, + + (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, + (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, + (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C, + (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C, + (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A, + (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9, + (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, + (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, + (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, + (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, + (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, + (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, + (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, + (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00, + + (byte)0x34 + }; + + SmsCbMessage msg = createFromPdu(pdu); + int updateNumber = msg.getSerialNumber() & 0x000f; + + assertEquals("Unexpected update number decoded", 5, updateNumber); + } + + /* ETWS Test message including header */ + private static final byte[] etwsMessageNormal = IccUtils.hexStringToBytes("000011001101" + + "0D0A5BAE57CE770C531790E85C716CBF3044573065B930675730" + + "9707767A751F30025F37304463FA308C306B5099304830664E0B30553044FF086C178C615E81FF09" + + "0000000000000000000000000000"); + + private static final byte[] etwsMessageCancel = IccUtils.hexStringToBytes("000011001101" + + "0D0A5148307B3069002800310030003A0035" + + "00320029306E7DCA602557309707901F5831309253D66D883057307E3059FF086C178C615E81FF09" + + "00000000000000000000000000000000000000000000"); + + private static final byte[] etwsMessageTest = IccUtils.hexStringToBytes("000011031101" + + "0D0A5BAE57CE770C531790E85C716CBF3044" + + "573065B9306757309707300263FA308C306B5099304830664E0B30553044FF086C178C615E81FF09" + + "00000000000000000000000000000000000000000000"); + + // FIXME: add example of ETWS primary notification PDU + + public void testEtwsMessageNormal() { + SmsCbMessage msg = createFromPdu(etwsMessageNormal); + Log.d(TAG, msg.toString()); + assertEquals("GS mismatch", 0, msg.getGeographicalScope()); + assertEquals("serial number mismatch", 0, msg.getSerialNumber()); + assertEquals("message ID mismatch", 0x1100, msg.getServiceCategory()); + assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE, + msg.getEtwsWarningInfo().getWarningType()); + } + + public void testEtwsMessageCancel() { + SmsCbMessage msg = createFromPdu(etwsMessageCancel); + Log.d(TAG, msg.toString()); + assertEquals("GS mismatch", 0, msg.getGeographicalScope()); + assertEquals("serial number mismatch", 0, msg.getSerialNumber()); + assertEquals("message ID mismatch", 0x1100, msg.getServiceCategory()); + assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE, + msg.getEtwsWarningInfo().getWarningType()); + } + + public void testEtwsMessageTest() { + SmsCbMessage msg = createFromPdu(etwsMessageTest); + Log.d(TAG, msg.toString()); + assertEquals("GS mismatch", 0, msg.getGeographicalScope()); + assertEquals("serial number mismatch", 0, msg.getSerialNumber()); + assertEquals("message ID mismatch", 0x1103, msg.getServiceCategory()); + assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE, + msg.getEtwsWarningInfo().getWarningType()); + } + + // Make sure we don't throw an exception if we feed random data to the PDU parser. + public void testRandomPdus() { + Random r = new Random(94040); + for (int run = 0; run < 10000; run++) { + int len = r.nextInt(140); + byte[] data = new byte[len]; + for (int i = 0; i < len; i++) { + data[i] = (byte) r.nextInt(256); + } + try { + // this should return a SmsCbMessage object or null for invalid data + SmsCbMessage msg = createFromPdu(data); + } catch (Exception e) { + Log.d(TAG, "exception thrown", e); + fail("Exception in decoder at run " + run + " length " + len + ": " + e); + } + } + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java new file mode 100644 index 0000000..ea6836d --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java @@ -0,0 +1,624 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.Message; +import android.os.SystemClock; +import android.util.Log; + +import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.IccIoResult; +import com.android.internal.telephony.UUSInfo; + +import junit.framework.Assert; + +/** + * Dummy BaseCommands for UsimDataDownloadTest. Only implements UICC envelope and + * SMS acknowledgement commands. + */ +class UsimDataDownloadCommands extends BaseCommands { + private static final String TAG = "UsimDataDownloadCommands"; + + private boolean mExpectingAcknowledgeGsmSms; // true if expecting ack GSM SMS + private boolean mExpectingAcknowledgeGsmSmsSuccess; // true if expecting ack SMS success + private int mExpectingAcknowledgeGsmSmsFailureCause; // expecting ack SMS failure cause + private String mExpectingAcknowledgeGsmSmsPdu; // expecting ack SMS PDU + + private boolean mExpectingSendEnvelope; // true to expect a send envelope command + private String mExpectingSendEnvelopeContents; // expected string for send envelope + private int mExpectingSendEnvelopeResponseSw1; // SW1/SW2 response status + private int mExpectingSendEnvelopeResponseSw2; // SW1/SW2 response status + private String mExpectingSendEnvelopeResponse; // Response string for Send Envelope + + UsimDataDownloadCommands(Context context) { + super(context); + } + + /** + * Expect a call to acknowledgeLastIncomingGsmSms with success flag and failure cause. + * @param success true if expecting success; false if expecting failure + * @param cause the failure cause, if success is false + */ + synchronized void expectAcknowledgeGsmSms(boolean success, int cause) { + Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); + mExpectingAcknowledgeGsmSms = true; + mExpectingAcknowledgeGsmSmsSuccess = success; + mExpectingAcknowledgeGsmSmsFailureCause = cause; + } + + /** + * Expect a call to acknowledgeLastIncomingGsmSmsWithPdu with success flag and PDU. + * @param success true if expecting success; false if expecting failure + * @param ackPdu the acknowledgement PDU to expect + */ + synchronized void expectAcknowledgeGsmSmsWithPdu(boolean success, String ackPdu) { + Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); + mExpectingAcknowledgeGsmSms = true; + mExpectingAcknowledgeGsmSmsSuccess = success; + mExpectingAcknowledgeGsmSmsPdu = ackPdu; + } + + /** + * Expect a call to sendEnvelopeWithStatus(). + * @param contents expected envelope contents to send + * @param sw1 simulated SW1 status to return + * @param sw2 simulated SW2 status to return + * @param response simulated envelope response to return + */ + synchronized void expectSendEnvelope(String contents, int sw1, int sw2, String response) { + Assert.assertFalse("expectSendEnvelope called twice", mExpectingSendEnvelope); + mExpectingSendEnvelope = true; + mExpectingSendEnvelopeContents = contents; + mExpectingSendEnvelopeResponseSw1 = sw1; + mExpectingSendEnvelopeResponseSw2 = sw2; + mExpectingSendEnvelopeResponse = response; + } + + synchronized void assertExpectedMethodsCalled() { + long stopTime = SystemClock.elapsedRealtime() + 5000; + while ((mExpectingAcknowledgeGsmSms || mExpectingSendEnvelope) + && SystemClock.elapsedRealtime() < stopTime) { + try { + wait(); + } catch (InterruptedException ignored) {} + } + Assert.assertFalse("expecting SMS acknowledge call", mExpectingAcknowledgeGsmSms); + Assert.assertFalse("expecting send envelope call", mExpectingSendEnvelope); + } + + @Override + public synchronized void acknowledgeLastIncomingGsmSms(boolean success, int cause, + Message response) { + Log.d(TAG, "acknowledgeLastIncomingGsmSms: success=" + success + ", cause=" + cause); + Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsFailureCause, cause); + mExpectingAcknowledgeGsmSms = false; + if (response != null) { + AsyncResult.forMessage(response); + response.sendToTarget(); + } + notifyAll(); // wake up assertExpectedMethodsCalled() + } + + @Override + public synchronized void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu, + Message response) { + Log.d(TAG, "acknowledgeLastIncomingGsmSmsWithPdu: success=" + success + + ", ackPDU= " + ackPdu); + Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsPdu, ackPdu); + mExpectingAcknowledgeGsmSms = false; + if (response != null) { + AsyncResult.forMessage(response); + response.sendToTarget(); + } + notifyAll(); // wake up assertExpectedMethodsCalled() + } + + @Override + public synchronized void sendEnvelopeWithStatus(String contents, Message response) { + // Add spaces between hex bytes for readability + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < contents.length(); i += 2) { + builder.append(contents.charAt(i)).append(contents.charAt(i+1)).append(' '); + } + Log.d(TAG, "sendEnvelopeWithStatus: " + builder.toString()); + + Assert.assertTrue("unexpected call to send envelope", mExpectingSendEnvelope); + Assert.assertEquals(mExpectingSendEnvelopeContents, contents); + mExpectingSendEnvelope = false; + + IccIoResult result = new IccIoResult(mExpectingSendEnvelopeResponseSw1, + mExpectingSendEnvelopeResponseSw2, mExpectingSendEnvelopeResponse); + + if (response != null) { + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + } + notifyAll(); // wake up assertExpectedMethodsCalled() + } + + @Override + public void setSuppServiceNotifications(boolean enable, Message result) { + } + + @Override + public void supplyIccPin(String pin, Message result) { + } + + @Override + public void supplyIccPinForApp(String pin, String aid, Message result) { + } + + @Override + public void supplyIccPuk(String puk, String newPin, Message result) { + } + + @Override + public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) { + } + + @Override + public void supplyIccPin2(String pin2, Message result) { + } + + @Override + public void supplyIccPin2ForApp(String pin2, String aid, Message result) { + } + + @Override + public void supplyIccPuk2(String puk2, String newPin2, Message result) { + } + + @Override + public void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message result) { + } + + @Override + public void changeIccPin(String oldPin, String newPin, Message result) { + } + + @Override + public void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message result) { + } + + @Override + public void changeIccPin2(String oldPin2, String newPin2, Message result) { + } + + @Override + public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr, Message result) { + } + + @Override + public void changeBarringPassword(String facility, String oldPwd, String newPwd, + Message result) { + } + + @Override + public void supplyNetworkDepersonalization(String netpin, Message result) { + } + + @Override + public void getCurrentCalls(Message result) { + } + + @Override + public void getPDPContextList(Message result) { + } + + @Override + public void getDataCallList(Message result) { + } + + @Override + public void dial(String address, int clirMode, Message result) { + } + + @Override + public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) { + } + + @Override + public void getIMSI(Message result) { + } + + @Override + public void getIMEI(Message result) { + } + + @Override + public void getIMEISV(Message result) { + } + + @Override + public void hangupConnection(int gsmIndex, Message result) { + } + + @Override + public void hangupWaitingOrBackground(Message result) { + } + + @Override + public void hangupForegroundResumeBackground(Message result) { + } + + @Override + public void switchWaitingOrHoldingAndActive(Message result) { + } + + @Override + public void conference(Message result) { + } + + @Override + public void setPreferredVoicePrivacy(boolean enable, Message result) { + } + + @Override + public void getPreferredVoicePrivacy(Message result) { + } + + @Override + public void separateConnection(int gsmIndex, Message result) { + } + + @Override + public void acceptCall(Message result) { + } + + @Override + public void rejectCall(Message result) { + } + + @Override + public void explicitCallTransfer(Message result) { + } + + @Override + public void getLastCallFailCause(Message result) { + } + + @Override + public void getLastPdpFailCause(Message result) { + } + + @Override + public void getLastDataCallFailCause(Message result) { + } + + @Override + public void setMute(boolean enableMute, Message response) { + } + + @Override + public void getMute(Message response) { + } + + @Override + public void getSignalStrength(Message response) { + } + + @Override + public void getVoiceRegistrationState(Message response) { + } + + @Override + public void getDataRegistrationState(Message response) { + } + + @Override + public void getOperator(Message response) { + } + + @Override + public void sendDtmf(char c, Message result) { + } + + @Override + public void startDtmf(char c, Message result) { + } + + @Override + public void stopDtmf(Message result) { + } + + @Override + public void sendBurstDtmf(String dtmfString, int on, int off, Message result) { + } + + @Override + public void sendSMS(String smscPDU, String pdu, Message response) { + } + + @Override + public void sendCdmaSms(byte[] pdu, Message response) { + } + + @Override + public void deleteSmsOnSim(int index, Message response) { + } + + @Override + public void deleteSmsOnRuim(int index, Message response) { + } + + @Override + public void writeSmsToSim(int status, String smsc, String pdu, Message response) { + } + + @Override + public void writeSmsToRuim(int status, String pdu, Message response) { + } + + @Override + public void setRadioPower(boolean on, Message response) { + } + + @Override + public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response) { + } + + @Override + public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data, + String pin2, Message response) { + } + + @Override + public void queryCLIP(Message response) { + } + + @Override + public void getCLIR(Message response) { + } + + @Override + public void setCLIR(int clirMode, Message response) { + } + + @Override + public void queryCallWaiting(int serviceClass, Message response) { + } + + @Override + public void setCallWaiting(boolean enable, int serviceClass, Message response) { + } + + @Override + public void setCallForward(int action, int cfReason, int serviceClass, String number, + int timeSeconds, Message response) { + } + + @Override + public void queryCallForwardStatus(int cfReason, int serviceClass, String number, + Message response) { + } + + @Override + public void setNetworkSelectionModeAutomatic(Message response) { + } + + @Override + public void setNetworkSelectionModeManual(String operatorNumeric, Message response) { + } + + @Override + public void getNetworkSelectionMode(Message response) { + } + + @Override + public void getAvailableNetworks(Message response) { + } + + @Override + public void getBasebandVersion(Message response) { + } + + @Override + public void queryFacilityLock(String facility, String password, int serviceClass, + Message response) { + } + + @Override + public void queryFacilityLockForApp(String facility, String password, int serviceClass, + String appId, Message response) { + } + + @Override + public void setFacilityLock(String facility, boolean lockState, String password, + int serviceClass, Message response) { + } + + @Override + public void setFacilityLockForApp(String facility, boolean lockState, String password, + int serviceClass, String appId, Message response) { + } + + @Override + public void sendUSSD(String ussdString, Message response) { + } + + @Override + public void cancelPendingUssd(Message response) { + } + + @Override + public void resetRadio(Message result) { + } + + @Override + public void setBandMode(int bandMode, Message response) { + } + + @Override + public void queryAvailableBandMode(Message response) { + } + + @Override + public void setPreferredNetworkType(int networkType, Message response) { + } + + @Override + public void getPreferredNetworkType(Message response) { + } + + @Override + public void getNeighboringCids(Message response) { + } + + @Override + public void setLocationUpdates(boolean enable, Message response) { + } + + @Override + public void getSmscAddress(Message result) { + } + + @Override + public void setSmscAddress(String address, Message result) { + } + + @Override + public void reportSmsMemoryStatus(boolean available, Message result) { + } + + @Override + public void reportStkServiceIsRunning(Message result) { + } + + @Override + public void invokeOemRilRequestRaw(byte[] data, Message response) { + } + + @Override + public void invokeOemRilRequestStrings(String[] strings, Message response) { + } + + @Override + public void sendTerminalResponse(String contents, Message response) { + } + + @Override + public void sendEnvelope(String contents, Message response) { + } + + @Override + public void handleCallSetupRequestFromSim(boolean accept, Message response) { + } + + @Override + public void setGsmBroadcastActivation(boolean activate, Message result) { + } + + @Override + public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { + } + + @Override + public void getGsmBroadcastConfig(Message response) { + } + + @Override + public void getDeviceIdentity(Message response) { + } + + @Override + public void getCDMASubscription(Message response) { + } + + @Override + public void sendCDMAFeatureCode(String FeatureCode, Message response) { + } + + @Override + public void setPhoneType(int phoneType) { + } + + @Override + public void queryCdmaRoamingPreference(Message response) { + } + + @Override + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + } + + @Override + public void setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response) { + } + + @Override + public void getCdmaSubscriptionSource(Message response) { + } + + @Override + public void setTTYMode(int ttyMode, Message response) { + } + + @Override + public void queryTTYMode(Message response) { + } + + @Override + public void setupDataCall(String radioTechnology, String profile, String apn, String user, + String password, String authType, String protocol, Message result) { + } + + @Override + public void deactivateDataCall(int cid, int reason, Message result) { + } + + @Override + public void setCdmaBroadcastActivation(boolean activate, Message result) { + } + + @Override + public void setCdmaBroadcastConfig(int[] configValuesArray, Message result) { + } + + @Override + public void getCdmaBroadcastConfig(Message result) { + } + + @Override + public void exitEmergencyCallbackMode(Message response) { + } + + @Override + public void getIccCardStatus(Message result) { + } + + @Override + public void requestIsimAuthentication(String nonce, Message response) { + } + + @Override + public void getVoiceRadioTechnology(Message response) { + } + + @Override + public void getIMSIForApp(String aid, Message result) { + } + + @Override + public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, String aid, Message response) { + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java new file mode 100644 index 0000000..6c8ba5e --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.os.HandlerThread; +import android.test.AndroidTestCase; +import android.util.Log; + +import java.nio.charset.Charset; + +/** + * Test SMS-PP data download to UICC. + * Uses test messages from 3GPP TS 31.124 section 27.22.5. + */ +public class UsimDataDownloadTest extends AndroidTestCase { + private static final String TAG = "UsimDataDownloadTest"; + + class TestHandlerThread extends HandlerThread { + private UsimDataDownloadHandler mHandler; + + TestHandlerThread() { + super("TestHandlerThread"); + } + + @Override + protected void onLooperPrepared() { + synchronized (this) { + mHandler = new UsimDataDownloadHandler(mCm); + notifyAll(); + } + } + + UsimDataDownloadHandler getHandler() { + synchronized (this) { + while (mHandler == null) { + try { + wait(); + } catch (InterruptedException ignored) {} + } + return mHandler; + } + } + } + + private UsimDataDownloadCommands mCm; + private TestHandlerThread mHandlerThread; + UsimDataDownloadHandler mHandler; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCm = new UsimDataDownloadCommands(mContext); + mHandlerThread = new TestHandlerThread(); + mHandlerThread.start(); + mHandler = mHandlerThread.getHandler(); + Log.d(TAG, "mHandler is constructed"); + } + + @Override + protected void tearDown() throws Exception { + mHandlerThread.quit(); + super.tearDown(); + } + + // SMS-PP Message 3.1.1 + private static final byte[] SMS_PP_MESSAGE_3_1_1 = { + // Service center address + 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, + + 0x04, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, 0x16, (byte) 0x89, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x31 + }; + + // SMS-PP Download Envelope 3.1.1 + private static final String SMS_PP_ENVELOPE_3_1_1 = "d12d8202838106099111223344556677f88b1c04" + + "049121437f16891010000000000d546573744d6573736167652031"; + + // SMS-PP Message 3.1.5 + private static final byte[] SMS_PP_MESSAGE_3_1_5 = { + // Service center address + 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, + + 0x44, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, (byte) 0xf6, (byte) 0x89, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x02, 0x70, 0x00, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x00, + 0x00, 0x00, (byte) 0xbf, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, + (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc + }; + + // SMS-PP Download Envelope 3.1.5 + private static final String SMS_PP_ENVELOPE_3_1_5 = "d13e8202838106099111223344556677f88b2d44" + + "049121437ff6891010000000001e0270000019000d00000000bfff00000000000100" + + "dcdcdcdcdcdcdcdcdcdc"; + + public void testDataDownloadMessage1() { + SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_1); + assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); + + mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, ""); + mCm.expectAcknowledgeGsmSms(true, 0); + mHandler.startDataDownload(message); + mCm.assertExpectedMethodsCalled(); + + mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, "0123456789"); + mCm.expectAcknowledgeGsmSmsWithPdu(true, "00077f16050123456789"); + mHandler.startDataDownload(message); + mCm.assertExpectedMethodsCalled(); + + mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x62, 0xff, "0123456789abcdef"); + mCm.expectAcknowledgeGsmSmsWithPdu(false, "00d5077f16080123456789abcdef"); + mHandler.startDataDownload(message); + mCm.assertExpectedMethodsCalled(); + } + + public void testDataDownloadMessage5() { + SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_5); + assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); + + mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x90, 0x00, "9876543210"); + mCm.expectAcknowledgeGsmSmsWithPdu(true, "00077ff6059876543210"); + mHandler.startDataDownload(message); + mCm.assertExpectedMethodsCalled(); + + mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x93, 0x00, ""); + mCm.expectAcknowledgeGsmSms(false, 0xd4); // SIM toolkit busy + mHandler.startDataDownload(message); + mCm.assertExpectedMethodsCalled(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimServiceTableTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimServiceTableTest.java new file mode 100644 index 0000000..56854ed --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimServiceTableTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Test UsimServiceTable class. + */ +public class UsimServiceTableTest extends AndroidTestCase { + + @SmallTest + public void testUsimServiceTable() { + byte[] noServices = {0x00}; + byte[] service1 = {0x01, 0x00}; + byte[] service8 = {(byte) 0x80, 0x00, 0x00}; + byte[] service8And9 = {(byte) 0x80, 0x01}; + byte[] service28 = {0x00, 0x00, 0x00, 0x08}; + byte[] service89To96 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, (byte) 0xff}; + + UsimServiceTable testTable1 = new UsimServiceTable(noServices); + assertFalse(testTable1.isAvailable(UsimServiceTable.UsimService.PHONEBOOK)); + assertFalse(testTable1.isAvailable(UsimServiceTable.UsimService.FDN)); + assertFalse(testTable1.isAvailable(UsimServiceTable.UsimService.NAS_CONFIG_BY_USIM)); + + UsimServiceTable testTable2 = new UsimServiceTable(service1); + assertTrue(testTable2.isAvailable(UsimServiceTable.UsimService.PHONEBOOK)); + assertFalse(testTable2.isAvailable(UsimServiceTable.UsimService.FDN)); + assertFalse(testTable2.isAvailable(UsimServiceTable.UsimService.NAS_CONFIG_BY_USIM)); + + UsimServiceTable testTable3 = new UsimServiceTable(service8); + assertFalse(testTable3.isAvailable(UsimServiceTable.UsimService.PHONEBOOK)); + assertFalse(testTable3.isAvailable(UsimServiceTable.UsimService.BDN_EXTENSION)); + assertTrue(testTable3.isAvailable(UsimServiceTable.UsimService.OUTGOING_CALL_INFO)); + assertFalse(testTable3.isAvailable(UsimServiceTable.UsimService.INCOMING_CALL_INFO)); + assertFalse(testTable3.isAvailable(UsimServiceTable.UsimService.NAS_CONFIG_BY_USIM)); + + UsimServiceTable testTable4 = new UsimServiceTable(service8And9); + assertFalse(testTable4.isAvailable(UsimServiceTable.UsimService.PHONEBOOK)); + assertFalse(testTable4.isAvailable(UsimServiceTable.UsimService.BDN_EXTENSION)); + assertTrue(testTable4.isAvailable(UsimServiceTable.UsimService.OUTGOING_CALL_INFO)); + assertTrue(testTable4.isAvailable(UsimServiceTable.UsimService.INCOMING_CALL_INFO)); + assertFalse(testTable4.isAvailable(UsimServiceTable.UsimService.SM_STORAGE)); + assertFalse(testTable4.isAvailable(UsimServiceTable.UsimService.NAS_CONFIG_BY_USIM)); + + UsimServiceTable testTable5 = new UsimServiceTable(service28); + assertFalse(testTable5.isAvailable(UsimServiceTable.UsimService.PHONEBOOK)); + assertTrue(testTable5.isAvailable(UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)); + assertFalse(testTable5.isAvailable(UsimServiceTable.UsimService.NAS_CONFIG_BY_USIM)); + + UsimServiceTable testTable6 = new UsimServiceTable(service89To96); + assertFalse(testTable6.isAvailable(UsimServiceTable.UsimService.PHONEBOOK)); + assertFalse(testTable6.isAvailable(UsimServiceTable.UsimService.HPLMN_DIRECT_ACCESS)); + assertTrue(testTable6.isAvailable(UsimServiceTable.UsimService.ECALL_DATA)); + assertTrue(testTable6.isAvailable(UsimServiceTable.UsimService.SM_OVER_IP)); + assertTrue(testTable6.isAvailable(UsimServiceTable.UsimService.UICC_ACCESS_TO_IMS)); + assertTrue(testTable6.isAvailable(UsimServiceTable.UsimService.NAS_CONFIG_BY_USIM)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java b/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java new file mode 100644 index 0000000..3149ee1 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.mockril; + +import android.util.Log; +import android.test.InstrumentationTestCase; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.android.internal.communication.MsgHeader; +import com.android.internal.communication.Msg; +import com.android.internal.telephony.RilChannel; +import com.android.internal.telephony.ril_proto.RilCtrlCmds; +import com.android.internal.telephony.ril_proto.RilCmds; + +import com.android.frameworks.telephonytests.TelephonyMockRilTestRunner; +import com.google.protobuf.micro.InvalidProtocolBufferMicroException; + +// Test suite for test ril +public class MockRilTest extends InstrumentationTestCase { + private static final String TAG = "MockRilTest"; + + RilChannel mMockRilChannel; + TelephonyMockRilTestRunner mRunner; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mRunner = (TelephonyMockRilTestRunner)getInstrumentation(); + mMockRilChannel = mRunner.mMockRilChannel; + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + static void log(String s) { + Log.v(TAG, s); + } + + /** + * Test Case 1: Test protobuf serialization and deserialization + * @throws InvalidProtocolBufferMicroException + */ + public void testProtobufSerDes() throws InvalidProtocolBufferMicroException { + log("testProtobufSerdes E"); + + RilCtrlCmds.CtrlRspRadioState rs = new RilCtrlCmds.CtrlRspRadioState(); + assertTrue(String.format("expected rs.state == 0 was %d", rs.getState()), + rs.getState() == 0); + rs.setState(1); + assertTrue(String.format("expected rs.state == 1 was %d", rs.getState()), + rs.getState() == 1); + + byte[] rs_ser = rs.toByteArray(); + RilCtrlCmds.CtrlRspRadioState rsNew = RilCtrlCmds.CtrlRspRadioState.parseFrom(rs_ser); + assertTrue(String.format("expected rsNew.state == 1 was %d", rs.getState()), + rs.getState() == 1); + + log("testProtobufSerdes X"); + } + + /** + * Test case 2: Test echo command works using writeMsg & readMsg + */ + public void testEchoMsg() throws IOException { + log("testEchoMsg E"); + + MsgHeader mh = new MsgHeader(); + mh.setCmd(0); + mh.setToken(1); + mh.setStatus(2); + ByteBuffer data = ByteBuffer.allocate(3); + data.put((byte)3); + data.put((byte)4); + data.put((byte)5); + Msg.send(mMockRilChannel, mh, data); + + Msg respMsg = Msg.recv(mMockRilChannel); + assertTrue(String.format("expected mhd.header.cmd == 0 was %d",respMsg.getCmd()), + respMsg.getCmd() == 0); + assertTrue(String.format("expected mhd.header.token == 1 was %d",respMsg.getToken()), + respMsg.getToken() == 1); + assertTrue(String.format("expected mhd.header.status == 2 was %d", respMsg.getStatus()), + respMsg.getStatus() == 2); + assertTrue(String.format("expected mhd.data[0] == 3 was %d", respMsg.getData(0)), + respMsg.getData(0) == 3); + assertTrue(String.format("expected mhd.data[1] == 4 was %d", respMsg.getData(1)), + respMsg.getData(1) == 4); + assertTrue(String.format("expected mhd.data[2] == 5 was %d", respMsg.getData(2)), + respMsg.getData(2) == 5); + + log("testEchoMsg X"); + } + + /** + * Test case 3: Test get as + */ + public void testGetAs() { + log("testGetAs E"); + + // Use a message header as the protobuf data content + MsgHeader mh = new MsgHeader(); + mh.setCmd(12345); + mh.setToken(9876); + mh.setStatus(7654); + mh.setLengthData(4321); + byte[] data = mh.toByteArray(); + MsgHeader mhResult = Msg.getAs(MsgHeader.class, data); + + assertTrue(String.format("expected cmd == 12345 was %d", mhResult.getCmd()), + mhResult.getCmd() == 12345); + assertTrue(String.format("expected token == 9876 was %d", mhResult.getToken()), + mhResult.getToken() == 9876); + assertTrue(String.format("expected status == 7654 was %d", mhResult.getStatus()), + mhResult.getStatus() == 7654); + assertTrue(String.format("expected lengthData == 4321 was %d", mhResult.getLengthData()), + mhResult.getLengthData() == 4321); + + Msg msg = Msg.obtain(); + msg.setData(ByteBuffer.wrap(data)); + + mhResult = msg.getDataAs(MsgHeader.class); + + assertTrue(String.format("expected cmd == 12345 was %d", mhResult.getCmd()), + mhResult.getCmd() == 12345); + assertTrue(String.format("expected token == 9876 was %d", mhResult.getToken()), + mhResult.getToken() == 9876); + assertTrue(String.format("expected status == 7654 was %d", mhResult.getStatus()), + mhResult.getStatus() == 7654); + assertTrue(String.format("expected lengthData == 4321 was %d", mhResult.getLengthData()), + mhResult.getLengthData() == 4321); + + log("testGetAs X"); + } + + /** + * Test case 3: test get radio state + */ + public void testGetRadioState() throws IOException { + log("testGetRadioState E"); + + Msg.send(mMockRilChannel, 1, 9876, 0, null); + + Msg resp = Msg.recv(mMockRilChannel); + //resp.printHeader("testGetRadioState"); + + assertTrue(String.format("expected cmd == 1 was %d", resp.getCmd()), + resp.getCmd() == 1); + assertTrue(String.format("expected token == 9876 was %d", resp.getToken()), + resp.getToken() == 9876); + assertTrue(String.format("expected status == 0 was %d", resp.getStatus()), + resp.getStatus() == 0); + + RilCtrlCmds.CtrlRspRadioState rsp = resp.getDataAs(RilCtrlCmds.CtrlRspRadioState.class); + + int state = rsp.getState(); + log("testGetRadioState state=" + state); + assertTrue(String.format("expected RadioState >= 0 && RadioState <= 9 was %d", state), + ((state >= 0) && (state <= 9))); + + log("testGetRadioState X"); + } + + /** + * Test case 5: test set radio state + */ + public void testSetRadioState() throws IOException { + log("testSetRadioState E"); + + RilCtrlCmds.CtrlReqRadioState cmdrs = new RilCtrlCmds.CtrlReqRadioState(); + assertEquals(0, cmdrs.getState()); + + cmdrs.setState(RilCmds.RADIOSTATE_SIM_NOT_READY); + assertEquals(2, cmdrs.getState()); + + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_RADIO_STATE, 0, 0, cmdrs); + + Msg resp = Msg.recv(mMockRilChannel); + log("get response status :" + resp.getStatus()); + log("get response for command: " + resp.getCmd()); + log("get command token: " + resp.getToken()); + + RilCtrlCmds.CtrlRspRadioState rsp = resp.getDataAs(RilCtrlCmds.CtrlRspRadioState.class); + + int state = rsp.getState(); + log("get response for testSetRadioState: " + state); + assertTrue(RilCmds.RADIOSTATE_SIM_NOT_READY == state); + } + + /** + * Test case 6: test start incoming call and hangup it. + */ + public void testStartIncomingCallAndHangup() throws IOException { + log("testStartIncomingCallAndHangup"); + RilCtrlCmds.CtrlReqSetMTCall cmd = new RilCtrlCmds.CtrlReqSetMTCall(); + String incomingCall = "6502889108"; + // set the MT call + cmd.setPhoneNumber(incomingCall); + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_MT_CALL, 0, 0, cmd); + // get response + Msg resp = Msg.recv(mMockRilChannel); + log("Get response status: " + resp.getStatus()); + assertTrue("The ril is not in a proper state to set MT calls.", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + + // allow the incoming call alerting for some time + try { + Thread.sleep(5000); + } catch (InterruptedException e) {} + + // we are playing a trick to assume the current is 1 + RilCtrlCmds.CtrlHangupConnRemote hangupCmd = new RilCtrlCmds.CtrlHangupConnRemote(); + hangupCmd.setConnectionId(1); + hangupCmd.setCallFailCause(16); // normal hangup + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_HANGUP_CONN_REMOTE, 0, 0, hangupCmd); + + // get response + resp = Msg.recv(mMockRilChannel); + log("Get response for hangup connection: " + resp.getStatus()); + assertTrue("CTRL_CMD_HANGUP_CONN_REMOTE failed", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + } + + /** + * Test case 7: test set call transition flag + */ + public void testSetCallTransitionFlag() throws IOException { + log("testSetCallTransitionFlag"); + // Set flag to true: + RilCtrlCmds.CtrlSetCallTransitionFlag cmd = new RilCtrlCmds.CtrlSetCallTransitionFlag(); + cmd.setFlag(true); + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_TRANSITION_FLAG, 0, 0, cmd); + + Msg resp = Msg.recv(mMockRilChannel); + log("Get response status: " + resp.getStatus()); + assertTrue("Set call transition flag failed", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + + // add a dialing call + RilCtrlCmds.CtrlReqAddDialingCall cmdDialCall = new RilCtrlCmds.CtrlReqAddDialingCall(); + String phoneNumber = "5102345678"; + cmdDialCall.setPhoneNumber(phoneNumber); + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_ADD_DIALING_CALL, 0, 0, cmdDialCall); + resp = Msg.recv(mMockRilChannel); + log("Get response status for adding a dialing call: " + resp.getStatus()); + assertTrue("add dialing call failed", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + try { + Thread.sleep(5000); + } catch (InterruptedException e) {} + + // send command to force call state change + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_ALERT, 0, 0, null); + resp = Msg.recv(mMockRilChannel); + log("Get response status: " + resp.getStatus()); + assertTrue("Set call alert failed", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) {} + + // send command to force call state change + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_ACTIVE, 0, 0, null); + resp = Msg.recv(mMockRilChannel); + log("Get response status: " + resp.getStatus()); + assertTrue("Set call active failed", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + + // hangup the active all remotely + RilCtrlCmds.CtrlHangupConnRemote hangupCmd = new RilCtrlCmds.CtrlHangupConnRemote(); + hangupCmd.setConnectionId(1); + hangupCmd.setCallFailCause(16); // normal hangup + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_HANGUP_CONN_REMOTE, 0, 0, hangupCmd); + resp = Msg.recv(mMockRilChannel); + log("Get response for hangup connection: " + resp.getStatus()); + assertTrue("CTRL_CMD_HANGUP_CONN_REMOTE failed", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + + // set the flag to false + cmd.setFlag(false); + Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_TRANSITION_FLAG, 0, 0, cmd); + resp = Msg.recv(mMockRilChannel); + assertTrue("Set call transition flag failed", + resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK); + } +} |