diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | e405ce157d5bfb44efa33a314ae08d543bc9d39e (patch) | |
tree | 9941f4acbde908891eddd6f39d538ebe377483e1 | |
download | Stk-release-1.0.tar.gz |
Initial Contributionandroid-1.0release-1.0cdma-import
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 @@ -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 Binary files differnew file mode 100755 index 0000000..0dfec74 --- /dev/null +++ b/res/drawable/ic_launcher_sim_toolkit.png 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(); + } +} |