summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commite405ce157d5bfb44efa33a314ae08d543bc9d39e (patch)
tree9941f4acbde908891eddd6f39d538ebe377483e1
downloadStk-release-1.0.tar.gz
-rw-r--r--Android.mk13
-rw-r--r--AndroidManifest.xml58
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--NOTICE190
-rwxr-xr-xres/drawable/ic_launcher_sim_toolkit.pngbin0 -> 3131 bytes
-rw-r--r--res/layout/stk_call_dialog.xml52
-rw-r--r--res/layout/stk_input.xml100
-rw-r--r--res/layout/stk_menu_item.xml44
-rw-r--r--res/layout/stk_menu_list.xml42
-rw-r--r--res/layout/stk_msg_dialog.xml55
-rw-r--r--res/layout/stk_title.xml53
-rw-r--r--res/values-de-rDE/strings.xml24
-rw-r--r--res/values-en-rGB/strings.xml24
-rw-r--r--res/values-es-rUS/strings.xml24
-rw-r--r--res/values-fr-rFR/strings.xml24
-rw-r--r--res/values-it-rIT/strings.xml24
-rw-r--r--res/values-mcc234-mnc030/strings.xml21
-rw-r--r--res/values-mcc234-mnc033/strings.xml19
-rw-r--r--res/values-mcc234-mnc034/strings.xml19
-rw-r--r--res/values-mcc262-mnc001/strings.xml19
-rw-r--r--res/values-zh-rTW/strings.xml24
-rw-r--r--res/values/colors.xml19
-rw-r--r--res/values/strings.xml38
-rw-r--r--res/xml/stk_settings.xml33
-rw-r--r--src/com/android/stk/StkActivity.java1317
-rw-r--r--src/com/android/stk/StkApp.java69
-rw-r--r--src/com/android/stk/StkDigitsKeyListener.java49
-rw-r--r--src/com/android/stk/StkInputActivity.java366
-rw-r--r--src/com/android/stk/StkMenuAdapter.java68
-rw-r--r--src/com/android/stk/StkSettings.java117
-rw-r--r--src/com/android/stk/TonePlayer.java79
-rw-r--r--src/com/android/stk/Util.java104
-rw-r--r--src/com/android/stk/WatchDog.java143
33 files changed, 3231 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..079d7ad
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,13 @@
+# Copyright 2007-2008 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Stk
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..83f8ae7
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.stk"
+ android:sharedUserId="android.uid.phone">
+
+ <application android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:label="@string/app_name"
+ android:clearTaskOnLaunch="true"
+ android:process="com.android.phone">
+
+ <activity android:name="StkActivity" android:label="@string/app_name"
+ android:enabled="false" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.intent.action.PICK" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="StkInputActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.intent.action.EDIT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- SIM Toolkit settings activity -->
+ <activity android:name="StkSettings" android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEVELOPMENT_PREFERENCE" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/res/drawable/ic_launcher_sim_toolkit.png b/res/drawable/ic_launcher_sim_toolkit.png
new file mode 100755
index 0000000..0dfec74
--- /dev/null
+++ b/res/drawable/ic_launcher_sim_toolkit.png
Binary files differ
diff --git a/res/layout/stk_call_dialog.xml b/res/layout/stk_call_dialog.xml
new file mode 100644
index 0000000..533187d
--- /dev/null
+++ b/res/layout/stk_call_dialog.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="240sp"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/prompt"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="16sp"
+ android:text="@string/launch_dialer"
+ android:layout_marginBottom="10dip" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center">
+ <Button
+ android:id="@+id/button_call"
+ android:layout_width="100sp"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:textSize="20sp"
+ android:text="@string/button_call" />
+ <Button
+ android:id="@+id/button_cancel"
+ android:layout_width="100sp"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:textStyle="bold"
+ android:textSize="20sp"
+ android:text="@string/button_cancel" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/stk_input.xml b/res/layout/stk_input.xml
new file mode 100644
index 0000000..fdaa39f
--- /dev/null
+++ b/res/layout/stk_input.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="20dip"
+ android:layout_gravity="center_horizontal">
+ <TextView
+ android:id="@+id/prompt"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:gravity="center_horizontal"
+ android:paddingBottom="30dip" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:id="@+id/normal_layout"
+ android:visibility="visible"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:id="@+id/input_restriction_info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dip"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/input_type"
+ android:gravity="left"
+ android:textColor="@color/ltgrey"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/num_of_chars"
+ android:textColor="@color/ltgrey"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dip" />
+ </LinearLayout>
+ <EditText
+ android:id="@+id/in_text"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="20dip"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+ <Button
+ android:id="@+id/button_ok"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="100sp"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/button_ok" />
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/yes_no_layout"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal">
+ <Button
+ android:id="@+id/button_yes"
+ android:layout_width="100sp"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/button_yes" />
+ <Button
+ android:id="@+id/button_no"
+ android:layout_marginLeft="10dip"
+ android:layout_width="100sp"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/button_no" />
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+</ScrollView>
diff --git a/res/layout/stk_menu_item.xml b/res/layout/stk_menu_item.xml
new file mode 100644
index 0000000..8ea5cc1
--- /dev/null
+++ b/res/layout/stk_menu_item.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:scaleType="fitCenter"
+ android:layout_width="@android:dimen/app_icon_size"
+ android:layout_height="@android:dimen/app_icon_size"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="5dip"
+ />
+
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:maxLength="234"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:gravity="center_vertical"
+ android:paddingLeft="25dip"
+ />
+
+</LinearLayout>
diff --git a/res/layout/stk_menu_list.xml b/res/layout/stk_menu_list.xml
new file mode 100644
index 0000000..50e5717
--- /dev/null
+++ b/res/layout/stk_menu_list.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <!-- Include stk title layout. -->
+ <include
+ android:id="@+id/stk_menu_title"
+ layout="@layout/stk_title" />
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
+ <TextView android:id="@android:id/empty"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:textSize="12sp" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/stk_msg_dialog.xml b/res/layout/stk_msg_dialog.xml
new file mode 100644
index 0000000..7ef3a6c
--- /dev/null
+++ b/res/layout/stk_msg_dialog.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="200dip"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="vertical" >
+
+ <ImageView android:id="@+id/dialog_icon"
+ android:layout_width="16dip"
+ android:layout_height="16dip"
+ android:layout_marginTop="5dip"
+ android:layout_marginLeft="5dip"
+ android:layout_alignParentLeft="true"
+ android:scaleType="fitCenter" />
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:padding="10dip"
+ android:orientation="vertical" >
+ <TextView
+ android:id="@+id/dialog_message"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:textSize="16sp"
+ android:layout_marginBottom="5dip" />
+ <Button
+ android:id="@+id/button_ok"
+ android:layout_width="120sp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="5dip"
+ android:textStyle="bold"
+ android:textSize="20sp"
+ android:text="@string/button_ok" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/stk_title.xml b/res/layout/stk_title.xml
new file mode 100644
index 0000000..9e8125c
--- /dev/null
+++ b/res/layout/stk_title.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <LinearLayout android:id="@+id/stk_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="?android:attr/windowTitleBackgroundStyle" >
+
+ <ImageView android:id="@+id/title_icon"
+ android:layout_width="16dip"
+ android:layout_height="16dip"
+ android:layout_marginLeft="2dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="center_vertical"
+ android:scaleType="fitCenter" />
+
+ <TextView android:id="@+id/title_text"
+ android:gravity="center_vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="5dip"
+ android:shadowColor="#BB000000"
+ android:shadowRadius="2.75"
+ style="@android:style/TextAppearance.WindowTitle" />
+
+ </LinearLayout>
+ <FrameLayout android:id="@android:id/content"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:foregroundGravity="fill_horizontal|top"
+ android:foreground="?android:attr/windowContentOverlay" />
+</LinearLayout>
diff --git a/res/values-de-rDE/strings.xml b/res/values-de-rDE/strings.xml
new file mode 100644
index 0000000..9041f0f
--- /dev/null
+++ b/res/values-de-rDE/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="alphabet">Alphabet</string>
+ <string name="app_name">SIM-Toolkit</string>
+ <string name="button_call">Anrufen</string>
+ <string name="button_cancel">Abbrechen</string>
+ <string name="button_no">Nein</string>
+ <string name="button_ok">OK</string>
+ <string name="button_yes">Ja</string>
+ <string name="default_call_setup_msg">Aktiver Anruf\u2026</string>
+ <string name="digits">Ziffern ( 0-9, *, #,+)</string>
+ <string name="disable_app">Deaktiviert</string>
+ <string name="enable_app">Aktiviert</string>
+ <string name="help">Hilfe</string>
+ <string name="launch_browser">Browser starten?</string>
+ <string name="launch_dialer">Wähltastatur starten?</string>
+ <string name="no_content">Kein SIM-Karten-Inhalt verfügbar!</string>
+ <string name="play_tone">Ton wiedergeben</string>
+ <string name="service_name">Dienstname</string>
+ <string name="sim_main_menu">Hauptmenü</string>
+ <string name="stk_app_state">Anwendungsstatus</string>
+ <string name="stk_no_service">Kein Dienst verfügbar</string>
+</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..b91eccc
--- /dev/null
+++ b/res/values-en-rGB/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="alphabet">Alphabets</string>
+ <string name="app_name">SIM Toolkit</string>
+ <string name="button_call">Call</string>
+ <string name="button_cancel">Cancel</string>
+ <string name="button_no">No</string>
+ <string name="button_ok">OK</string>
+ <string name="button_yes">Yes</string>
+ <string name="default_call_setup_msg">Call in progress\u2026</string>
+ <string name="digits">Digits (0-9, *, #, +)</string>
+ <string name="disable_app">Disabled</string>
+ <string name="enable_app">Enabled</string>
+ <string name="help">Help</string>
+ <string name="launch_browser">Launch Browser?</string>
+ <string name="launch_dialer">Launch Dialer?</string>
+ <string name="no_content">No SIM content available!</string>
+ <string name="play_tone">Play tone</string>
+ <string name="service_name">Service name</string>
+ <string name="sim_main_menu">Main menu</string>
+ <string name="stk_app_state">Application state</string>
+ <string name="stk_no_service">No service available</string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..4fe5db0
--- /dev/null
+++ b/res/values-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="alphabet">Alfabetos</string>
+ <string name="app_name">Herramientas SIM</string>
+ <string name="button_call">Llamar</string>
+ <string name="button_cancel">Cancelar</string>
+ <string name="button_no">No</string>
+ <string name="button_ok">Aceptar</string>
+ <string name="button_yes">Sí</string>
+ <string name="default_call_setup_msg">Llamada en curso\u2026</string>
+ <string name="digits">Dígitos (0-9, *, #, +)</string>
+ <string name="disable_app">Deshabilitado</string>
+ <string name="enable_app">Habilitado</string>
+ <string name="help">Ayuda</string>
+ <string name="launch_browser">¿Iniciar explorador?</string>
+ <string name="launch_dialer">¿Iniciar marcador?</string>
+ <string name="no_content">¡Sin contenido SIM disponible!</string>
+ <string name="play_tone">Reproducir tono</string>
+ <string name="service_name">Nombre del servicio</string>
+ <string name="sim_main_menu">Menú principal</string>
+ <string name="stk_app_state">Estado de la aplicación</string>
+ <string name="stk_no_service">Sin servicio disponible</string>
+</resources>
diff --git a/res/values-fr-rFR/strings.xml b/res/values-fr-rFR/strings.xml
new file mode 100644
index 0000000..44fecde
--- /dev/null
+++ b/res/values-fr-rFR/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="alphabet">Alphabets</string>
+ <string name="app_name">Outils SIM</string>
+ <string name="button_call">Appeler</string>
+ <string name="button_cancel">Annuler</string>
+ <string name="button_no">Non</string>
+ <string name="button_ok">OK</string>
+ <string name="button_yes">Oui</string>
+ <string name="default_call_setup_msg">Appel en cours\u2026</string>
+ <string name="digits">Chiffres (0-9, *, #, +)</string>
+ <string name="disable_app">Désactivé</string>
+ <string name="enable_app">Activé</string>
+ <string name="help">Aide</string>
+ <string name="launch_browser">Lancer le navigateur ?</string>
+ <string name="launch_dialer">Lancer le numéroteur ?</string>
+ <string name="no_content">Aucun contenu SIM disponible !</string>
+ <string name="play_tone">Émettre la tonalité</string>
+ <string name="service_name">Nom de service</string>
+ <string name="sim_main_menu">Menu principal</string>
+ <string name="stk_app_state">État d\'application</string>
+ <string name="stk_no_service">Pas de service disponible</string>
+</resources>
diff --git a/res/values-it-rIT/strings.xml b/res/values-it-rIT/strings.xml
new file mode 100644
index 0000000..a349699
--- /dev/null
+++ b/res/values-it-rIT/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="alphabet">Alfabeti</string>
+ <string name="app_name">Kit di strumenti SIM</string>
+ <string name="button_call">Chiama</string>
+ <string name="button_cancel">Annulla</string>
+ <string name="button_no">No</string>
+ <string name="button_ok">OK</string>
+ <string name="button_yes">Sì</string>
+ <string name="default_call_setup_msg">Chiamata in corso\u2026</string>
+ <string name="digits">Numeri (0-9, *, #, +)</string>
+ <string name="disable_app">Disabilitato</string>
+ <string name="enable_app">Abilitato</string>
+ <string name="help">Guida</string>
+ <string name="launch_browser">Avviare il browser?</string>
+ <string name="launch_dialer">Avviare il dialer?</string>
+ <string name="no_content">Nessun contenuto SIM disponibile.</string>
+ <string name="play_tone">Riproduci tono</string>
+ <string name="service_name">Nome servizio</string>
+ <string name="sim_main_menu">Menu principale</string>
+ <string name="stk_app_state">Stato applicazione</string>
+ <string name="stk_no_service">Nessun servizio disponibile</string>
+</resources>
diff --git a/res/values-mcc234-mnc030/strings.xml b/res/values-mcc234-mnc030/strings.xml
new file mode 100644
index 0000000..c3d4de5
--- /dev/null
+++ b/res/values-mcc234-mnc030/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+
+<resources>
+ <string name="app_name">Interactive</string>
+</resources>
+
diff --git a/res/values-mcc234-mnc033/strings.xml b/res/values-mcc234-mnc033/strings.xml
new file mode 100644
index 0000000..226065b
--- /dev/null
+++ b/res/values-mcc234-mnc033/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string name="app_name">Orange Plus</string>
+</resources>
diff --git a/res/values-mcc234-mnc034/strings.xml b/res/values-mcc234-mnc034/strings.xml
new file mode 100644
index 0000000..226065b
--- /dev/null
+++ b/res/values-mcc234-mnc034/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string name="app_name">Orange Plus</string>
+</resources>
diff --git a/res/values-mcc262-mnc001/strings.xml b/res/values-mcc262-mnc001/strings.xml
new file mode 100644
index 0000000..e56258c
--- /dev/null
+++ b/res/values-mcc262-mnc001/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string name="app_name">SIM Tool Kit</string>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..68c337f
--- /dev/null
+++ b/res/values-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="alphabet">字母</string>
+ <string name="app_name">SIM Toolkit</string>
+ <string name="button_call">撥號</string>
+ <string name="button_cancel">取消</string>
+ <string name="button_no">否</string>
+ <string name="button_ok">確定</string>
+ <string name="button_yes">是</string>
+ <string name="default_call_setup_msg">通話中\u2026</string>
+ <string name="digits">數字 (0-9、*、#、+)</string>
+ <string name="disable_app">停用</string>
+ <string name="enable_app">啟用</string>
+ <string name="help">說明</string>
+ <string name="launch_browser">啟動瀏覽器?</string>
+ <string name="launch_dialer">啟動撥號員?</string>
+ <string name="no_content">無可用的 SIM 卡內容!</string>
+ <string name="play_tone">播放音調</string>
+ <string name="service_name">服務名稱</string>
+ <string name="sim_main_menu">主功能表</string>
+ <string name="stk_app_state">應用程式狀態</string>
+ <string name="stk_no_service">無可用的服務</string>
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
new file mode 100644
index 0000000..1a4d54d
--- /dev/null
+++ b/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <color name="ltgrey">#ffe0e0e0</color>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..792801e
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string name="app_name">SIM Toolkit</string>
+ <string name="no_content">No SIM content available!</string>
+ <string name="sim_main_menu">Main menu</string>
+ <string name="service_name">Service name</string>
+ <string name="stk_app_state">Application state</string>
+ <string name="stk_no_service">No service available</string>
+ <string name="enable_app">Enabled</string>
+ <string name="disable_app">Disabled</string>
+ <string name="button_ok">OK</string>
+ <string name="button_call">Call</string>
+ <string name="button_cancel">Cancel</string>
+ <string name="button_yes">Yes</string>
+ <string name="button_no">No</string>
+ <string name="alphabet">Alphabets</string>
+ <string name="digits">Digits (0-9, *, #, +)</string>
+ <string name="launch_dialer">Launch Dialer?</string>
+ <string name="default_call_setup_msg">Call in progress\u2026</string>
+ <string name="launch_browser">Launch Browser?</string>
+ <string name="play_tone">Play tone</string>
+ <string name="help">Help</string>
+</resources>
diff --git a/res/xml/stk_settings.xml b/res/xml/stk_settings.xml
new file mode 100644
index 0000000..e265406
--- /dev/null
+++ b/res/xml/stk_settings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/app_name" >
+
+ <PreferenceScreen
+ android:key="service_name"
+ android:title="@string/service_name"
+ android:summary="@string/stk_no_service"
+ android:persistent="false"/>
+
+ <CheckBoxPreference
+ android:key="stk_app_enable_disable"
+ android:title="@string/stk_app_state"
+ android:persistent="false"
+ android:summaryOn="@string/enable_app"
+ android:summaryOff="@string/disable_app"/>
+
+</PreferenceScreen>
diff --git a/src/com/android/stk/StkActivity.java b/src/com/android/stk/StkActivity.java
new file mode 100644
index 0000000..b442545
--- /dev/null
+++ b/src/com/android/stk/StkActivity.java
@@ -0,0 +1,1317 @@
+/*
+ * 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.stk;
+
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.telephony.gsm.stk.*;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Display main menu and items menu of the SIM application. Launch sub
+ * activities and dialogs to interact with user.
+ */
+public class StkActivity extends ListActivity implements View.OnClickListener {
+
+ // Members
+ private AppInterface mStkService = null;
+ private String mSelectedItem = null;
+ private Handler mHandler = null;
+ private BitSet mStkEvents = null;
+ private DialogEvent mActiveMsgDialogEvent = null;
+ private DialogEvent mActiveBrowserDialogEvent = null;
+ private MsgDialogParams mMsgDialogParams = new MsgDialogParams();
+ private MsgDialogParams mNextMsgDialogParams = new MsgDialogParams();
+ private BrowserDialogParams mBrowserDialogParams = new BrowserDialogParams();
+ private CallDialogParams mCallDialogParams = new CallDialogParams();
+
+ private TonePlayer mTonePlayer = null;
+ private WatchDog mTimeoutWatchDog = null;
+ private Object mMsgDialogSync = null;
+ private int mUiState = UI_STATE_IDLE;
+ private boolean mLaunchNextDialog = false;
+ private TextView mTitleText;
+ private ImageView mTitleIcon;
+ private com.android.internal.telephony.gsm.stk.Menu mCurrentMenu = null;
+
+ // Constants
+ private static final String TAG = "STK ACTIVITY";
+
+ private static final String UI_STATE = "Stk.ui.state";
+ private static final String STK_MENU = "Stk.ui.stkMenu";
+
+ // Internal Activity id
+ public static final int ACTIVITY_MAIN = 1;
+ public static final int ACTIVITY_GET_INPUT = 2;
+ public static final int ACTIVITY_GET_INKEY = 3;
+ public static final int ACTIVITY_GET_INKEY_YESNO = 4;
+ public static final int ACTIVITY_BROWSER = 5;
+ public static final int ACTIVITY_CALL = 6;
+
+ // Internal Dialog id
+ private static final int NO_DIALOG_ID = 0;
+ private static final int CALL_CONFIRM_DIALOG_ID = 1;
+ private static final int CALL_SETUP_DIALOG_ID = 2;
+ private static final int MSG_DIALOG_ID = 3;
+ private static final int BROWSER_DIALOG_ID = 4;
+
+ // Internal state id
+ private static final int UI_STATE_IDLE = 0;
+ private static final int UI_STATE_MAIN = 1;
+ private static final int UI_STATE_SELECT = 2;
+ private static final int UI_STATE_IN_MSG_DIALOG = 3;
+ private static final int UI_STATE_IN_BROWSER_DIALOG = 4;
+ private static final int UI_STATE_IN_CALL_CONFIRM_DIALOG = 5;
+ private static final int UI_STATE_IN_CALL_SETUP_DIALOG = 6;
+ private static final int UI_STATE_PLAY_TONE = 7;
+
+ // Message id to signal tone duration timeout.
+ private static final int STOP_TONE_MSG = 0xde;
+
+ // Inner class, implements WatchDog.Event. track the active state of a dialog
+ // Event should be set when dialog becomes inactive.
+ private class DialogEvent implements Event {
+ private boolean mActiveMsgDialog = true;
+
+ public void set() {
+ mActiveMsgDialog = true;
+ }
+
+ public void unSet() {
+ mActiveMsgDialog = false;
+ }
+
+ public boolean isSet() {
+ return mActiveMsgDialog;
+ }
+ }
+
+ // Container to store dialog parameters.
+ private class DialogParams {
+ // Constants
+ private static final String DIALOG_TEXT = "Dialog.text";
+ private static final String DIALOG_TITLE = "Dialog.title";
+ private static final String DIALOG_ATTR = "Dialog.attr";
+
+ String text;
+ TextAttribute attr;
+ String title;
+ Bitmap icon;
+ // timer
+ WatchDog timeoutWatchDog;
+
+ DialogParams() {
+ title = "";
+ attr = null;
+ text = "";
+ icon = null;
+ timeoutWatchDog = null;
+ }
+
+ void setTimer() {
+ dismissTimer();
+ timeoutWatchDog = new WatchDog(null, mHandler, null,
+ StkApp.UI_TIMEOUT);
+ }
+
+ void dismissTimer() {
+ if (timeoutWatchDog != null) {
+ timeoutWatchDog.cancel();
+ }
+ }
+
+ DialogParams(String text, TextAttribute attr, String title, Bitmap icon) {
+ this.text = text;
+ this.attr = attr;
+ this.title = title;
+ this.icon = icon;
+ }
+
+ void packParams(Bundle bundle) {
+ bundle.putString(DIALOG_TEXT, this.text);
+ bundle.putString(DIALOG_TITLE, this.title);
+ bundle.putBundle(DIALOG_ATTR, Util.packTextAttr(this.attr));
+ }
+
+ void unPackParams(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ this.text = bundle.getString(DIALOG_TEXT);
+ this.title = bundle.getString(DIALOG_TITLE);
+ this.attr = Util.unPackTextAttr(bundle.getBundle(DIALOG_ATTR));
+ }
+ }
+
+ // Container to store message dialog parameters.
+ private class MsgDialogParams extends DialogParams {
+ // Constants
+ private static final String MSG_DIALOG_RES = "MsgDialog.response";
+ private static final String MSG_DIALOG_CONIF = "MsgDialog.confirmed";
+
+ // Message dialog specific parameters.
+ boolean responseNeeded;
+ Object terminationLock;
+
+ MsgDialogParams() {
+ super();
+ responseNeeded = false;
+ terminationLock = new Object();
+ }
+
+ void setTimer() {
+ dismissTimer();
+ timeoutWatchDog = new WatchDog(null, mHandler,
+ new RunTerminateMsgDialog(), StkApp.UI_TIMEOUT);
+ }
+
+ void packParams(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ super.packParams(bundle);
+ bundle.putBoolean(MSG_DIALOG_RES, this.responseNeeded);
+ }
+
+ void unPackParams(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ super.unPackParams(bundle);
+ this.responseNeeded = bundle.getBoolean(MSG_DIALOG_RES);
+ }
+ }
+
+ // Container to store browser dialog parameters.
+ private class BrowserDialogParams extends DialogParams {
+ // Constants
+ private static final String BROWSER_DIALOG_URI = "BrowserDialog.uri";
+ private static final String BROWSER_DIALOG_MODE = "BrowserDialog.mode";
+
+ // Browser dialog specific parameters.
+ Uri uri;
+ LaunchBrowserMode mode;
+
+ BrowserDialogParams() {
+ super();
+ // Set default uri.
+ uri = Uri.parse("file:///android_asset/html/home.html");
+ mode = LaunchBrowserMode.LAUNCH_NEW_BROWSER;
+ }
+
+ void setTimer() {
+ dismissTimer();
+ timeoutWatchDog = new WatchDog(null, mHandler,
+ new RunTerminateBrowserDialog(), StkApp.UI_TIMEOUT);
+ }
+
+ void packParams(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ super.packParams(bundle);
+ if (this.uri != null) {
+ bundle.putString(BROWSER_DIALOG_URI, this.uri.toString());
+ }
+ if (this.mode != null) {
+ bundle.putInt(BROWSER_DIALOG_MODE, this.mode.ordinal());
+ }
+ }
+
+ void unPackParams(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ super.unPackParams(bundle);
+ String uriValue = bundle.getString(BROWSER_DIALOG_URI);
+ if (uriValue != null) {
+ this.uri = Uri.parse(uriValue);
+ }
+ int modeValue = bundle.getInt(BROWSER_DIALOG_MODE);
+ if (modeValue != 0) {
+ this.mode = LaunchBrowserMode.values() [modeValue];
+ }
+ }
+ }
+
+ private class CallDialogParams extends DialogParams {
+ // Constants
+ private static final String CALL_DIALOG_MSG = "CallDialog.message";
+
+ String callMsg;
+
+ CallDialogParams() {
+ super();
+ }
+
+ CallDialogParams(String text, TextAttribute attr, String title,
+ String callMsg) {
+ super(text, attr, title, null);
+ this.callMsg = callMsg;
+ }
+
+ void packParams(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ bundle.putString(CALL_DIALOG_MSG, callMsg);
+ }
+
+ void unPackParams(Bundle bundle) {
+ if (bundle == null) {
+ return;
+ }
+ callMsg = bundle.getString(CALL_DIALOG_MSG);
+ }
+ }
+
+ // Runnable to be executed when message dialog are timed out.
+ private class RunTerminateMsgDialog implements Runnable {
+ public void run() {
+ terminateMsgDialog(ResultCode.NO_RESPONSE_FROM_USER);
+ }
+ }
+
+ // Runnable to be terminate browser confirmation dialog.
+ private class RunTerminateBrowserDialog implements Runnable {
+ public void run() {
+ terminateBrowserDialog(false, true);
+ }
+ }
+
+ // Runnable to be notify STK service user didn't respond to display text
+ // command.
+ private class OnNoResponse implements Runnable {
+ public void run() {
+ mStkService.notifyNoResponse();
+ mUiState = UI_STATE_IDLE;
+ }
+ }
+
+ // Runnable to trigger refresh view on session end.
+ private class RunRefeshViewOnSessionEnd implements Runnable {
+ public void run() {
+ refreshViewOnSessionEnd();
+ }
+ }
+
+ /**
+ * Handler used to stop tones from playing when the duration ends.
+ */
+ Handler mToneStopper = new Handler() {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case STOP_TONE_MSG:
+ terminateTone();
+ break;
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ int dialogId = NO_DIALOG_ID;
+ super.onCreate(icicle);
+
+ // Remove the default title, customized one is used.
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ // Set the layout for this activity.
+ setContentView(R.layout.stk_menu_list);
+
+ mTitleText = (TextView) findViewById(R.id.title_text);
+ mTitleIcon = (ImageView) findViewById(R.id.title_icon);
+
+ // Initialize members
+ mStkService = Service.getInstance();
+ if (mStkService == null) {
+ Log.d(TAG, "Unable to get application handle ==> Activity stoped");
+ finish();
+ }
+
+ // Instantiate members
+ mHandler = new Handler();
+ mMsgDialogSync = new Object();
+ mActiveMsgDialogEvent = new DialogEvent();
+ mActiveBrowserDialogEvent = new DialogEvent();
+
+ // Synchronize application state with the service, only if it's on main
+ // state. This is usually true when the application is launched for the
+ // first time. Otherwise the application state will be preserved using
+ // onSaveInstanceState(...) & onRestoreInstaceState(...).
+ if (mStkService.getState() == AppInterface.State.MAIN_MENU) {
+ mUiState = UI_STATE_MAIN;
+ mCurrentMenu = mStkService.getCurrentMenu();
+ }
+ }
+
+ public void onClick(View v) {
+ switch(v.getId()) {
+ case R.id.button_ok:
+ // used on message dialog.
+ terminateMsgDialog(ResultCode.OK);
+ break;
+ case R.id.button_no:
+ // used on launch browser dialog.
+ terminateBrowserDialog(false, true);
+ break;
+ case R.id.button_yes:
+ // used on launch browser dialog.
+ terminateBrowserDialog(true, true);
+ break;
+ case R.id.button_call:
+ // used on set up call dialog.
+ terminateCallConfirmDialog(true, true);
+ break;
+ // used on set up call dialog.
+ case R.id.button_cancel:
+ terminateCallConfirmDialog(false, true);
+ break;
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ // Setting stk service command listener to null will stop the service
+ // from trying to send messages when the app is paused.
+ mStkService.setCommandListener(null);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ // Set stk service command listener to receive proactive commands.
+ mStkService.setCommandListener(this.new StkCmdListener());
+
+ // If application is resumed from call setup go back to the menu state.
+ if (mUiState == UI_STATE_IN_CALL_SETUP_DIALOG) {
+ switch (mStkService.getState()) {
+ case SELECT_ITEM:
+ mUiState = UI_STATE_SELECT;
+ break;
+ case MAIN_MENU:
+ mUiState = UI_STATE_MAIN;
+ mCurrentMenu = mStkService.getCurrentMenu();
+ break;
+ default:
+ mStkService.terminateSession();
+ return;
+ }
+ }
+
+ // Render application view.
+ refreshView();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mTimeoutWatchDog != null) {
+ mTimeoutWatchDog.cancel();
+ }
+
+ // If Toneplayer was used, release it's resources.
+ if (mTonePlayer != null) {
+ mTonePlayer.release();
+ }
+ }
+
+ @Override
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+ super.onListItemClick(l, v, position, id);
+
+ AppInterface.State state = mStkService.getState();
+ Item item = getSelectedItem(position);
+ if (item == null) {
+ return;
+ }
+ switch (state) {
+ case MAIN_MENU:
+ // Notify the SIM about the menu selection id.
+ mStkService.notifyMenuSelection(item.id, false);
+ break;
+ case SELECT_ITEM:
+ // Terminate timeout watchdog for SELECT_ITEM.
+ if (mTimeoutWatchDog != null) {
+ mTimeoutWatchDog.cancel();
+ }
+ // Save item string for display purposes.
+ mSelectedItem = mCurrentMenu.items.get(position).toString();
+ // Notify the SIM about the item selection id.
+ mStkService.notifySelectedItem(item.id, false);
+ break;
+ default:
+ // If application and service are not synchronized, terminate
+ // the current session.
+ mStkService.terminateSession();
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ switch (mUiState) {
+ case UI_STATE_SELECT:
+ cancelTimeOut();
+ // Signal stk service to go back, if failed go to the main menu.
+ if (!mStkService.backwardMove()) {
+ mStkService.terminateSession();
+ }
+ mUiState = UI_STATE_IDLE;
+ return true;
+ case UI_STATE_MAIN:
+ mUiState = UI_STATE_IDLE;
+ break;
+ }
+ break;
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ resetTimeOut();
+ return super.onTrackballEvent(event);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ resetTimeOut();
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ Bundle extras = null;
+ boolean helpRequired = false;
+ boolean yesNoResponse = false;
+ String inputResponse = null;
+ char inKeyResponse = 'F';
+
+ if (data != null) {
+ extras = data.getExtras();
+ }
+
+ switch (resultCode) {
+ case StkApp.RESULT_HELP:
+ helpRequired = true;
+ case StkApp.RESULT_OK:
+ switch (requestCode) {
+ case ACTIVITY_GET_INPUT:
+ if (extras != null) {
+ inputResponse = extras.getString(Util.INPUT_TYPE_TEXT);
+ }
+ mStkService.notifyInput(inputResponse, helpRequired);
+ break;
+ case ACTIVITY_GET_INKEY:
+ if (extras != null) {
+ inKeyResponse = extras.getChar(Util.INPUT_TYPE_KEY);
+ }
+ mStkService.notifyInkey(inKeyResponse, helpRequired);
+ break;
+ case ACTIVITY_GET_INKEY_YESNO:
+ if (extras != null) {
+ yesNoResponse = extras.getBoolean(Util.INPUT_TYPE_KEY);
+ }
+ mStkService.notifyInkey(yesNoResponse, helpRequired);
+ break;
+ case ACTIVITY_BROWSER:
+ // Handle browser termination event
+ if (getEventStatus(Service.UICC_EVENT_BROWSER_TERMINATION)) {
+ setEventStatus(Service.UICC_EVENT_BROWSER_TERMINATION,
+ false);
+ mStkService.notifyBrowserTermination(false);
+ break;
+ }
+ case ACTIVITY_CALL:
+ break;
+ }
+ break;
+ case StkApp.RESULT_TIMEDOUT:
+ mStkService.notifyNoResponse();
+ break;
+ case StkApp.RESULT_BACKWARD:
+ mStkService.backwardMove();
+ break;
+ case StkApp.RESULT_END_SESSION:
+ mStkService.terminateSession();
+ break;
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(android.view.Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ menu.add(0, StkApp.MENU_ID_MAIN, 1, R.string.sim_main_menu);
+ menu.add(0, StkApp.MENU_ID_HELP, 2, R.string.help);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(android.view.Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ boolean helpVisible = false;
+ boolean mainVisible = false;
+
+ if (mUiState == UI_STATE_SELECT) {
+ mainVisible = true;
+ }
+ if (mCurrentMenu != null) {
+ helpVisible = mCurrentMenu.helpAvailable;
+ }
+
+ menu.findItem(StkApp.MENU_ID_MAIN).setVisible(mainVisible);
+ menu.findItem(StkApp.MENU_ID_HELP).setVisible(helpVisible);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case StkApp.MENU_ID_MAIN:
+ // Cancel timeout thread.
+ cancelTimeOut();
+ // Terminate SIM session
+ mStkService.terminateSession();
+ // Set ui state to idle.
+ mUiState = UI_STATE_IDLE;
+ return true;
+ case StkApp.MENU_ID_HELP:
+ int position = getSelectedItemPosition();
+ Item stkItem = getSelectedItem(position);
+ if (item == null) {
+ break;
+ }
+ switch(mUiState) {
+ case UI_STATE_MAIN:
+ mStkService.notifyMenuSelection(stkItem.id, true);
+ break;
+ case UI_STATE_SELECT:
+ mStkService.notifySelectedItem(stkItem.id, true);
+ break;
+ }
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ if (StkApp.DBG) Log.d(TAG, "onSaveInstanceState");
+
+ super.onSaveInstanceState(outState);
+
+ // Setting stk service command listener to null will stop the service
+ // from trying to send messages while the state is being saved.
+ // This function is also called in onPause for cases where state is not
+ // preserved.
+ mStkService.setCommandListener(null);
+
+ outState.putInt(UI_STATE, mUiState);
+ outState.putParcelable(STK_MENU, mCurrentMenu);
+
+ // Preserve dialog parameters
+ switch (mUiState) {
+ case UI_STATE_IN_MSG_DIALOG:
+ mMsgDialogParams.packParams(outState);
+ mMsgDialogParams.responseNeeded = false;
+ terminateMsgDialog();
+ removeDialog(MSG_DIALOG_ID);
+ break;
+ case UI_STATE_IN_BROWSER_DIALOG:
+ mBrowserDialogParams.packParams(outState);
+ terminateBrowserDialog(false, false);
+ removeDialog(BROWSER_DIALOG_ID);
+ break;
+ case UI_STATE_IN_CALL_CONFIRM_DIALOG:
+ mCallDialogParams.packParams(outState);
+ terminateCallConfirmDialog(false, false);
+ removeDialog(CALL_CONFIRM_DIALOG_ID);
+ break;
+ case UI_STATE_IN_CALL_SETUP_DIALOG:
+ dismissDialog(CALL_SETUP_DIALOG_ID);
+ removeDialog(CALL_SETUP_DIALOG_ID);
+ break;
+ case UI_STATE_PLAY_TONE:
+ mToneStopper.removeMessages(STOP_TONE_MSG);
+ terminateTone();
+ // Once playing the tone is done the session is ended so the application
+ // should go back to main state.
+ outState.putInt(UI_STATE, UI_STATE_MAIN);
+ break;
+ }
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ if (StkApp.DBG) Log.d(TAG, "onRestoreInstanceState");
+
+ super.onRestoreInstanceState(savedInstanceState);
+
+ mUiState = savedInstanceState.getInt(UI_STATE);
+ mCurrentMenu = savedInstanceState.getParcelable(STK_MENU);
+
+ switch (mUiState) {
+ case UI_STATE_IN_MSG_DIALOG:
+ MsgDialogParams m = new MsgDialogParams();
+ m.unPackParams(savedInstanceState);
+ prepareMsgDialog(m.text, m.attr, m.title, m.responseNeeded, m.icon);
+ break;
+ case UI_STATE_IN_BROWSER_DIALOG:
+ mBrowserDialogParams.unPackParams(savedInstanceState);
+ break;
+ case UI_STATE_IN_CALL_CONFIRM_DIALOG:
+ mCallDialogParams.unPackParams(savedInstanceState);
+ break;
+ }
+ }
+
+ private Item getSelectedItem(int position) {
+ Item item = null;
+ if (mCurrentMenu != null) {
+ try {
+ item = mCurrentMenu.items.get(position);
+ } catch (IndexOutOfBoundsException e) {
+ if (StkApp.DBG) {
+ Log.d(TAG, "Invalid menu");
+ }
+ } catch (NullPointerException e) {
+ if (StkApp.DBG) {
+ Log.d(TAG, "Invalid menu");
+ }
+ }
+ }
+ return item;
+ }
+
+ // Bind list adapter to the items list.
+ private void displayMenu() {
+
+ if (mCurrentMenu != null) {
+ // create an array adapter for the menu list
+ StkMenuAdapter adapter = new StkMenuAdapter(this,
+ mCurrentMenu.items, mCurrentMenu.itemsIconSelfExplanatory);
+ // Bind menu list to the new adapter.
+ setListAdapter(adapter);
+
+ // Display title & title icon
+ if (mCurrentMenu.titleIcon != null) {
+ mTitleIcon.setImageBitmap(mCurrentMenu.titleIcon);
+ } else {
+ mTitleIcon.setVisibility(View.GONE);
+ }
+ if (!mCurrentMenu.titleIconSelfExplanatory) {
+ if (mCurrentMenu.title == null) {
+ mTitleText.setText(R.string.app_name);
+ } else {
+ mTitleText.setText(mCurrentMenu.title);
+ }
+ }
+ // Set default item
+ setSelection(mCurrentMenu.defaultItem);
+ }
+ }
+
+ private void refreshView() {
+ displayMenu();
+
+ // In case a dialog needs to be refreshed.
+ switch (mUiState) {
+ case UI_STATE_IN_MSG_DIALOG:
+ launchMsgDialog();
+ break;
+ case UI_STATE_IN_BROWSER_DIALOG:
+ launchBrowserDialog();
+ break;
+ case UI_STATE_IN_CALL_CONFIRM_DIALOG:
+ launchCallConfirmDialog();
+ break;
+ default:
+ return;
+ }
+ }
+
+ private void refreshViewOnSessionEnd() {
+ cancelTimeOut();
+ switch (mStkService.getState()) {
+ case MAIN_MENU:
+ mUiState = UI_STATE_MAIN;
+ mCurrentMenu = mStkService.getCurrentMenu();
+ refreshView();
+ break;
+ case IDLE:
+ finish();
+ break;
+ }
+ }
+
+ private void resetTimeOut() {
+ if (mTimeoutWatchDog != null) {
+ // Reset timeout.
+ mTimeoutWatchDog.reset();
+ }
+ }
+
+ private void cancelTimeOut() {
+ if (mTimeoutWatchDog != null) {
+ // Reset timeout.
+ mTimeoutWatchDog.cancel();
+ }
+ }
+
+ private void pauseTimeOut() {
+ if (mTimeoutWatchDog != null) {
+ // Reset timeout.
+ mTimeoutWatchDog.pause();
+ }
+ }
+
+ private void resumeTimeOut() {
+ if (mTimeoutWatchDog != null) {
+ // Reset timeout.
+ mTimeoutWatchDog.unpause();
+ }
+ }
+
+ private void prepareDialog(DialogParams params, String text,
+ TextAttribute attr, String title, Bitmap icon) {
+ if (params == null) return;
+
+ params.text = text;
+ params.attr = attr;
+ params.title = title;
+ params.icon = icon;
+ }
+
+ // Set text dialog parameters into a member.
+ private void prepareMsgDialog(String text, TextAttribute attrs,
+ String title, boolean responseNeeded, Bitmap icon) {
+ synchronized (mMsgDialogSync) {
+ prepareDialog(mNextMsgDialogParams, text, attrs, title, icon);
+ mNextMsgDialogParams.responseNeeded = responseNeeded;
+ }
+ }
+
+ // Set text dialog parameters into a member.
+ private void prepareBrowserDialog(String text, TextAttribute attrs,
+ String title, Uri uri, LaunchBrowserMode mode) {
+
+ prepareDialog(mBrowserDialogParams, text, attrs, title, null);
+ mBrowserDialogParams.uri = uri;
+ mBrowserDialogParams.mode = mode;
+ }
+
+ private void prepareCallDialog(String text, TextAttribute attrs,
+ String title, String callMsg) {
+ prepareDialog(mCallDialogParams, text, attrs, title, null);
+ mCallDialogParams.callMsg = callMsg;
+ }
+
+ // Opens display text dialog. MUST be preceded by prepareMsgDialog(...)
+ private void launchMsgDialog() {
+ // Pause timeout thread for Select Item.
+ pauseTimeOut();
+ mUiState = UI_STATE_IN_MSG_DIALOG;
+ mActiveMsgDialogEvent.unSet();
+ synchronized (mMsgDialogSync) {
+ mMsgDialogParams = mNextMsgDialogParams;
+ }
+ mMsgDialogParams.setTimer();
+ showDialog(MSG_DIALOG_ID);
+ }
+
+ // Opens display browser confirmation dialog. MUST be preceded by
+ // prepareBrowserDialog(...)
+ private void launchBrowserDialog() {
+ mUiState = UI_STATE_IN_BROWSER_DIALOG;
+ mActiveBrowserDialogEvent.unSet();
+ mBrowserDialogParams.setTimer();
+ showDialog(BROWSER_DIALOG_ID);
+ }
+
+ // Opens call/cancel confirmation dialog
+ private void launchCallConfirmDialog() {
+ mUiState = UI_STATE_IN_CALL_CONFIRM_DIALOG;
+ showDialog(CALL_CONFIRM_DIALOG_ID);
+ }
+
+ // Opens setup call dialog
+ private void launchCallSetupDialog() {
+ mUiState = UI_STATE_IN_CALL_SETUP_DIALOG;
+ showDialog(CALL_SETUP_DIALOG_ID);
+ }
+
+ // Same as terminateMsgDialog(), with additional ResultCode send to the STK
+ // Service.
+ private void terminateMsgDialog(ResultCode terminationCode) {
+ terminateMsgDialog();
+ if (mMsgDialogParams.responseNeeded) {
+ mStkService.notifyDisplayTextEnded(terminationCode);
+ }
+ }
+
+ private void terminateMsgDialog() {
+ synchronized (mMsgDialogParams.terminationLock) {
+ dismissDialog(MSG_DIALOG_ID);
+ mMsgDialogParams.dismissTimer();
+ // Resume timeout thread for Select Item.
+ resumeTimeOut();
+ if (mLaunchNextDialog == true) {
+ synchronized (this) {
+ mLaunchNextDialog = false;
+ }
+ launchMsgDialog();
+ } else {
+ mUiState = UI_STATE_IDLE;
+ // signal message dialog event.
+ mActiveMsgDialogEvent.set();
+ }
+ }
+ }
+
+ private void terminateBrowserDialog(boolean userConfirmed,
+ boolean notifyService) {
+ dismissDialog(BROWSER_DIALOG_ID);
+ mBrowserDialogParams.dismissTimer();
+ if (userConfirmed) {
+ launchBrowser(mBrowserDialogParams.uri, mBrowserDialogParams.mode);
+ }
+ if (notifyService) {
+ mStkService.notifyLaunchBrowser(userConfirmed);
+ }
+ mUiState = UI_STATE_IDLE;
+ // signal browser dialog event.
+ mActiveBrowserDialogEvent.set();
+ }
+
+ private void terminateCallConfirmDialog(boolean call, boolean notifyService) {
+ dismissDialog(CALL_CONFIRM_DIALOG_ID);
+ if (call) {
+ if (mCallDialogParams.callMsg == null) {
+ mCallDialogParams.callMsg = getString(R.string.default_call_setup_msg);
+ }
+ launchCallSetupDialog();
+ } else {
+ mUiState = UI_STATE_IDLE;
+ }
+ if (notifyService) {
+ mStkService.acceptOrRejectCall(call);
+ }
+ }
+
+ private void terminateTone() {
+ if (mTonePlayer != null) {
+ mTonePlayer.stop();
+ mStkService.notifyToneEnded();
+ }
+ mUiState = UI_STATE_IDLE;
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ Dialog dialog = null;
+ if (id == CALL_SETUP_DIALOG_ID) {
+ dialog = new ProgressDialog(this);
+ dialog.setCancelable(false);
+ ((ProgressDialog) dialog).setMessage(mCallDialogParams.callMsg);
+ ((ProgressDialog) dialog).setIndeterminate(true);
+ } else {
+ dialog = new Dialog(this);
+
+ switch (id) {
+ case MSG_DIALOG_ID:
+ dialog.setContentView(R.layout.stk_msg_dialog);
+ break;
+ case BROWSER_DIALOG_ID:
+ dialog.setContentView(R.layout.stk_input);
+
+ View yesNoLayout = dialog.findViewById(R.id.yes_no_layout);
+ View normalLayout = dialog.findViewById(R.id.normal_layout);
+
+ yesNoLayout.setVisibility(View.VISIBLE);
+ normalLayout.setVisibility(View.GONE);
+ break;
+ case CALL_CONFIRM_DIALOG_ID:
+ dialog.setContentView(R.layout.stk_call_dialog);
+ break;
+ }
+ }
+ return dialog;
+ }
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ DialogParams currentDialogParams = null;
+ TextView promptView = null;
+ ImageView imageView = null;
+
+ switch (id) {
+ case MSG_DIALOG_ID:
+ currentDialogParams = mMsgDialogParams;
+ promptView = (TextView) dialog.findViewById(R.id.dialog_message);
+ imageView = (ImageView) dialog.findViewById(R.id.dialog_icon);
+ Button b = (Button) dialog.findViewById(R.id.button_ok);
+ b.setOnClickListener(this);
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
+ public boolean onKey(DialogInterface dialog, int keyCode,
+ KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ terminateMsgDialog(ResultCode.BACKWARD_MOVE_BY_USER);
+ break;
+ }
+ return false;
+ }
+ });
+ break;
+ case CALL_CONFIRM_DIALOG_ID:
+ currentDialogParams = mCallDialogParams;
+ promptView = (TextView) dialog.findViewById(R.id.prompt);
+ Button call = (Button) dialog.findViewById(R.id.button_call);
+ Button cancel = (Button) dialog.findViewById(R.id.button_cancel);
+ call.setOnClickListener(this);
+ cancel.setOnClickListener(this);
+ dialog.setCancelable(false);
+ break;
+ case BROWSER_DIALOG_ID:
+ currentDialogParams = mBrowserDialogParams;
+ promptView = (TextView) dialog.findViewById(R.id.prompt);
+ Button y = (Button) dialog.findViewById(R.id.button_yes);
+ Button n = (Button) dialog.findViewById(R.id.button_no);
+ y.setOnClickListener(this);
+ n.setOnClickListener(this);
+ dialog.setCancelable(false);
+ break;
+ default:
+ return;
+ }
+ // Set prompt and title.
+ promptView.setText(currentDialogParams.text);
+ // Set title if present... if not remove it from the layout.
+ if (currentDialogParams.title != null) {
+ dialog.setTitle(currentDialogParams.title);
+ } else {
+ View t = dialog.findViewById(android.R.id.title);
+ t.setVisibility(View.GONE);
+ }
+ if(currentDialogParams.icon != null) {
+ imageView.setImageBitmap(currentDialogParams.icon);
+ } else if (imageView != null) {
+ imageView.setVisibility(View.GONE);
+ }
+ }
+
+ // Opens the browser
+ private void launchBrowser(Uri uri, LaunchBrowserMode mode) {
+ // Set browser launch mode
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClassName("com.android.browser",
+ "com.android.browser.BrowserActivity");
+ intent.setData(uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ switch (mode) {
+ case USE_EXISTING_BROWSER:
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ break;
+ case LAUNCH_NEW_BROWSER:
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ break;
+ case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ break;
+ }
+ // start browser activity
+ startActivity(intent);
+ }
+
+ private void updateEventsSet(BitSet events) {
+ mStkEvents.or(events);
+ }
+
+ private void setEventStatus(int event, boolean state) {
+ if (mStkEvents == null) return;
+
+ mStkEvents.set(event, state);
+ }
+
+ private boolean getEventStatus(int event) {
+ if (mStkEvents == null) return false;
+
+ return mStkEvents.get(event);
+ }
+
+ // Private inner class, implements CommandListener I/F to get callback calls
+ // from the STK service.
+ private class StkCmdListener implements CommandListener {
+
+ public void onCallSetup(String confirmMsg, List<TextAttribute> textAttrs,
+ String callMsg) {
+ if (StkApp.DBG) Log.d(TAG, "onCallSetup");
+
+ TextAttribute attr = null;
+ String title = getString(R.string.launch_dialer);
+
+ if (textAttrs != null && textAttrs.size() > 0) {
+ attr = textAttrs.get(0);
+ }
+ // Launch call confirmation dialog.
+ prepareCallDialog(confirmMsg, attr, title, callMsg);
+ launchCallConfirmDialog();
+ }
+
+ public void onDisplayText(String text, List<TextAttribute> textAttrs,
+ boolean isHighPriority, boolean userClear,
+ boolean responseNeeded, Bitmap icon) {
+
+ if (StkApp.DBG) Log.d(TAG, "onDisplayText: " + text);
+
+ // Store dialog parameters to be used just before dialog creation.
+ TextAttribute attr = null;
+ if (textAttrs != null && textAttrs.size() > 0) {
+ attr = textAttrs.get(0);
+ }
+ prepareMsgDialog(text, attr, null, responseNeeded, icon);
+
+ // If there is an active message dialog, signal to launch a new dialog
+ // when the current one is done.
+ if (mUiState == UI_STATE_IN_MSG_DIALOG) {
+ synchronized (StkActivity.this) {
+ mLaunchNextDialog = true;
+ }
+ if (isHighPriority) {
+ terminateMsgDialog(ResultCode.OK);
+ }
+ } else {
+ launchMsgDialog();
+ }
+ }
+
+ public void onSetUpMenu(com.android.internal.telephony.gsm.stk.Menu menu) {
+ if (StkApp.DBG) Log.d(TAG, "onSetUpMenu");
+
+ mUiState = UI_STATE_MAIN;
+ mCurrentMenu = menu;
+ displayMenu();
+ }
+
+ public void onGetInkey(String text, List<TextAttribute> textAttrs,
+ boolean yesNo, boolean digitOnly, boolean ucs2,
+ boolean immediateResponse, boolean helpAvailable) {
+
+ if (StkApp.DBG) Log.d(TAG, "onGetInkey" + text);
+
+ Intent intent = new Intent(StkActivity.this, StkInputActivity.class);
+ int subActivityId = yesNo ? ACTIVITY_GET_INKEY_YESNO
+ : ACTIVITY_GET_INKEY;
+
+ // put command data inside the intent.
+ intent.putExtra(Util.INPUT_TYPE, Util.INPUT_TYPE_KEY);
+ intent.putExtra(Util.INPUT_PROMPT, text);
+
+ if (textAttrs != null && textAttrs.size() > 0) {
+ TextAttribute attr = textAttrs.get(0);
+ Bundle texttAttrBundle;
+ if (attr != null) {
+ texttAttrBundle = Util.packTextAttr(attr);
+ intent.putExtra(Util.INPUT_TEXT_ATTRS, texttAttrBundle);
+ }
+ }
+ // Pack the global input attributes into the intent.
+ Bundle glblAttrBundle = new Bundle();
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_YES_NO, yesNo);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_DIGITS, digitOnly);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_UCS2, ucs2);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_IMD_RESPONSE,
+ immediateResponse);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_HELP, helpAvailable);
+ intent.putExtra(Util.INPUT_GLBL_ATTRS, glblAttrBundle);
+
+ // Start the input sub activity
+ startActivityForResult(intent, subActivityId);
+ }
+
+ public void onGetInput(String text, String defaultText, int minLen,
+ int maxLen, boolean noMaxLimit, List<TextAttribute> textAttrs,
+ boolean digitOnly, boolean ucs2, boolean echo,
+ boolean helpAvailable) {
+
+ if (StkApp.DBG) Log.d(TAG, "onGetInput: " + text);
+
+ Intent intent = new Intent(StkActivity.this, StkInputActivity.class);
+ // put command data inside the intent.
+ intent.putExtra(Util.INPUT_TYPE, Util.INPUT_TYPE_TEXT);
+ intent.putExtra(Util.INPUT_PROMPT, text);
+ if (defaultText != null) {
+ intent.putExtra(Util.INPUT_DEFAULT, defaultText);
+ }
+
+ // Pack text attributes into the intent.
+ if (textAttrs != null && textAttrs.size() > 0) {
+ TextAttribute attr = textAttrs.get(0);
+ if (attr != null) {
+ Bundle texttAttrBundle = Util.packTextAttr(attr);
+ intent.putExtra(Util.INPUT_TEXT_ATTRS, texttAttrBundle);
+ }
+ }
+ // Pack the global input attributes into the intent.
+ Bundle glblAttrBundle = new Bundle();
+ glblAttrBundle.putInt(Util.INPUT_ATTR_MINLEN, minLen);
+ glblAttrBundle.putInt(Util.INPUT_ATTR_MAXLEN, maxLen);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_NOMAAXLIM, noMaxLimit);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_DIGITS, digitOnly);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_UCS2, ucs2);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_ECHO, echo);
+ glblAttrBundle.putBoolean(Util.INPUT_ATTR_HELP, helpAvailable);
+ intent.putExtra(Util.INPUT_GLBL_ATTRS, glblAttrBundle);
+
+ // Start the input sub activity
+ startActivityForResult(intent, ACTIVITY_GET_INPUT);
+ }
+
+ public void onSelectItem(com.android.internal.telephony.gsm.stk.Menu menu,
+ PresentationType presentationType) {
+
+ if (StkApp.DBG) Log.d(TAG, "onSelectItem: " + menu.title);
+
+ mCurrentMenu = menu;
+
+ // If activity is already inside a message dialog, launch the next
+ // item list when that message is dismissed.
+ if (mUiState != UI_STATE_IN_MSG_DIALOG) {
+ mUiState = UI_STATE_SELECT;
+ displayMenu();
+ // launch timeout watchdog to signal no response from user.
+ mTimeoutWatchDog = new WatchDog(null, mHandler,
+ new OnNoResponse(), StkApp.UI_TIMEOUT);
+ } else {
+ new WatchDog(mActiveMsgDialogEvent, mHandler, new Runnable() {
+ public void run() {
+ mUiState = UI_STATE_SELECT;
+ displayMenu();
+ // launch timeout wathdog to signal no response from
+ // user.
+ mTimeoutWatchDog = new WatchDog(null, mHandler,
+ new OnNoResponse(), StkApp.UI_TIMEOUT);
+ }
+ }, WatchDog.TIMEOUT_WAIT_FOREVER);
+ }
+ }
+
+ public void onSetUpEventList(BitSet events) throws ResultException {
+ if (StkApp.DBG) Log.d(TAG, "onSetUpEventList");
+
+ if (events == null || events.isEmpty()) {
+ throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
+ }
+
+ updateEventsSet(events);
+ }
+
+ public void onLaunchBrowser(String url, String confirmMsg,
+ List<TextAttribute> confirmMsgAttrs,
+ final LaunchBrowserMode mode) {
+ if (StkApp.DBG) Log.d(TAG, "onLaunchBrowser: " + url);
+
+ TextAttribute attrs = null;
+ String title = getString(R.string.launch_browser);
+ Uri uri = url == null ? null : Uri.parse(url);
+
+ // Launch browser confirmation dialog.
+ if (confirmMsg != null) {
+ if (confirmMsgAttrs != null && confirmMsgAttrs.size() > 0) {
+ attrs = confirmMsgAttrs == null ? null : confirmMsgAttrs
+ .get(0);
+ }
+ prepareBrowserDialog(confirmMsg, attrs, title, uri, mode);
+ launchBrowserDialog();
+ } else {
+ mStkService.notifyLaunchBrowser(true);
+ launchBrowser(uri, mode);
+ }
+ }
+
+ public void onPlayTone(Tone tone, String text,
+ List<TextAttribute> textAttrs, Duration duration)
+ throws ResultException {
+ if (StkApp.DBG) Log.d(TAG, "onPlayTone:" + tone + " Message:" + text);
+
+ if (text != null) {
+ String title = getString(R.string.play_tone);
+ TextAttribute attrs = textAttrs == null ? null : textAttrs
+ .get(0);
+ prepareMsgDialog(text, attrs, title, false, null);
+ launchMsgDialog();
+ }
+ if (mTonePlayer == null) {
+ mTonePlayer = new TonePlayer();
+ }
+ mTonePlayer.play(tone);
+ int timeout = StkApp.calculateToneDuration(duration);
+ mToneStopper.sendEmptyMessageDelayed(STOP_TONE_MSG, timeout);
+ mUiState = UI_STATE_PLAY_TONE;
+ }
+
+ public void onSessionEnd() {
+ if (StkApp.DBG) Log.d(TAG, "onSessionEnd");
+
+ // If any message dialog is active wait until it is finish before
+ // the refreshing the view.
+ synchronized (mMsgDialogParams.terminationLock) {
+ if (mUiState == UI_STATE_IN_MSG_DIALOG) {
+ new WatchDog(mActiveMsgDialogEvent,
+ StkActivity.this.mHandler,
+ new RunRefeshViewOnSessionEnd(),
+ WatchDog.TIMEOUT_WAIT_FOREVER);
+ } else {
+ refreshViewOnSessionEnd();
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/stk/StkApp.java b/src/com/android/stk/StkApp.java
new file mode 100644
index 0000000..cabbb19
--- /dev/null
+++ b/src/com/android/stk/StkApp.java
@@ -0,0 +1,69 @@
+/*
+ * 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.stk;
+
+import android.app.Activity;
+import android.app.Application;
+import com.android.internal.telephony.gsm.stk.Duration;
+
+/**
+ * Top-level Application class for the Phone app.
+ */
+public class StkApp extends Application {
+ // Application constants
+ public static final boolean DBG = true;
+
+ // Result values for sub activities started by the main StkActivity.
+ static final int RESULT_OK = Activity.RESULT_OK;
+ static final int RESULT_TIMEDOUT = RESULT_OK + 10;
+ static final int RESULT_BACKWARD = RESULT_OK + 11;
+ static final int RESULT_HELP = RESULT_OK + 12;
+ static final int RESULT_END_SESSION = RESULT_OK + 20;
+
+ // Identifiers for option menu items
+ static final int MENU_ID_MAIN = android.view.Menu.FIRST;
+ static final int MENU_ID_HELP = android.view.Menu.FIRST + 1;
+
+ // UI timeout, 30 seconds - used for display dialog and activities.
+ static final int UI_TIMEOUT = (20 * 1000);
+
+ // Tone default timeout - 2 seconds
+ static final int TONE_DFEAULT_TIMEOUT = (2 * 1000);
+
+ /**
+ * This function calculate the time in MS a tone should be played.
+ */
+ public static int calculateToneDuration(Duration duration) {
+ int timeout = TONE_DFEAULT_TIMEOUT;
+ if (duration != null) {
+ switch (duration.timeUnit) {
+ case MINUTE:
+ timeout = 1000 * 60;
+ break;
+ case TENTH_SECOND:
+ timeout = 1000 * 10;
+ break;
+ case SECOND:
+ default:
+ timeout = 1000;
+ break;
+ }
+ timeout *= duration.timeInterval;
+ }
+ return timeout;
+ }
+}
diff --git a/src/com/android/stk/StkDigitsKeyListener.java b/src/com/android/stk/StkDigitsKeyListener.java
new file mode 100644
index 0000000..475b932
--- /dev/null
+++ b/src/com/android/stk/StkDigitsKeyListener.java
@@ -0,0 +1,49 @@
+/*
+ * 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.stk;
+
+import android.text.method.NumberKeyListener;
+import android.view.KeyEvent;
+
+/**
+ * For entering dates in a text field.
+ */
+public class StkDigitsKeyListener extends NumberKeyListener {
+ @Override
+ protected char[] getAcceptedChars() {
+ return CHARACTERS;
+ }
+
+ public static StkDigitsKeyListener getInstance() {
+ if (sInstance != null) {
+ return sInstance;
+ }
+ sInstance = new StkDigitsKeyListener();
+ return sInstance;
+ }
+
+ /**
+ * The characters that are used.
+ *
+ * @see KeyEvent#getMatch
+ * @see #getAcceptedChars
+ */
+ public static final char[] CHARACTERS = new char[] {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', '+'};
+
+ private static StkDigitsKeyListener sInstance;
+}
diff --git a/src/com/android/stk/StkInputActivity.java b/src/com/android/stk/StkInputActivity.java
new file mode 100644
index 0000000..d629ef3
--- /dev/null
+++ b/src/com/android/stk/StkInputActivity.java
@@ -0,0 +1,366 @@
+/*
+ * 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.stk;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import com.android.internal.telephony.gsm.stk.AppInterface;
+import com.android.internal.telephony.gsm.stk.FontSize;
+import com.android.internal.telephony.gsm.stk.Service;
+import com.android.internal.telephony.gsm.stk.TextAttribute;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.TextWatcher;
+import android.graphics.Typeface;
+import android.text.method.PasswordTransformationMethod;
+
+/**
+ * Display a request for a text input a long with a text edit form.
+ */
+public class StkInputActivity extends Activity implements View.OnClickListener,
+ TextWatcher {
+
+ // Members
+ private int mState;
+ private int mMinTextLength = NO_MIN_LIMIT;
+ private EditText mTextIn = null;
+ private TextView mPromptView = null;
+ private View mYesNoLayout = null;
+ private View mNormalLayout = null;
+ private WatchDog mTimeoutWatchDog = null;
+ private boolean mHelpAvailable = false;
+
+ // Constants
+ private static final String TAG = "STK INPUT ACTIVITY";
+
+ private static final int IN_STATE_TEXT = 1;
+ private static final int IN_STATE_KEY = 2;
+
+ private static final int NO_MIN_LIMIT = 0;
+ private static final int INKEY_MAX_LIMIT = 1;
+
+ private static final String INKEY_MAX_LIMIT_STR = "1";
+
+ // Font size factor values.
+ static final float NORMAL_FONT_FACTOR = 1;
+ static final float LARGE_FONT_FACTOR = 2;
+ static final float SMALL_FONT_FACTOR = (1 / 2);
+
+ private class Terminate implements Runnable {
+ public void run() {
+ setResult(StkApp.RESULT_TIMEDOUT);
+ finish();
+ }
+ }
+
+ // Click listener to handle buttons press..
+ public void onClick(View v) {
+ Intent data = new Intent();
+
+ switch (v.getId()) {
+ case R.id.button_ok:
+ // Check that text entered is valid .
+ if (!verfiyTypedText()) {
+ return;
+ }
+ switch (mState) {
+ case IN_STATE_TEXT:
+ // return input text to the calling activity
+ String input = mTextIn.getText().toString();
+ data.putExtra(Util.INPUT_TYPE_TEXT, input);
+ break;
+ case IN_STATE_KEY:
+ // return input key to the calling activity
+ Character key = new Character(mTextIn.getText().toString()
+ .charAt(0));
+ data.putExtra(Util.INPUT_TYPE_KEY, key.charValue());
+ break;
+ }
+ break;
+ // Yes/No layout buttons.
+ case R.id.button_yes:
+ onYesNoButtonClick(true);
+ break;
+ case R.id.button_no:
+ onYesNoButtonClick(true);
+ break;
+ }
+
+ setResult(RESULT_OK, data);
+ finish();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Set the layout for this activity.
+ setContentView(R.layout.stk_input);
+
+ // Initialize members
+ mTextIn = (EditText) this.findViewById(R.id.in_text);
+ mPromptView = (TextView) this.findViewById(R.id.prompt);
+
+ // Set buttons listeners.
+ Button okButton = (Button) findViewById(R.id.button_ok);
+ Button yesButton = (Button) findViewById(R.id.button_yes);
+ Button noButton = (Button) findViewById(R.id.button_no);
+
+ okButton.setOnClickListener(this);
+ yesButton.setOnClickListener(this);
+ noButton.setOnClickListener(this);
+
+ mYesNoLayout = findViewById(R.id.yes_no_layout);
+ mNormalLayout = findViewById(R.id.normal_layout);
+
+ // Get the calling intent type: text/key, and setup the
+ // display parameters.
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ // set input state
+ String str = extras.getString(Util.INPUT_TYPE);
+ mState = (str.equals(Util.INPUT_TYPE_TEXT)) ? IN_STATE_TEXT
+ : IN_STATE_KEY;
+ configInputDisplay(extras);
+ }
+ // Create a watch dog to terminate the activity if no input is received
+ // after one minute.
+ mTimeoutWatchDog = new WatchDog(null, new Handler(), new Terminate(),
+ StkApp.UI_TIMEOUT);
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+
+ mTextIn.addTextChangedListener(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mTimeoutWatchDog.cancel();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ AppInterface stkService = Service.getInstance();
+
+ // Reset timeout.
+ mTimeoutWatchDog.reset();
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ setResult(StkApp.RESULT_BACKWARD);
+ finish();
+ break;
+ case KeyEvent.KEYCODE_HOME:
+ setResult(StkApp.RESULT_END_SESSION);
+ finish();
+ break;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ // Reset timeout.
+ mTimeoutWatchDog.reset();
+ return super.onTrackballEvent(event);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // Reset timeout.
+ mTimeoutWatchDog.reset();
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(android.view.Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ menu.add(0, StkApp.MENU_ID_MAIN, 1, R.string.sim_main_menu);
+ menu.add(0, StkApp.MENU_ID_HELP, 2, R.string.help);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(android.view.Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(StkApp.MENU_ID_MAIN).setVisible(true);
+ menu.findItem(StkApp.MENU_ID_HELP).setVisible(mHelpAvailable);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ AppInterface stkService = Service.getInstance();
+
+ switch (item.getItemId()) {
+ case StkApp.MENU_ID_MAIN:
+ setResult(StkApp.RESULT_END_SESSION);
+ finish();
+ return true;
+ case StkApp.MENU_ID_HELP:
+ setResult(StkApp.RESULT_HELP);
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // Reset timeout.
+ mTimeoutWatchDog.reset();
+ }
+
+ public void afterTextChanged(Editable s) {
+ }
+
+ private void onYesNoButtonClick(boolean yesNo) {
+ Intent data = new Intent();
+ data.putExtra(Util.INPUT_TYPE_KEY, yesNo);
+
+ // End the activity.
+ setResult(StkApp.RESULT_OK, data);
+ finish();
+ }
+
+ private boolean verfiyTypedText() {
+ // If not enough input was typed in stay on the edit screen.
+ if (mTextIn.getText().length() < mMinTextLength) return false;
+
+ return true;
+ }
+
+ private void configInputDisplay(Bundle extras) {
+ TextView numOfCharsView = (TextView) findViewById(R.id.num_of_chars);
+ TextView inTypeView = (TextView) findViewById(R.id.input_type);
+ Bundle bundle = extras.getBundle(Util.INPUT_TEXT_ATTRS);
+ Bundle glblAttrs = extras.getBundle(Util.INPUT_GLBL_ATTRS);
+ TextAttribute textAttrs = null;
+ int inTypeId = R.string.alphabet;
+
+ // set the prompt.
+ String prompt = extras.getString(Util.INPUT_PROMPT);
+ if (prompt != null) {
+ mPromptView.setText(prompt);
+ }
+
+ // Unpack text attributes from the bundle.
+ if (bundle != null) textAttrs = Util.unPackTextAttr(bundle);
+
+ // Set input type (alphabet/digit) info close to the InText form.
+ if (glblAttrs.getBoolean(Util.INPUT_ATTR_DIGITS)) {
+ mTextIn.setKeyListener(StkDigitsKeyListener.getInstance());
+ inTypeId = R.string.digits;
+ }
+ inTypeView.setText(inTypeId);
+
+ if (glblAttrs.getBoolean(Util.INPUT_ATTR_HELP)) {
+ mHelpAvailable = true;
+ }
+
+ // Handle specific global and text attributes.
+ switch (mState) {
+ case IN_STATE_TEXT:
+ // Handle text attributes setup for get input.
+ if (textAttrs != null) {
+ // Set font size.
+ float size = mPromptView.getTextSize() *
+ getFontSizeFactor(textAttrs.size);
+
+ mPromptView.setTextSize(size);
+
+ // Set prompt to bold.
+ if (textAttrs.bold) {
+ mPromptView.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+ // Set prompt to italic.
+ if (textAttrs.italic) {
+ mPromptView.setTypeface(Typeface.create(Typeface.DEFAULT,
+ Typeface.ITALIC));
+ }
+ // Set text color.
+ mPromptView.setTextColor(textAttrs.color.ordinal());
+ }
+ // Handle global attributes setup.
+ mMinTextLength = glblAttrs.getInt(Util.INPUT_ATTR_MINLEN);
+
+ // Set the maximum number of characters according to the maximum
+ // input size.
+ int maxTextLength = glblAttrs.getInt(Util.INPUT_ATTR_MAXLEN);
+ mTextIn.setFilters(new InputFilter[] {new InputFilter.LengthFilter(
+ maxTextLength)});
+
+ // Set number of chars info.
+ String lengthLimit = String.valueOf(mMinTextLength);
+ if (maxTextLength != mMinTextLength) {
+ lengthLimit = mMinTextLength + " - " + maxTextLength;
+ }
+ numOfCharsView.setText(lengthLimit);
+
+ if (!glblAttrs.getBoolean(Util.INPUT_ATTR_ECHO)) {
+ mTextIn.setTransformationMethod(PasswordTransformationMethod
+ .getInstance());
+ }
+ // Set default text if present.
+ String defaultText = extras.getString(Util.INPUT_DEFAULT);
+ if (defaultText != null) {
+ mTextIn.setText(defaultText);
+ }
+
+ break;
+ case IN_STATE_KEY:
+ // Set display mode - normal / yes-no layout
+ if (glblAttrs.getBoolean(Util.INPUT_ATTR_YES_NO)) {
+ mYesNoLayout.setVisibility(View.VISIBLE);
+ mNormalLayout.setVisibility(View.GONE);
+ break;
+ }
+ // In case of a input key, limit the text in to a single char.
+ mTextIn.setFilters(new InputFilter[] {new InputFilter.LengthFilter(
+ INKEY_MAX_LIMIT)});
+ mMinTextLength = INKEY_MAX_LIMIT;
+ numOfCharsView.setText(INKEY_MAX_LIMIT_STR);
+ break;
+ }
+ }
+
+ private float getFontSizeFactor(FontSize size) {
+ final float[] fontSizes =
+ {NORMAL_FONT_FACTOR, LARGE_FONT_FACTOR, SMALL_FONT_FACTOR};
+
+ return fontSizes[size.ordinal()];
+ }
+}
diff --git a/src/com/android/stk/StkMenuAdapter.java b/src/com/android/stk/StkMenuAdapter.java
new file mode 100644
index 0000000..cd0e7f9
--- /dev/null
+++ b/src/com/android/stk/StkMenuAdapter.java
@@ -0,0 +1,68 @@
+/*
+ * 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.stk;
+
+import com.android.internal.telephony.gsm.stk.Item;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Icon list view adapter to show the list of STK items.
+ */
+public class StkMenuAdapter extends ArrayAdapter<Item> {
+ private final LayoutInflater mInflater;
+ private boolean mIcosSelfExplanatory = false;
+
+ public StkMenuAdapter(Context context, List<Item> items,
+ boolean icosSelfExplanatory) {
+ super(context, 0, items);
+ mInflater = LayoutInflater.from(context);
+ mIcosSelfExplanatory = icosSelfExplanatory;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final Item item = getItem(position);
+
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.stk_menu_item, parent,
+ false);
+ }
+
+ if (!mIcosSelfExplanatory || (mIcosSelfExplanatory && item.icon == null)) {
+ ((TextView) convertView.findViewById(R.id.text)).setText(item.text);
+ }
+ ImageView imageView = ((ImageView) convertView.findViewById(R.id.icon));
+ if (item.icon == null) {
+ imageView.setVisibility(View.GONE);
+ } else {
+ imageView.setImageBitmap(item.icon);
+ }
+
+ return convertView;
+ }
+}
diff --git a/src/com/android/stk/StkSettings.java b/src/com/android/stk/StkSettings.java
new file mode 100644
index 0000000..d1f07c4
--- /dev/null
+++ b/src/com/android/stk/StkSettings.java
@@ -0,0 +1,117 @@
+/*
+ * 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.stk;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.preference.CheckBoxPreference;
+import com.android.internal.telephony.gsm.stk.Service;
+
+/**
+ * This class controls the UI for STK global settings.
+ */
+public class StkSettings extends PreferenceActivity {
+
+ // members
+ private Preference mServiceName = null;
+ private CheckBoxPreference mButtonOnOff = null;
+ private Service mStkService = null;
+ private static boolean mFirstCreate = true;
+ private static int mAppState;
+
+ //String keys for preference lookup
+ private static final String SERVICE_NAME = "service_name";
+ private static final String TOGGLE_BUTTON = "stk_app_enable_disable";
+
+ private static final int APP_ON = 1;
+ private static final int APP_OFF = 2;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ // set the preference layout.
+ addPreferencesFromResource(R.xml.stk_settings);
+
+ // Initialize members.
+ mStkService = Service.getInstance();
+ if (mStkService == null) {
+ finish();
+ return;
+ }
+ PreferenceScreen prefSet = getPreferenceScreen();
+ mServiceName = prefSet.findPreference(SERVICE_NAME);
+ mButtonOnOff = (CheckBoxPreference) prefSet.findPreference(TOGGLE_BUTTON);
+
+ // Synchronize activity UI state with STK service.
+ refreshUiState();
+ mFirstCreate = false;
+ }
+
+ // Click listener for all toggle events
+ public boolean onPreferenceTreeClick(PreferenceScreen preferences, Preference preference) {
+ if (preference instanceof CheckBoxPreference) {
+ CheckBoxPreference tp = (CheckBoxPreference) preference;
+
+ if (tp == mButtonOnOff) {
+ if (tp.isChecked()) {
+ mAppState = APP_ON;
+ sendBroadcast(new Intent("com.android.stk.action.INSTALL"));
+ //StkInstaller.installApp(this);
+ } else {
+ mAppState = APP_OFF;
+ sendBroadcast(new Intent("com.android.stk.action.INSTALL"));
+ //StkInstaller.unInstallApp(this);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // This function update the UI state according the the Service or package
+ // manager state. ON the first time it is called the state should fit the
+ // service. Sequential calls update the ui according to the state of the
+ /// package manager.
+ private void refreshUiState() {
+ if (!mFirstCreate) {
+ PackageManager pm = this.getPackageManager();
+ if (pm == null) return;
+
+ // Set application state.
+ setAppState(mAppState == APP_ON);
+ } else {
+ boolean enabled = mStkService.isStkSupported();
+ mAppState = enabled ? APP_ON : APP_OFF;
+ setAppState(enabled);
+ }
+ }
+
+ private void setAppState(boolean enabled) {
+ if (enabled) {
+ String name = mStkService.getServiceName();
+ mServiceName.setSummary(mStkService.getServiceName());
+ mButtonOnOff.setChecked(true);
+ } else {
+ mServiceName.setSummary(R.string.stk_no_service);
+ mButtonOnOff.setChecked(false);
+ }
+ }
+}
diff --git a/src/com/android/stk/TonePlayer.java b/src/com/android/stk/TonePlayer.java
new file mode 100644
index 0000000..d8d9195
--- /dev/null
+++ b/src/com/android/stk/TonePlayer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.stk;
+
+import java.util.HashMap;
+
+import android.media.AudioManager;
+import android.media.ToneGenerator;
+import com.android.internal.telephony.gsm.stk.Tone;
+
+/**
+ * Class that implements a tones player for the SIM toolkit application.
+ *
+ */
+public class TonePlayer {
+ private static final String TAG = "TonePlayer";
+ private static final HashMap<Tone, Integer> mToneMap = new HashMap<Tone, Integer>();
+
+ static {
+ // Map STK tone ids to the system tone ids.
+ mToneMap.put(Tone.DIAL, ToneGenerator.TONE_SUP_DIAL);
+ mToneMap.put(Tone.BUSY, ToneGenerator.TONE_SUP_BUSY);
+ mToneMap.put(Tone.CONGESTION, ToneGenerator.TONE_SUP_CONGESTION);
+ mToneMap.put(Tone.RADIO_PATH_ACK, ToneGenerator.TONE_SUP_RADIO_ACK);
+ mToneMap.put(Tone.RADIO_PATH_NOT_AVAILABLE, ToneGenerator.TONE_SUP_RADIO_NOTAVAIL);
+ mToneMap.put(Tone.ERROR_SPECIAL_INFO, ToneGenerator.TONE_SUP_ERROR);
+ mToneMap.put(Tone.CALL_WAITING, ToneGenerator.TONE_SUP_CALL_WAITING);
+ mToneMap.put(Tone.RINGING, ToneGenerator.TONE_SUP_RINGTONE);
+ mToneMap.put(Tone.GENERAL_BEEP, ToneGenerator.TONE_PROP_BEEP);
+ mToneMap.put(Tone.POSITIVE_ACK, ToneGenerator.TONE_PROP_ACK);
+ mToneMap.put(Tone.NEGATIVE_ACK, ToneGenerator.TONE_PROP_NACK);
+ }
+
+ private ToneGenerator mToneGenerator = null;
+
+ TonePlayer() {
+ mToneGenerator = new ToneGenerator(AudioManager.STREAM_RING, 80);
+ }
+
+ public void play(Tone tone) {
+ int toneId = getToneId(tone);
+ if (toneId > 0 && mToneGenerator != null) {
+ mToneGenerator.startTone(toneId);
+ }
+ }
+
+ public void stop() {
+ if (mToneGenerator != null) {
+ mToneGenerator.stopTone();
+ }
+ }
+
+ public void release() {
+ mToneGenerator.release();
+ }
+
+ private int getToneId(Tone tone) {
+ int toneId = ToneGenerator.TONE_PROP_BEEP;
+
+ if (tone != null && mToneMap.containsKey(tone)) {
+ toneId = mToneMap.get(tone);
+ }
+ return toneId;
+ }
+}
diff --git a/src/com/android/stk/Util.java b/src/com/android/stk/Util.java
new file mode 100644
index 0000000..edde82f
--- /dev/null
+++ b/src/com/android/stk/Util.java
@@ -0,0 +1,104 @@
+/*
+ * 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.stk;
+
+import android.os.Bundle;
+import com.android.internal.telephony.gsm.stk.FontSize;
+import com.android.internal.telephony.gsm.stk.TextAlignment;
+import com.android.internal.telephony.gsm.stk.TextAttribute;
+import com.android.internal.telephony.gsm.stk.TextColor;
+
+public class Util {
+ // Constants
+ public static final String INPUT_TYPE = "Stk.InputType";
+ public static final String INPUT_PROMPT = "Stk.InputPrompt";
+ public static final String INPUT_DEFAULT = "Stk.InputDefault";
+ public static final String INPUT_CALL_PERMISSION = "Stk.InputCallPermission";
+ public static final String INPUT_TYPE_TEXT = "Stk.InputType.Text";
+ public static final String INPUT_TYPE_KEY = "Stk.InputType.Key";
+
+ public static final String INPUT_TEXT_ATTRS = "Stk.TextAtrs";
+ public static final String INPUT_ATTR_START = "Stk.Atr.Start";
+ public static final String INPUT_ATTR_LENGHT = "Stk.Atr.Length";
+ public static final String INPUT_ATTR_ALIGN = "Stk.Atr.Align";
+ public static final String INPUT_ATTR_SIZE = "Stk.Atr.Size";
+ public static final String INPUT_ATTR_BOLD = "Stk.Atr.Bold'";
+ public static final String INPUT_ATTR_ITALIC = "Stk.Atr.Italic";
+ public static final String INPUT_ATTR_UNDERLINED = "Stk.Atr.underlined'";
+ public static final String INPUT_ATTR_STRIKE_THROUGH = "Stk.Atr.Strike.Through";
+ public static final String INPUT_ATTR_COLOR = "Stk.Atr.Color";
+
+ public static final String INPUT_GLBL_ATTRS = "Stk.GlblAtrs";
+ public static final String INPUT_ATTR_MINLEN = "Stk.Atr.MinLen";
+ public static final String INPUT_ATTR_MAXLEN = "Stk.Atr.MaxLen";
+ public static final String INPUT_ATTR_NOMAAXLIM = "Stk.Atr.NoMaxLimit";
+ public static final String INPUT_ATTR_DIGITS = "Stk.Atr.Digits";
+ public static final String INPUT_ATTR_UCS2 = "Stk.Atr.UCS2";
+ public static final String INPUT_ATTR_ECHO = "Stk.Atr.Echo";
+ public static final String INPUT_ATTR_HELP = "Stk.Atr.Help";
+ public static final String INPUT_ATTR_IMD_RESPONSE = "Stk.Atr.ImdResponse";
+ public static final String INPUT_ATTR_YES_NO = "Stk.Atr.YesNo";
+
+ // Packing text attributes into a bundle to pass with an Intent.
+ public static Bundle packTextAttr(TextAttribute textAttrs) {
+ if (textAttrs == null) return null;
+
+ Bundle bundle = new Bundle();
+
+ bundle.putInt(INPUT_ATTR_START, textAttrs.start);
+ bundle.putInt(INPUT_ATTR_LENGHT, textAttrs.length);
+ if (textAttrs.align != null) {
+ bundle.putInt(INPUT_ATTR_ALIGN, textAttrs.align.ordinal());
+ }
+ if (textAttrs.size != null) {
+ bundle.putInt(INPUT_ATTR_SIZE, textAttrs.size.ordinal());
+ }
+ bundle.putBoolean(INPUT_ATTR_BOLD, textAttrs.bold);
+ bundle.putBoolean(INPUT_ATTR_ITALIC, textAttrs.italic);
+ bundle.putBoolean(INPUT_ATTR_UNDERLINED, textAttrs.underlined);
+ bundle.putBoolean(INPUT_ATTR_STRIKE_THROUGH, textAttrs.strikeThrough);
+ if (textAttrs.color != null) {
+ bundle.putInt(INPUT_ATTR_COLOR, textAttrs.color.ordinal());
+ }
+ return bundle;
+ }
+
+ // Unpacking text attributes from a bundle passed with an Intent.
+ public static TextAttribute unPackTextAttr(Bundle bundle) {
+ if (bundle == null) return null;
+
+ int start = bundle.getInt(INPUT_ATTR_START);
+ int length = bundle.getInt(INPUT_ATTR_LENGHT);
+ TextAlignment align = TextAlignment.fromInt(bundle.getInt(INPUT_ATTR_ALIGN));
+ FontSize size = FontSize.fromInt(bundle.getInt(INPUT_ATTR_SIZE));
+ boolean bold = bundle.getBoolean(INPUT_ATTR_BOLD);
+ boolean italic = bundle.getBoolean(INPUT_ATTR_ITALIC);
+ boolean underlined = bundle.getBoolean(INPUT_ATTR_UNDERLINED);
+ boolean strikeThrough = bundle.getBoolean(INPUT_ATTR_STRIKE_THROUGH);
+ TextColor color = TextColor.fromInt(bundle.getInt(INPUT_ATTR_COLOR));
+
+ TextAttribute textAttrs = new TextAttribute(start, length, align, size,
+ bold, italic, underlined, strikeThrough, color);
+
+ return textAttrs;
+ }
+}
+
+
+
+
+
diff --git a/src/com/android/stk/WatchDog.java b/src/com/android/stk/WatchDog.java
new file mode 100644
index 0000000..423e694
--- /dev/null
+++ b/src/com/android/stk/WatchDog.java
@@ -0,0 +1,143 @@
+/*
+ * 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.stk;
+
+import android.os.Handler;
+import android.util.Log;
+
+/**
+ * This interface defines Event to be used by WatchDog.
+ * Watchdog expires when event is set.
+ */
+interface Event {
+
+ public void set();
+
+ public void unSet();
+
+ public boolean isSet();
+}
+
+/**
+ * This class implements Watch Dog using a daemon thread.
+ * WatchDog waits for an event to expire and execute Runnable in the caller
+ * context.
+ */
+class WatchDog extends Thread {
+ // Constants
+ private static final int POLLING_INTERVAL = 150;
+ public static final int TIMEOUT_WAIT_FOREVER = Integer.MAX_VALUE;
+
+ private static final String TAG = "WatchDog";
+ private static final boolean DBG = true;
+
+ // Members
+ private Event mEvent = null;
+ private Handler mCaller = null;
+ private Runnable mRunnable = null;
+ private int mTimeout = TIMEOUT_WAIT_FOREVER;
+ private int mInterval = POLLING_INTERVAL;
+ private int mElapsedTime = 0;
+ private Object mElapsedTimeLock = new Object();
+ private boolean mCanceled = false;
+ private boolean mPaused = false;
+
+ class VoidEvent implements Event {
+ public void set() {}
+
+ public void unSet() {}
+
+ public boolean isSet() {
+ return false;
+ }
+ }
+
+ WatchDog(Event event, Handler caller, Runnable onEventResponse, int timeout) {
+ mEvent = event == null ? new VoidEvent() : event;
+ mCaller = caller;
+ mRunnable = onEventResponse;
+ mTimeout = timeout;
+
+ this.setDaemon(true);
+ this.start();
+ }
+
+ public void cancel() {
+ mTimeout = 0;
+ mCanceled = true;
+ }
+
+ public void reset() {
+ synchronized (mElapsedTimeLock) {
+ mElapsedTime = 0;
+ }
+ }
+
+ public void pause() {
+ mPaused = true;
+ }
+
+ public void unpause() {
+ mPaused = false;
+ }
+
+ @Override
+ public void run() {
+ watchEvent();
+ // When event expires post response to caller.
+ if (mCaller != null && mRunnable != null) {
+ if (!mCanceled) {
+ mCaller.post(mRunnable);
+ }
+ }
+ }
+
+ // Synchronized method, block until event expires.
+ private void watchEvent() {
+ while (!isEventSet() && !isTimedOut()) {
+ try {
+ Thread.sleep(mInterval);
+ incrementTime();
+ } catch (InterruptedException ie) {
+ if (DBG) Log.d(TAG, ie.toString());
+ }
+ }
+ }
+
+ private void incrementTime() {
+ if (mPaused) {
+ return;
+ }
+ synchronized (mElapsedTimeLock) {
+ mElapsedTime += (mTimeout == TIMEOUT_WAIT_FOREVER ? 0 : mInterval);
+ }
+ }
+
+ private boolean isTimedOut() {
+ if (mPaused) {
+ return false;
+ }
+ return (mElapsedTime >= mTimeout);
+ }
+
+ private boolean isEventSet() {
+ if (mPaused) {
+ return false;
+ }
+ return mEvent.isSet();
+ }
+}