diff options
author | Xavier Ducrohet <xav@android.com> | 2011-02-28 09:51:38 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2011-02-28 09:51:38 -0800 |
commit | ce57a7f35344e76689d30f45964d1e37b78280cb (patch) | |
tree | 880399208681c04fb55a240b9317b65fc135c91b | |
parent | e630e5f49ba15005172dceeda7299569b2d2351f (diff) | |
parent | 6504490cde3ec5d48321d539e654d1f2072b33f9 (diff) | |
download | frameworks_base-ce57a7f35344e76689d30f45964d1e37b78280cb.zip frameworks_base-ce57a7f35344e76689d30f45964d1e37b78280cb.tar.gz frameworks_base-ce57a7f35344e76689d30f45964d1e37b78280cb.tar.bz2 |
am 6504490c: am dff6b8e7: Merge "Add --non-constant-id to aapt."
* commit '6504490cde3ec5d48321d539e654d1f2072b33f9':
GpsLocationProvider: Clean up HAL initialization/cleanup sequence
Fixed GSM encoded network initiated position request
Ensuring thread-safe usage of DateFormat.
Fixing infinite loop for zero duration.
Fix for an infinite loop while scrolling lists.
WAPPushManager, WAP Push over SMS message handler
Add --non-constant-id to aapt.
33 files changed, 4476 insertions, 208 deletions
@@ -184,6 +184,7 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \ telephony/java/com/android/internal/telephony/IIccPhoneBook.aidl \ telephony/java/com/android/internal/telephony/ISms.aidl \ + telephony/java/com/android/internal/telephony/IWapPushManager.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl \ telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl \ vpn/java/android/net/vpn/IVpnService.aidl \ diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index a95dad7..353b628 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -642,14 +642,18 @@ public class DateUtils private static void initFormatStrings() { synchronized (sLock) { - Resources r = Resources.getSystem(); - Configuration cfg = r.getConfiguration(); - if (sLastConfig == null || !sLastConfig.equals(cfg)) { - sLastConfig = cfg; - sStatusTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT); - sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss); - sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss); - } + initFormatStringsLocked(); + } + } + + private static void initFormatStringsLocked() { + Resources r = Resources.getSystem(); + Configuration cfg = r.getConfiguration(); + if (sLastConfig == null || !sLastConfig.equals(cfg)) { + sLastConfig = cfg; + sStatusTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT); + sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss); + sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss); } } @@ -659,8 +663,10 @@ public class DateUtils * @hide */ public static final CharSequence timeString(long millis) { - initFormatStrings(); - return sStatusTimeFormat.format(millis); + synchronized (sLock) { + initFormatStringsLocked(); + return sStatusTimeFormat.format(millis); + } } /** diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 85ce5e1..5c281cf 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -190,7 +190,7 @@ public class TimeUtils { int pos = 0; fieldLen -= 1; while (pos < fieldLen) { - formatStr[pos] = ' '; + formatStr[pos++] = ' '; } formatStr[pos] = '0'; return pos+1; diff --git a/core/java/android/widget/EdgeGlow.java b/core/java/android/widget/EdgeGlow.java index 416be86..a11de6f 100644 --- a/core/java/android/widget/EdgeGlow.java +++ b/core/java/android/widget/EdgeGlow.java @@ -317,6 +317,7 @@ public class EdgeGlow { mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp * factor; + mState = STATE_RECEDE; break; case STATE_RECEDE: mState = STATE_IDLE; diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index d539833..ffc3346 100755 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -29,6 +29,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.R; +import com.android.internal.telephony.GsmAlphabet; /** * A GPS Network-initiated Handler class used by LocationManager. @@ -288,58 +289,32 @@ public class GpsNetInitiatedHandler { */ static String decodeGSMPackedString(byte[] input) { - final char CHAR_CR = 0x0D; - int nStridx = 0; - int nPckidx = 0; - int num_bytes = input.length; - int cPrev = 0; - int cCurr = 0; - byte nShift; - byte nextChar; - byte[] stringBuf = new byte[input.length * 2]; - String result = ""; - - while(nPckidx < num_bytes) - { - nShift = (byte) (nStridx & 0x07); - cCurr = input[nPckidx++]; - if (cCurr < 0) cCurr += 256; - - /* A 7-bit character can be split at the most between two bytes of packed - ** data. - */ - nextChar = (byte) (( (cCurr << nShift) | (cPrev >> (8-nShift)) ) & 0x7F); - stringBuf[nStridx++] = nextChar; - - /* Special case where the whole of the next 7-bit character fits inside - ** the current byte of packed data. - */ - if(nShift == 6) - { - /* If the next 7-bit character is a CR (0x0D) and it is the last - ** character, then it indicates a padding character. Drop it. - */ - if (nPckidx == num_bytes || (cCurr >> 1) == CHAR_CR) - { - break; + final char PADDING_CHAR = 0x00; + int lengthBytes = input.length; + int lengthSeptets = (lengthBytes * 8) / 7; + String decoded; + + /* Special case where the last 7 bits in the last byte could hold a valid + * 7-bit character or a padding character. Drop the last 7-bit character + * if it is a padding character. + */ + if (lengthBytes % 7 == 0) { + if (lengthBytes > 0) { + if ((input[lengthBytes - 1] >> 1) == PADDING_CHAR) { + lengthSeptets = lengthSeptets - 1; } - - nextChar = (byte) (cCurr >> 1); - stringBuf[nStridx++] = nextChar; } - - cPrev = cCurr; } - try { - result = new String(stringBuf, 0, nStridx, "US-ASCII"); - } - catch (UnsupportedEncodingException e) - { - Log.e(TAG, e.getMessage()); + decoded = GsmAlphabet.gsm7BitPackedToString(input, 0, lengthSeptets); + + // Return "" if decoding of GSM packed string fails + if (null == decoded) { + Log.e(TAG, "Decoding of GSM packed string failed"); + decoded = ""; } - return result; + return decoded; } static String decodeUTF8String(byte[] input) diff --git a/packages/WAPPushManager/Android.mk b/packages/WAPPushManager/Android.mk new file mode 100644 index 0000000..c1d8f4b --- /dev/null +++ b/packages/WAPPushManager/Android.mk @@ -0,0 +1,20 @@ +# Copyright 2007-2008 The Android Open Source Project + + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := WAPPushManager + +LOCAL_STATIC_JAVA_LIBRARIES += android-common + +LOCAL_PROGUARD_FLAGS := -include $(LOCAL_PATH)/proguard.flags + +include $(BUILD_PACKAGE) + +# This finds and builds the test apk as well, so a single make does both. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml new file mode 100644 index 0000000..89e9d6a --- /dev/null +++ b/packages/WAPPushManager/AndroidManifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright (C) 2007-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. + */ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.smspush"> + + <permission android:name="com.android.smspush.WAPPUSH_MANAGER_BIND" + android:protectionLevel="signatureOrSystem" /> + + <original-package android:name="com.android.smspush" /> + <application> + <service android:name=".WapPushManager" + android:permission="com.android.smspush.WAPPUSH_MANAGER_BIND" + android:exported="true"> + <intent-filter> + <action android:name="com.android.internal.telephony.IWapPushManager"></action> + </intent-filter> + </service> + </application> + + +</manifest> diff --git a/packages/WAPPushManager/CleanSpec.mk b/packages/WAPPushManager/CleanSpec.mk new file mode 100644 index 0000000..b84e1b6 --- /dev/null +++ b/packages/WAPPushManager/CleanSpec.mk @@ -0,0 +1,49 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/packages/WAPPushManager/MODULE_LICENSE_APACHE2 b/packages/WAPPushManager/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/packages/WAPPushManager/MODULE_LICENSE_APACHE2 diff --git a/packages/WAPPushManager/NOTICE b/packages/WAPPushManager/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/packages/WAPPushManager/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/packages/WAPPushManager/proguard.flags b/packages/WAPPushManager/proguard.flags new file mode 100644 index 0000000..d09887b --- /dev/null +++ b/packages/WAPPushManager/proguard.flags @@ -0,0 +1,18 @@ + +#apply method is dynamically referenced by the reflection class. +-keep class android.app.ContextImpl$SharedPreferencesImpl$EditorImpl { + void apply(); +} +-keep class android.content.SharedPreferences$Editor { + void apply(); +} + +#WapPushManager is referenced only by AndroidManifest.xml +-keep class com.android.smspush.WapPushManager { +#CTS module method + public boolean isDataExist(java.lang.String, java.lang.String, + java.lang.String, java.lang.String); + public boolean verifyData(java.lang.String, java.lang.String, + java.lang.String, java.lang.String, int, boolean, boolean); +} + diff --git a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java new file mode 100644 index 0000000..96e0377 --- /dev/null +++ b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush; + +import android.app.Service; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteDatabase; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.telephony.IWapPushManager; +import com.android.internal.telephony.WapPushManagerParams; + +/** + * The WapPushManager service is implemented to process incoming + * WAP Push messages and to maintain the Receiver Application/Application + * ID mapping. The WapPushManager runs as a system service, and only the + * WapPushManager can update the WAP Push message and Receiver Application + * mapping (Application ID Table). When the device receives an SMS WAP Push + * message, the WapPushManager looks up the Receiver Application name in + * Application ID Table. If an application is found, the application is + * launched using its full component name instead of broadcasting an implicit + * Intent. If a Receiver Application is not found in the Application ID + * Table or the WapPushManager returns a process-further value, the + * telephony stack will process the message using existing message processing + * flow, and broadcast an implicit Intent. + */ +public class WapPushManager extends Service { + + private static final String LOG_TAG = "WAP PUSH"; + private static final String DATABASE_NAME = "wappush.db"; + private static final String APPID_TABLE_NAME = "appid_tbl"; + + /** + * Version number must be incremented when table structure is changed. + */ + private static final int WAP_PUSH_MANAGER_VERSION = 1; + private static final boolean DEBUG_SQL = false; + private static final boolean LOCAL_LOGV = false; + + /** + * Inner class that deals with application ID table + */ + private class WapPushManDBHelper extends SQLiteOpenHelper { + WapPushManDBHelper(Context context) { + super(context, DATABASE_NAME, null, WAP_PUSH_MANAGER_VERSION); + if (LOCAL_LOGV) Log.v(LOG_TAG, "helper instance created."); + } + + @Override + public void onCreate(SQLiteDatabase db) { + if (LOCAL_LOGV) Log.v(LOG_TAG, "db onCreate."); + String sql = "CREATE TABLE " + APPID_TABLE_NAME + " (" + + "id INTEGER PRIMARY KEY, " + + "x_wap_application TEXT, " + + "content_type TEXT, " + + "package_name TEXT, " + + "class_name TEXT, " + + "app_type INTEGER, " + + "need_signature INTEGER, " + + "further_processing INTEGER, " + + "install_order INTEGER " + + ")"; + + if (DEBUG_SQL) Log.v(LOG_TAG, "sql: " + sql); + db.execSQL(sql); + } + + @Override + public void onUpgrade(SQLiteDatabase db, + int oldVersion, int newVersion) { + // TODO: when table structure is changed, need to dump and restore data. + /* + db.execSQL( + "drop table if exists "+APPID_TABLE_NAME); + onCreate(db); + */ + Log.w(LOG_TAG, "onUpgrade is not implemented yet. do nothing."); + } + + protected class queryData { + public String packageName; + public String className; + int appType; + int needSignature; + int furtherProcessing; + int installOrder; + } + + /** + * Query the latest receiver application info with supplied application ID and + * content type. + * @param app_id application ID to look up + * @param content_type content type to look up + */ + protected queryData queryLastApp(SQLiteDatabase db, + String app_id, String content_type) { + String sql = "select install_order, package_name, class_name, " + + " app_type, need_signature, further_processing" + + " from " + APPID_TABLE_NAME + + " where x_wap_application=\'" + app_id + "\'" + + " and content_type=\'" + content_type + "\'" + + " order by install_order desc"; + if (DEBUG_SQL) Log.v(LOG_TAG, "sql: " + sql); + Cursor cur = db.rawQuery(sql, null); + queryData ret = null; + + if (cur.moveToNext()) { + ret = new queryData(); + ret.installOrder = cur.getInt(cur.getColumnIndex("install_order")); + ret.packageName = cur.getString(cur.getColumnIndex("package_name")); + ret.className = cur.getString(cur.getColumnIndex("class_name")); + ret.appType = cur.getInt(cur.getColumnIndex("app_type")); + ret.needSignature = cur.getInt(cur.getColumnIndex("need_signature")); + ret.furtherProcessing = cur.getInt(cur.getColumnIndex("further_processing")); + } + cur.close(); + return ret; + } + + } + + /** + * The exported API implementations class + */ + private class IWapPushManagerStub extends IWapPushManager.Stub { + public Context mContext; + + public IWapPushManagerStub() { + + } + + /** + * Compare the package signature with WapPushManager package + */ + protected boolean signatureCheck(String package_name) { + PackageManager pm = mContext.getPackageManager(); + int match = pm.checkSignatures(mContext.getPackageName(), package_name); + + if (LOCAL_LOGV) Log.v(LOG_TAG, "compare signature " + mContext.getPackageName() + + " and " + package_name + ", match=" + match); + + return match == PackageManager.SIGNATURE_MATCH; + } + + /** + * Returns the status value of the message processing. + * The message will be processed as follows: + * 1.Look up Application ID Table with x-wap-application-id + content type + * 2.Check the signature of package name that is found in the + * Application ID Table by using PackageManager.checkSignature + * 3.Trigger the Application + * 4.Returns the process status value. + */ + public int processMessage(String app_id, String content_type, Intent intent) + throws RemoteException { + Log.d(LOG_TAG, "wpman processMsg " + app_id + ":" + content_type); + + WapPushManDBHelper dbh = getDatabase(mContext); + SQLiteDatabase db = dbh.getReadableDatabase(); + WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, app_id, content_type); + db.close(); + + if (lastapp == null) { + Log.w(LOG_TAG, "no receiver app found for " + app_id + ":" + content_type); + return WapPushManagerParams.APP_QUERY_FAILED; + } + if (LOCAL_LOGV) Log.v(LOG_TAG, "starting " + lastapp.packageName + + "/" + lastapp.className); + + if (lastapp.needSignature != 0) { + if (!signatureCheck(lastapp.packageName)) { + return WapPushManagerParams.SIGNATURE_NO_MATCH; + } + } + + if (lastapp.appType == WapPushManagerParams.APP_TYPE_ACTIVITY) { + //Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClassName(lastapp.packageName, lastapp.className); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w(LOG_TAG, "invalid name " + + lastapp.packageName + "/" + lastapp.className); + return WapPushManagerParams.INVALID_RECEIVER_NAME; + } + } else { + intent.setClassName(mContext, lastapp.className); + intent.setComponent(new ComponentName(lastapp.packageName, + lastapp.className)); + if (mContext.startService(intent) == null) { + Log.w(LOG_TAG, "invalid name " + + lastapp.packageName + "/" + lastapp.className); + return WapPushManagerParams.INVALID_RECEIVER_NAME; + } + } + + return WapPushManagerParams.MESSAGE_HANDLED + | (lastapp.furtherProcessing == 1 ? + WapPushManagerParams.FURTHER_PROCESSING : 0); + } + + protected boolean appTypeCheck(int app_type) { + if (app_type == WapPushManagerParams.APP_TYPE_ACTIVITY || + app_type == WapPushManagerParams.APP_TYPE_SERVICE) { + return true; + } else { + return false; + } + } + + /** + * Returns true if adding the package succeeded. + */ + public boolean addPackage(String x_app_id, String content_type, + String package_name, String class_name, + int app_type, boolean need_signature, boolean further_processing) { + WapPushManDBHelper dbh = getDatabase(mContext); + SQLiteDatabase db = dbh.getWritableDatabase(); + WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, x_app_id, content_type); + boolean ret = false; + boolean insert = false; + int sq = 0; + + if (!appTypeCheck(app_type)) { + Log.w(LOG_TAG, "invalid app_type " + app_type + ". app_type must be " + + WapPushManagerParams.APP_TYPE_ACTIVITY + " or " + + WapPushManagerParams.APP_TYPE_SERVICE); + return false; + } + + if (lastapp == null) { + insert = true; + sq = 0; + } else if (!lastapp.packageName.equals(package_name) || + !lastapp.className.equals(class_name)) { + insert = true; + sq = lastapp.installOrder + 1; + } + + if (insert) { + ContentValues values = new ContentValues(); + + values.put("x_wap_application", x_app_id); + values.put("content_type", content_type); + values.put("package_name", package_name); + values.put("class_name", class_name); + values.put("app_type", app_type); + values.put("need_signature", need_signature ? 1 : 0); + values.put("further_processing", further_processing ? 1 : 0); + values.put("install_order", sq); + db.insert(APPID_TABLE_NAME, null, values); + if (LOCAL_LOGV) Log.v(LOG_TAG, "add:" + x_app_id + ":" + content_type + + " " + package_name + "." + class_name + + ", newsq:" + sq); + ret = true; + } + + db.close(); + + return ret; + } + + /** + * Returns true if updating the package succeeded. + */ + public boolean updatePackage(String x_app_id, String content_type, + String package_name, String class_name, + int app_type, boolean need_signature, boolean further_processing) { + + if (!appTypeCheck(app_type)) { + Log.w(LOG_TAG, "invalid app_type " + app_type + ". app_type must be " + + WapPushManagerParams.APP_TYPE_ACTIVITY + " or " + + WapPushManagerParams.APP_TYPE_SERVICE); + return false; + } + + WapPushManDBHelper dbh = getDatabase(mContext); + SQLiteDatabase db = dbh.getWritableDatabase(); + WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, x_app_id, content_type); + + if (lastapp == null) { + db.close(); + return false; + } + + ContentValues values = new ContentValues(); + String where = "x_wap_application=\'" + x_app_id + "\'" + + " and content_type=\'" + content_type + "\'" + + " and install_order=" + lastapp.installOrder; + + values.put("package_name", package_name); + values.put("class_name", class_name); + values.put("app_type", app_type); + values.put("need_signature", need_signature ? 1 : 0); + values.put("further_processing", further_processing ? 1 : 0); + + int num = db.update(APPID_TABLE_NAME, values, where, null); + if (LOCAL_LOGV) Log.v(LOG_TAG, "update:" + x_app_id + ":" + content_type + " " + + package_name + "." + class_name + + ", sq:" + lastapp.installOrder); + + db.close(); + + return num > 0; + } + + /** + * Returns true if deleting the package succeeded. + */ + public boolean deletePackage(String x_app_id, String content_type, + String package_name, String class_name) { + WapPushManDBHelper dbh = getDatabase(mContext); + SQLiteDatabase db = dbh.getWritableDatabase(); + String where = "x_wap_application=\'" + x_app_id + "\'" + + " and content_type=\'" + content_type + "\'" + + " and package_name=\'" + package_name + "\'" + + " and class_name=\'" + class_name + "\'"; + int num_removed = db.delete(APPID_TABLE_NAME, where, null); + + db.close(); + if (LOCAL_LOGV) Log.v(LOG_TAG, "deleted " + num_removed + " rows:" + + x_app_id + ":" + content_type + " " + + package_name + "." + class_name); + return num_removed > 0; + } + }; + + + /** + * Linux IPC Binder + */ + private final IWapPushManagerStub mBinder = new IWapPushManagerStub(); + + /** + * Default constructor + */ + public WapPushManager() { + super(); + mBinder.mContext = this; + } + + @Override + public IBinder onBind(Intent arg0) { + return mBinder; + } + + /** + * Application ID database instance + */ + private WapPushManDBHelper mDbHelper = null; + protected WapPushManDBHelper getDatabase(Context context) { + if (mDbHelper == null) { + if (LOCAL_LOGV) Log.v(LOG_TAG, "create new db inst."); + mDbHelper = new WapPushManDBHelper(context); + } + return mDbHelper; + } + + + /** + * This method is used for testing + */ + public boolean verifyData(String x_app_id, String content_type, + String package_name, String class_name, + int app_type, boolean need_signature, boolean further_processing) { + WapPushManDBHelper dbh = getDatabase(this); + SQLiteDatabase db = dbh.getReadableDatabase(); + WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, x_app_id, content_type); + + db.close(); + + if (lastapp == null) return false; + + if (lastapp.packageName.equals(package_name) + && lastapp.className.equals(class_name) + && lastapp.appType == app_type + && lastapp.needSignature == (need_signature ? 1 : 0) + && lastapp.furtherProcessing == (further_processing ? 1 : 0)) { + return true; + } else { + return false; + } + } + + /** + * This method is used for testing + */ + public boolean isDataExist(String x_app_id, String content_type, + String package_name, String class_name) { + WapPushManDBHelper dbh = getDatabase(this); + SQLiteDatabase db = dbh.getReadableDatabase(); + boolean ret = dbh.queryLastApp(db, x_app_id, content_type) != null; + + db.close(); + return ret; + } + +} + diff --git a/packages/WAPPushManager/tests/Android.mk b/packages/WAPPushManager/tests/Android.mk new file mode 100644 index 0000000..0a95b52 --- /dev/null +++ b/packages/WAPPushManager/tests/Android.mk @@ -0,0 +1,38 @@ +# Copyright 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# We only want this apk build for tests. +LOCAL_MODULE_TAGS := tests + +LOCAL_JAVA_LIBRARIES := android.test.runner + +# Include all test java files. +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES += \ + src/com/android/smspush/unitTests/IDataVerify.aidl + + +# Notice that we don't have to include the src files of Email because, by +# running the tests using an instrumentation targeting Eamil, we +# automatically get all of its classes loaded into our environment. + +LOCAL_PACKAGE_NAME := WAPPushManagerTests + +LOCAL_INSTRUMENTATION_FOR := WAPPushManager + +include $(BUILD_PACKAGE) + diff --git a/packages/WAPPushManager/tests/AndroidManifest.xml b/packages/WAPPushManager/tests/AndroidManifest.xml new file mode 100644 index 0000000..da7634f --- /dev/null +++ b/packages/WAPPushManager/tests/AndroidManifest.xml @@ -0,0 +1,71 @@ +<?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. + +--> + +<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.smspush.unitTests"> + + + <uses-permission android:name="com.android.smspush.WAPPUSH_MANAGER_BIND" /> + <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" /> + <!--testing.../--> + <application android:icon="@drawable/icon" android:label="wappush test"> + <uses-library android:name="android.test.runner" /> + <activity android:name=".ClientTest" + android:label="wappush test"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <receiver android:name=".DrmReceiver" android:enabled="true"> + <intent-filter> + <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" /> + <data android:mimeType="application/vnd.oma.drm.rights+xml" /> + <data android:value="application/vnd.oma.drm.rights+wbxml" /> + </intent-filter> + </receiver> + + <service android:enabled="true" android:name=".ReceiverService" + android:exported="true"/> + + <activity android:name=".ReceiverActivity" + android:exported="true" android:label="test receiver" /> + + <service android:name=".DataVerify" + android:exported="true"> + <intent-filter> + <action android:name="com.android.smspush.unitTests.IDataVerify" /> + </intent-filter> + </service> + + </application> + + <!-- + This declares that this application uses the instrumentation test runner targeting + the package of com.android.smspush. To run the tests use the command: + "adb shell am instrument -w + com.android.smspush.unitTests/android.test.InstrumentationTestRunner" + --> + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.smspush" + android:label="Tests for WAPPushManager"/> + +</manifest> + diff --git a/packages/WAPPushManager/tests/res/drawable-hdpi/icon.png b/packages/WAPPushManager/tests/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 0000000..8074c4c --- /dev/null +++ b/packages/WAPPushManager/tests/res/drawable-hdpi/icon.png diff --git a/packages/WAPPushManager/tests/res/drawable-ldpi/icon.png b/packages/WAPPushManager/tests/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 0000000..1095584 --- /dev/null +++ b/packages/WAPPushManager/tests/res/drawable-ldpi/icon.png diff --git a/packages/WAPPushManager/tests/res/drawable-mdpi/icon.png b/packages/WAPPushManager/tests/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 0000000..a07c69f --- /dev/null +++ b/packages/WAPPushManager/tests/res/drawable-mdpi/icon.png diff --git a/packages/WAPPushManager/tests/res/layout/main.xml b/packages/WAPPushManager/tests/res/layout/main.xml new file mode 100644 index 0000000..c7bdbb2 --- /dev/null +++ b/packages/WAPPushManager/tests/res/layout/main.xml @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<AbsoluteLayout +android:id="@+id/widget133" +android:layout_width="fill_parent" +android:layout_height="fill_parent" +xmlns:android="http://schemas.android.com/apk/res/android" +> +<EditText +android:id="@+id/app_id" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:text="10" +android:textSize="18sp" +android:layout_x="0px" +android:layout_y="26px" +> +</EditText> +<EditText +android:id="@+id/cont" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:text="20" +android:textSize="18sp" +android:layout_x="47px" +android:layout_y="26px" +> +</EditText> +<EditText +android:id="@+id/pkg" +android:layout_width="125px" +android:layout_height="wrap_content" +android:text="pkg" +android:textSize="18sp" +android:layout_x="0px" +android:layout_y="81px" +> +</EditText> +<EditText +android:id="@+id/cls" +android:layout_width="173px" +android:layout_height="wrap_content" +android:text="cls" +android:textSize="18sp" +android:layout_x="147px" +android:layout_y="81px" +> +</EditText> +<Button +android:id="@+id/addpkg" +android:layout_width="182px" +android:layout_height="wrap_content" +android:text="add/update package" +android:layout_x="15px" +android:layout_y="225px" +> +</Button> +<TextView +android:id="@+id/widget52" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:text="input app_id, cont_type, pkg, cls" +android:textSize="18sp" +android:layout_x="0px" +android:layout_y="0px" +> +</TextView> +<Button +android:id="@+id/procmsg" +android:layout_width="109px" +android:layout_height="wrap_content" +android:text="process msg" +android:layout_x="197px" +android:layout_y="361px" +> +</Button> +<RadioGroup +android:id="@+id/widget137" +android:layout_width="83px" +android:layout_height="80px" +android:orientation="vertical" +android:layout_x="19px" +android:layout_y="137px" +> +<RadioButton +android:id="@+id/act" +android:layout_width="182px" +android:layout_height="wrap_content" +android:text="act" +android:checked="true" +> +</RadioButton> +<RadioButton +android:id="@+id/svc" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:text="svc" +> +</RadioButton> +</RadioGroup> +<Button +android:id="@+id/delpkg" +android:layout_width="174px" +android:layout_height="wrap_content" +android:text="delete pkg" +android:layout_x="14px" +android:layout_y="283px" +> +</Button> +<EditText +android:id="@+id/pdu" +android:layout_width="186px" +android:layout_height="83px" +android:text="0006080302030aaf02905c030d6a0085070373616d706c6540646f636f6d6f2e6e652e6a700005c3072009102012345601" +android:textSize="18sp" +android:layout_x="10px" +android:layout_y="341px" +> +</EditText> +<CheckBox +android:id="@+id/ftr" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:text="ftr_proc" +android:layout_x="143px" +android:layout_y="181px" +> +</CheckBox> +<CheckBox +android:id="@+id/sig" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:text="nd_sig" +android:checked="true" +android:layout_x="142px" +android:layout_y="140px" +> +</CheckBox> +</AbsoluteLayout> diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ClientTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ClientTest.java new file mode 100644 index 0000000..78fd174 --- /dev/null +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ClientTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush.unitTests; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.RadioButton; + +import com.android.internal.telephony.IWapPushManager; +import com.android.internal.telephony.WapPushManagerParams; +import com.android.internal.telephony.WapPushOverSms; +import com.android.internal.util.HexDump; +import com.android.smspush.WapPushManager; + +/** + * WapPushManager test application + */ +public class ClientTest extends Activity { + private static final String LOG_TAG = "WAP PUSH"; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + Button addpbtn = (Button) findViewById(R.id.addpkg); + Button procbtn = (Button) findViewById(R.id.procmsg); + Button delbtn = (Button) findViewById(R.id.delpkg); + + Log.v(LOG_TAG, "activity created!!"); + + addpbtn.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + EditText app_id = (EditText) findViewById(R.id.app_id); + EditText cont = (EditText) findViewById(R.id.cont); + EditText pkg = (EditText) findViewById(R.id.pkg); + EditText cls = (EditText) findViewById(R.id.cls); + RadioButton act = (RadioButton) findViewById(R.id.act); + CheckBox sig = (CheckBox) findViewById(R.id.sig); + CheckBox ftr = (CheckBox) findViewById(R.id.ftr); + + try { + if (!mWapPushMan.addPackage( + app_id.getText().toString(), + cont.getText().toString(), + pkg.getText().toString(), + cls.getText().toString(), + act.isChecked() ? WapPushManagerParams.APP_TYPE_ACTIVITY : + WapPushManagerParams.APP_TYPE_SERVICE, + sig.isChecked(), ftr.isChecked())) { + + Log.w(LOG_TAG, "remote add pkg failed..."); + mWapPushMan.updatePackage( + app_id.getText().toString(), + cont.getText().toString(), + pkg.getText().toString(), + cls.getText().toString(), + act.isChecked() ? WapPushManagerParams.APP_TYPE_ACTIVITY : + WapPushManagerParams.APP_TYPE_SERVICE, + sig.isChecked(), ftr.isChecked()); + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "remote func failed..."); + } + } + }); + + delbtn.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + EditText app_id = (EditText) findViewById(R.id.app_id); + EditText cont = (EditText) findViewById(R.id.cont); + EditText pkg = (EditText) findViewById(R.id.pkg); + EditText cls = (EditText) findViewById(R.id.cls); + // CheckBox delall = (CheckBox) findViewById(R.id.delall); + // Log.d(LOG_TAG, "button clicked"); + + try { + mWapPushMan.deletePackage( + app_id.getText().toString(), + cont.getText().toString(), + pkg.getText().toString(), + cls.getText().toString()); + // delall.isChecked()); + } catch (RemoteException e) { + Log.w(LOG_TAG, "remote func failed..."); + } + } + }); + + procbtn.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + EditText pdu = (EditText) findViewById(R.id.pdu); + EditText app_id = (EditText) findViewById(R.id.app_id); + EditText cont = (EditText) findViewById(R.id.cont); + + // WapPushOverSms wap = new WapPushOverSms(); + // wap.dispatchWapPdu(strToHex(pdu.getText().toString())); + try { + Intent intent = new Intent(); + intent.putExtra("transactionId", 0); + intent.putExtra("pduType", 6); + intent.putExtra("header", + HexDump.hexStringToByteArray(pdu.getText().toString())); + intent.putExtra("data", + HexDump.hexStringToByteArray(pdu.getText().toString())); + + mWapPushMan.processMessage( + app_id.getText().toString(), + cont.getText().toString(), + intent); + //HexDump.hexStringToByteArray(pdu.getText().toString()), 0, 6, 5, 5); + } catch (RemoteException e) { + Log.w(LOG_TAG, "remote func failed..."); + } + } + }); + } + + private IWapPushManager mWapPushMan; + private ServiceConnection conn = new ServiceConnection() { + public void onServiceDisconnected(ComponentName name) { + mWapPushMan = null; + Log.v(LOG_TAG, "service disconnected."); + } + + public void onServiceConnected(ComponentName name, IBinder service) { + mWapPushMan = IWapPushManager.Stub.asInterface(service); + Log.v(LOG_TAG, "service connected."); + } + }; + + @Override + public void onStart() { + super.onStart(); + Log.v(LOG_TAG, "onStart bind WAPPushManager service " + + IWapPushManager.class.getName()); + this.bindService(new Intent(IWapPushManager.class.getName()), conn, + Context.BIND_AUTO_CREATE); + Log.v(LOG_TAG, "bind service done."); + } + + @Override + public void onDestroy() { + super.onDestroy(); + this.unbindService(conn); + } + +} diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/DataVerify.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/DataVerify.java new file mode 100644 index 0000000..ef491fd --- /dev/null +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/DataVerify.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush.unitTests; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.util.Log; + +import com.android.internal.util.HexDump; + +/** + * To verify that receiver application receives correct body data. + */ +public class DataVerify extends Service { + private static final String LOG_TAG = "WAP PUSH"; + private static final int TIME_WAIT = 100; + private static final int WAIT_COUNT = 100; + private static byte[] mLastReceivedPdu = null; + private static boolean sDataSet = false; + + private class IDataVerifyStub extends IDataVerify.Stub { + public Context mContext; + + public IDataVerifyStub() { + } + + boolean arrayCompare(byte[] arr1, byte[] arr2) { + int i; + + if (arr1 == null || arr2 == null) { + if (arr1 == null) { + Log.w(LOG_TAG, "arr1 is null"); + } else { + Log.w(LOG_TAG, "arr2 is null"); + } + return false; + } + + if (arr1.length != arr2.length) { + return false; + } + + for (i = 0; i < arr1.length; i++) { + if (arr1[i] != arr2[i]) return false; + } + return true; + } + + /** + * Compare pdu and received pdu + */ + public synchronized boolean verifyData(byte[] pdu) { + int cnt = 0; + + while (!sDataSet) { + // wait for the activity receive data. + try { + Thread.sleep(TIME_WAIT); + if (cnt++ > WAIT_COUNT) { + // don't wait more than 10 sec. + return false; + } + } catch (InterruptedException e) {} + } + + Log.v(LOG_TAG, "verify pdu"); + boolean ret = arrayCompare(pdu, mLastReceivedPdu); + return ret; + } + + /** + * Clear the old data. This method must be called before starting the test + */ + public void resetData() { + mLastReceivedPdu = null; + sDataSet = false; + } + } + + private final IDataVerifyStub binder = new IDataVerifyStub(); + + /** + * Constructor + */ + public DataVerify() { + } + + /** + * Receiver application must call this method when it receives the wap push message + */ + public static void SetLastReceivedPdu(byte[] pdu) { + mLastReceivedPdu = pdu; + sDataSet = true; + } + + @Override + public IBinder onBind(Intent arg0) { + return binder; + } + +} + + diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/DrmReceiver.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/DrmReceiver.java new file mode 100644 index 0000000..5f5f121 --- /dev/null +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/DrmReceiver.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush.unitTests; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.android.internal.util.HexDump; + +/** + * A sample wap push receiver application for existing framework + * This class is listening for "application/vnd.oma.drm.rights+xml" message + */ +public class DrmReceiver extends BroadcastReceiver { + private static final String LOG_TAG = "WAP PUSH"; + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(LOG_TAG, "DrmReceiver received."); + + byte[] body; + byte[] header; + + body = intent.getByteArrayExtra("data"); + header = intent.getByteArrayExtra("header"); + + Log.d(LOG_TAG, "header:"); + Log.d(LOG_TAG, HexDump.dumpHexString(header)); + Log.d(LOG_TAG, "body:"); + Log.d(LOG_TAG, HexDump.dumpHexString(body)); + + DataVerify.SetLastReceivedPdu(body); + } + +} + + diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/IDataVerify.aidl b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/IDataVerify.aidl new file mode 100644 index 0000000..f0670fa --- /dev/null +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/IDataVerify.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush.unitTests; + +/** + * Interface to receiver application data verifyer class + */ +interface IDataVerify { + /** + * Verify data + */ + boolean verifyData(in byte[] pdu); + + /** + * Initialize data + */ + void resetData(); +} + diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ReceiverActivity.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ReceiverActivity.java new file mode 100644 index 0000000..07f55ea --- /dev/null +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ReceiverActivity.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush.unitTests; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +import com.android.internal.util.HexDump; + +/** + * Activity type receiver application + */ +public class ReceiverActivity extends Activity { + private static final String LOG_TAG = "WAP PUSH"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d(LOG_TAG, "activity created!!"); + + Intent in = getIntent(); + byte[] body; + byte[] header; + + body = in.getByteArrayExtra("data"); + header = in.getByteArrayExtra("header"); + + Log.d(LOG_TAG, "header:"); + Log.d(LOG_TAG, HexDump.dumpHexString(header)); + Log.d(LOG_TAG, "body:"); + Log.d(LOG_TAG, HexDump.dumpHexString(body)); + + DataVerify.SetLastReceivedPdu(body); + + finish(); + + } +} + diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ReceiverService.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ReceiverService.java new file mode 100644 index 0000000..b024bf5 --- /dev/null +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/ReceiverService.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush.unitTests; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.util.Log; + +import com.android.internal.util.HexDump; + +/** + * Service type receiver application + */ +public class ReceiverService extends Service { + private static final String LOG_TAG = "WAP PUSH"; + + @Override + public void onCreate() { + super.onCreate(); + Log.d(LOG_TAG, "Receiver service created"); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(LOG_TAG, "Receiver service started"); + + byte[] body; + byte[] header; + body = intent.getByteArrayExtra("data"); + header = intent.getByteArrayExtra("header"); + + Log.d(LOG_TAG, "header:"); + Log.d(LOG_TAG, HexDump.dumpHexString(header)); + Log.d(LOG_TAG, "body:"); + Log.d(LOG_TAG, HexDump.dumpHexString(body)); + + DataVerify.SetLastReceivedPdu(body); + return START_STICKY; + } +} + + diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java new file mode 100644 index 0000000..9b0a36b --- /dev/null +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java @@ -0,0 +1,2513 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smspush.unitTests; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.provider.Telephony.Sms.Intents; +import android.test.ServiceTestCase; +import android.util.Log; +import android.util.Config; + +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.IWapPushManager; +import com.android.internal.telephony.WapPushManagerParams; +import com.android.internal.telephony.WspTypeDecoder; +import com.android.internal.util.HexDump; +import com.android.smspush.WapPushManager; + +import java.util.Random; + +/** + * This is a simple framework for a test of a Service. See {@link android.test.ServiceTestCase + * ServiceTestCase} for more information on how to write and extend service tests. + * + * To run this test, you can type: + * adb shell am instrument -w \ + * -e class com.android.smspush.unitTests.WapPushTest \ + * com.android.smspush.unitTests/android.test.InstrumentationTestRunner + */ +public class WapPushTest extends ServiceTestCase<WapPushManager> { + private static final String LOG_TAG = "WAP PUSH"; + private static final boolean LOCAL_LOGV = false; + private static final int TIME_WAIT = 100; + + protected int mAppIdValue = 0x8002; + protected String mAppIdName = "x-wap-application:*"; + protected int mContentTypeValue = 0x030a; + protected String mContentTypeName = "application/vnd.wap.sic"; + + protected String mPackageName; + protected String mClassName; + + protected byte[] mGsmHeader = { + (byte) 0x00, // sc address + (byte) 0x40, // TP-MTI + (byte) 0x04, // sender address length? + (byte) 0x81, (byte) 0x55, (byte) 0x45, // sender address? + (byte) 0x00, // data schema + (byte) 0x00, // proto ID + (byte) 0x01, (byte) 0x60, (byte) 0x12, (byte) 0x31, + (byte) 0x74, (byte) 0x34, (byte) 0x63 // time stamp + }; + + protected byte[] mUserDataHeader = { + (byte) 0x07, // UDH len + (byte) 0x06, // header len + (byte) 0x05, // port addressing type? + (byte) 0x00, // dummy + (byte) 0x0B, (byte) 0x84, // dest port + (byte) 0x23, (byte) 0xF0 // src port + }; + + protected byte[] mWspHeader; + + protected byte[] mMessageBody = { + (byte) 0x00, + (byte) 0x01, + (byte) 0x02, + (byte) 0x03, + (byte) 0x04, + (byte) 0x05, + (byte) 0x06, + (byte) 0x07, + (byte) 0x08, + (byte) 0x09, + (byte) 0x0a, + (byte) 0x0b, + (byte) 0x0c, + (byte) 0x0d, + (byte) 0x0e, + (byte) 0x0f + }; + + protected int mWspHeaderStart; + protected int mWspHeaderLen; + protected int mWspContentTypeStart; + + /** + * OMA application ID in binary form + * http://www.openmobilealliance.org/tech/omna/omna-push-app-id.aspx + */ + final int[] OMA_APPLICATION_ID_VALUES = new int[] { + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x8000, + 0x8001, + 0x8002, + 0x8003, + 0x8004, + 0x8005, + 0x8006, + 0x8007, + 0x8008, + 0x8009, + 0x800B, + 0x8010 + }; + + /** + * OMA application ID in string form + * http://www.openmobilealliance.org/tech/omna/omna-push-app-id.aspx + */ + final String[] OMA_APPLICATION_ID_NAMES = new String[] { + "x-wap-application:*", + "x-wap-application:push.sia", + "x-wap-application:wml.ua", + "x-wap-application:wta.ua", + "x-wap-application:mms.ua", + "x-wap-application:push.syncml", + "x-wap-application:loc.ua", + "x-wap-application:syncml.dm", + "x-wap-application:drm.ua", + "x-wap-application:emn.ua", + "x-wap-application:wv.ua", + "x-wap-microsoft:localcontent.ua", + "x-wap-microsoft:IMclient.ua", + "x-wap-docomo:imode.mail.ua", + "x-wap-docomo:imode.mr.ua", + "x-wap-docomo:imode.mf.ua", + "x-motorola:location.ua", + "x-motorola:now.ua", + "x-motorola:otaprov.ua", + "x-motorola:browser.ua", + "x-motorola:splash.ua", + "x-wap-nai:mvsw.command", + "x-wap-openwave:iota.ua" + }; + + /** + * OMA content type in binary form + * http://www.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx + */ + final int[] OMA_CONTENT_TYPE_VALUES = new int[] { + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, +// 0x55, +// 0x56, +// 0x57, +// 0x58, + 0x0201, + 0x0202, + 0x0203, + 0x0204, + 0x0205, + 0x0206, + 0x0207, + 0x0208, + 0x0209, + 0x020A, + 0x020B, + 0x020C, + 0x0300, + 0x0301, + 0x0302, + 0x0303, + 0x0304, + 0x0305, + 0x0306, + 0x0307, + 0x0308, + 0x0309, + 0x030A, + 0x030B, + 0x030C, + 0x030D, + 0x030E, + 0x030F, + 0x0310, + 0x0311, + 0x0312, + 0x0313, + 0x0314, + 0x0315, + 0x0316, + 0x0317, + 0x0318, + 0x0319, + 0x031A, + 0x031B + /*0x031C, + 0x031D*/ + }; + + /** + * OMA content type in string form + * http://www.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx + */ + final String[] OMA_CONTENT_TYPE_NAMES = new String[] { + "*/*", + "text/*", + "text/html", + "text/plain", + "text/x-hdml", + "text/x-ttml", + "text/x-vCalendar", + "text/x-vCard", + "text/vnd.wap.wml", + "text/vnd.wap.wmlscript", + "text/vnd.wap.wta-event", + "multipart/*", + "multipart/mixed", + "multipart/form-data", + "multipart/byterantes", + "multipart/alternative", + "application/*", + "application/java-vm", + "application/x-www-form-urlencoded", + "application/x-hdmlc", + "application/vnd.wap.wmlc", + "application/vnd.wap.wmlscriptc", + "application/vnd.wap.wta-eventc", + "application/vnd.wap.uaprof", + "application/vnd.wap.wtls-ca-certificate", + "application/vnd.wap.wtls-user-certificate", + "application/x-x509-ca-cert", + "application/x-x509-user-cert", + "image/*", + "image/gif", + "image/jpeg", + "image/tiff", + "image/png", + "image/vnd.wap.wbmp", + "application/vnd.wap.multipart.*", + "application/vnd.wap.multipart.mixed", + "application/vnd.wap.multipart.form-data", + "application/vnd.wap.multipart.byteranges", + "application/vnd.wap.multipart.alternative", + "application/xml", + "text/xml", + "application/vnd.wap.wbxml", + "application/x-x968-cross-cert", + "application/x-x968-ca-cert", + "application/x-x968-user-cert", + "text/vnd.wap.si", + "application/vnd.wap.sic", + "text/vnd.wap.sl", + "application/vnd.wap.slc", + "text/vnd.wap.co", + "application/vnd.wap.coc", + "application/vnd.wap.multipart.related", + "application/vnd.wap.sia", + "text/vnd.wap.connectivity-xml", + "application/vnd.wap.connectivity-wbxml", + "application/pkcs7-mime", + "application/vnd.wap.hashed-certificate", + "application/vnd.wap.signed-certificate", + "application/vnd.wap.cert-response", + "application/xhtml+xml", + "application/wml+xml", + "text/css", + "application/vnd.wap.mms-message", + "application/vnd.wap.rollover-certificate", + "application/vnd.wap.locc+wbxml", + "application/vnd.wap.loc+xml", + "application/vnd.syncml.dm+wbxml", + "application/vnd.syncml.dm+xml", + "application/vnd.syncml.notification", + "application/vnd.wap.xhtml+xml", + "application/vnd.wv.csp.cir", + "application/vnd.oma.dd+xml", + "application/vnd.oma.drm.message", + "application/vnd.oma.drm.content", + "application/vnd.oma.drm.rights+xml", + "application/vnd.oma.drm.rights+wbxml", + "application/vnd.wv.csp+xml", + "application/vnd.wv.csp+wbxml", + "application/vnd.syncml.ds.notification", + "audio/*", + "video/*", + "application/vnd.oma.dd2+xml", + "application/mikey", + "application/vnd.oma.dcd", + "application/vnd.oma.dcdc", +// "text/x-vMessage", +// "application/vnd.omads-email+wbxml", +// "text/x-vBookmark", +// "application/vnd.syncml.dm.notification", + "application/vnd.uplanet.cacheop-wbxml", + "application/vnd.uplanet.signal", + "application/vnd.uplanet.alert-wbxml", + "application/vnd.uplanet.list-wbxml", + "application/vnd.uplanet.listcmd-wbxml", + "application/vnd.uplanet.channel-wbxml", + "application/vnd.uplanet.provisioning-status-uri", + "x-wap.multipart/vnd.uplanet.header-set", + "application/vnd.uplanet.bearer-choice-wbxml", + "application/vnd.phonecom.mmc-wbxml", + "application/vnd.nokia.syncset+wbxml", + "image/x-up-wpng", + "application/iota.mmc-wbxml", + "application/iota.mmc-xml", + "application/vnd.syncml+xml", + "application/vnd.syncml+wbxml", + "text/vnd.wap.emn+xml", + "text/calendar", + "application/vnd.omads-email+xml", + "application/vnd.omads-file+xml", + "application/vnd.omads-folder+xml", + "text/directory;profile=vCard", + "application/vnd.wap.emn+wbxml", + "application/vnd.nokia.ipdc-purchase-response", + "application/vnd.motorola.screen3+xml", + "application/vnd.motorola.screen3+gzip", + "application/vnd.cmcc.setting+wbxml", + "application/vnd.cmcc.bombing+wbxml", + "application/vnd.docomo.pf", + "application/vnd.docomo.ub", + "application/vnd.omaloc-supl-init", + "application/vnd.oma.group-usage-list+xml", + "application/oma-directory+xml", + "application/vnd.docomo.pf2", + "application/vnd.oma.drm.roap-trigger+wbxml", + "application/vnd.sbm.mid2", + "application/vnd.wmf.bootstrap", + "application/vnc.cmcc.dcd+xml", + "application/vnd.sbm.cid", + "application/vnd.oma.bcast.provisioningtrigger", + /*"application/vnd.docomo.dm", + "application/vnd.oma.scidm.messages+xml"*/ + }; + + private IDataVerify mIVerify = null; + + ServiceConnection mConn = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + Log.v(LOG_TAG, "data verify interface connected."); + mIVerify = IDataVerify.Stub.asInterface(service); + } + public void onServiceDisconnected(ComponentName name) { + } + }; + + /** + * Main WapPushManager test module constructor + */ + public WapPushTest() { + super(WapPushManager.class); + mClassName = this.getClass().getName(); + mPackageName = this.getClass().getPackage().getName(); + } + + /** + * Initialize the verifier + */ + @Override + public void setUp() { + try { + super.setUp(); + // get verifier + getContext().bindService(new Intent(IDataVerify.class.getName()), + mConn, Context.BIND_AUTO_CREATE); + } catch (Exception e) { + Log.w(LOG_TAG, "super exception"); + } + // Log.d(LOG_TAG, "test setup"); + } + + private IWapPushManager mWapPush = null; + IWapPushManager getInterface() { + if (mWapPush != null) return mWapPush; + Intent startIntent = new Intent(); + startIntent.setClass(getContext(), WapPushManager.class); + IBinder service = bindService(startIntent); + + mWapPush = IWapPushManager.Stub.asInterface(service); + return mWapPush; + } + + /* + * All methods need to start with 'test'. + * Use various assert methods to pass/fail the test case. + */ + protected void utAddPackage(boolean need_sig, boolean more_proc) { + IWapPushManager iwapman = getInterface(); + + // insert new data + try { + assertTrue(iwapman.addPackage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, need_sig, more_proc)); + } catch (RemoteException e) { + assertTrue(false); + } + + // verify the data + WapPushManager wpman = getService(); + assertTrue(wpman.verifyData(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, need_sig, more_proc)); + } + + /** + * Add package test + */ + public void testAddPackage1() { + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + + utAddPackage(true, true); + mAppIdValue += 10; + utAddPackage(true, false); + mContentTypeValue += 20; + utAddPackage(false, true); + mContentTypeValue += 20; + utAddPackage(false, false); + + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + + // clean up data + try { + IWapPushManager iwapman = getInterface(); + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + mAppIdValue += 10; + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + mContentTypeValue += 20; + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + mContentTypeValue += 20; + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + } catch (RemoteException e) { + assertTrue(false); + } + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + } + + /** + * Add duprecated package test. + */ + public void testAddPackage2() { + try { + IWapPushManager iwapman = getInterface(); + + // set up data + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, 0, + false, false); + iwapman.addPackage(Integer.toString(mAppIdValue + 10), + Integer.toString(mContentTypeValue), mPackageName, mClassName, 0, + false, false); + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue + 10), mPackageName, mClassName, 0, + false, false); + + assertFalse(iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, 0, + false, false)); + assertFalse(iwapman.addPackage(Integer.toString(mAppIdValue + 10), + Integer.toString(mContentTypeValue), mPackageName, mClassName, 0, + false, false)); + assertFalse(iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue + 10), mPackageName, mClassName, 0, + false, false)); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + iwapman.deletePackage(Integer.toString(mAppIdValue + 10), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue + 10), mPackageName, mClassName); + } catch (RemoteException e) { + assertTrue(false); + } + } + + protected void utUpdatePackage(boolean need_sig, boolean more_proc) { + IWapPushManager iwapman = getInterface(); + + // insert new data + try { + assertTrue(iwapman.updatePackage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, need_sig, more_proc)); + } catch (RemoteException e) { + assertTrue(false); + } + + // verify the data + WapPushManager wpman = getService(); + assertTrue(wpman.verifyData( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, need_sig, more_proc)); + } + + /** + * Updating package test + */ + public void testUpdatePackage1() { + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + + // set up data + try { + IWapPushManager iwapman = getInterface(); + + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + mAppIdValue += 10; + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + mContentTypeValue += 20; + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + mContentTypeValue += 20; + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + } catch (RemoteException e) { + assertTrue(false); + } + + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + utUpdatePackage(false, false); + mAppIdValue += 10; + utUpdatePackage(false, true); + mContentTypeValue += 20; + utUpdatePackage(true, false); + mContentTypeValue += 20; + utUpdatePackage(true, true); + + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + + // clean up data + try { + IWapPushManager iwapman = getInterface(); + + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + mAppIdValue += 10; + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + mContentTypeValue += 20; + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + mContentTypeValue += 20; + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + } catch (RemoteException e) { + assertTrue(false); + } + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + } + + /** + * Updating invalid package test + */ + public void testUpdatePackage2() { + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + + try { + // set up data + IWapPushManager iwapman = getInterface(); + + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + assertFalse(iwapman.updatePackage( + Integer.toString(mAppIdValue + 10), + Integer.toString(mContentTypeValue), + mPackageName, mClassName, 0, false, false)); + assertFalse(iwapman.updatePackage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue + 10), + mPackageName, mClassName, 0, false, false)); + assertTrue(iwapman.updatePackage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName + "dummy_data", mClassName, 0, false, false)); + assertTrue(iwapman.updatePackage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName + "dummy_data", 0, false, false)); + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, + mClassName + "dummy_data"); + } catch (RemoteException e) { + assertTrue(false); + } + } + + protected void utDeletePackage() { + IWapPushManager iwapman = getInterface(); + + try { + assertTrue(iwapman.deletePackage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName)); + } catch (RemoteException e) { + assertTrue(false); + } + + // verify the data + WapPushManager wpman = getService(); + assertTrue(!wpman.isDataExist( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName)); + } + + /** + * Deleting package test + */ + public void testDeletePackage1() { + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + + // set up data + try { + IWapPushManager iwapman = getInterface(); + + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + mAppIdValue += 10; + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + mContentTypeValue += 20; + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + mContentTypeValue += 20; + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + } catch (RemoteException e) { + assertTrue(false); + } + + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + utDeletePackage(); + mAppIdValue += 10; + utDeletePackage(); + mContentTypeValue += 20; + utDeletePackage(); + mContentTypeValue += 20; + utDeletePackage(); + + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + } + + /** + * Deleting invalid package test + */ + public void testDeletePackage2() { + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + + try { + // set up data + IWapPushManager iwapman = getInterface(); + + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + 0, false, false); + + assertFalse(iwapman.deletePackage(Integer.toString(mAppIdValue + 10), + Integer.toString(mContentTypeValue), mPackageName, mClassName)); + assertFalse(iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue + 20), mPackageName, mClassName)); + assertFalse(iwapman.deletePackage(Integer.toString(mAppIdValue + 10), + Integer.toString(mContentTypeValue + 20), mPackageName, mClassName)); + + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + } catch (RemoteException e) { + assertTrue(false); + } + } + + + protected int encodeUint32(int uint32Val, byte[] arr, int start) { + int bit = 1; + int topbit = 0; + int encodeLen; + int tmpVal; + + assertTrue(uint32Val >= 0); + for (int i = 0; i < 31; i++) { + if ((bit & uint32Val) > 0) topbit = i; + bit = (bit << 1); + } + encodeLen = topbit/7 + 1; + if (arr == null) return encodeLen; + + //Log.d(LOG_TAG, "uint32Val = " + Integer.toHexString(uint32Val) + ", topbit = " + // + topbit + ", encodeLen = " + encodeLen); + + tmpVal = uint32Val; + for (int i = encodeLen - 1; i >= 0; i--) { + long val = 0; + if (i < encodeLen - 1) val = 0x80; + val |= tmpVal & 0x7f; + arr[start + i] = (byte) (val & 0xFF); + tmpVal = (tmpVal >> 7); + } + return encodeLen; + } + + protected int encodeShortInt(int sintVal, byte[] arr, int start) { + int encodeLen = 0; + + if (sintVal >= 0x80) return encodeLen; + encodeLen = 1; + arr[start] = (byte) (sintVal | 0x80); + return encodeLen; + } + + + /** + * Generate Random WSP header with integer application ID + */ + protected void createRandomWspHeader(byte[] arr, Random rd, int headerStart, + boolean noAppId) { + + boolean appIdAdded = false; + + Log.d(LOG_TAG, "headerStart = " + headerStart + ", appId = " + mAppIdValue + + "(" + Integer.toHexString(mAppIdValue) + ")"); + Log.d(LOG_TAG, "random arr length:" + arr.length); + String typename[] = new String[] { "short int", "long int", "string", "uint32"}; + + while (!appIdAdded) { + int type; + int index = headerStart; + int len = arr.length; + int i; + boolean addAppid = false; + int tmpVal = 0; + int tmpVal2 = 0; + + while (true) { + int add; + + /* + * field name + * 0: short int + * 1: long int + * 2: text + * (no uint for param value) + */ + type = rd.nextInt(3); + switch (type) { + case 0: // header short integer + if (index > 100 && !appIdAdded) addAppid = true; + add = 1; + break; + case 1: // header long int + add = 1 + rd.nextInt(29); + break; + default: // header string + add = 2 + rd.nextInt(10); + break; + } + if (index + add >= len) break; + + // fill header name + switch (type) { + case 0: // header short integer + if (!addAppid) { + do { + arr[index] = (byte) (0x80 | rd.nextInt(128)); + } while (arr[index] == (byte) 0xaf); + } else { + Log.d(LOG_TAG, "appId added."); + arr[index] = (byte) 0xaf; + // if noAppId case, appId fld must be decieved. + if (noAppId) arr[index]++; + } + break; + case 1: // header long int + arr[index] = (byte) (add - 1); + tmpVal2 = 0; + for (i = 1; i < add; i++) { + tmpVal = rd.nextInt(255); + tmpVal2 = (tmpVal2 << 8) | tmpVal; + arr[index + i] = (byte) tmpVal; + } + // don't set application id + if (tmpVal2 == 0x2f) arr[index + 1]++; + break; + default: // header string + for (i = 0; i < add - 1; i++) { + tmpVal = rd.nextInt(127); + if (tmpVal < 32) tmpVal= (32 + tmpVal); + arr[index + i] = (byte) tmpVal; + } + arr[index + i] = (byte) 0x0; + break; + } + + if (LOCAL_LOGV) { + Log.d(LOG_TAG, "field name index:" + index); + Log.d(LOG_TAG, "type:" + typename[type] + ", add:" + add); + if (type != 2) { + for (i = index; i< index + add; i++) { + System.out.print(Integer.toHexString(0xff & arr[i])); + System.out.print(' '); + } + } else { + System.out.print(Integer.toHexString(0xff & arr[index])); + System.out.print(' '); + String str = new String(arr, index + 1, add - 2); + for (i = 0; i < str.length(); i++) { + System.out.print(str.charAt(i)); + System.out.print(' '); + } + } + System.out.print('\n'); + } + index += add; + + + /* + * field value + * 0: short int + * 1: long int + * 2: text + * 3: uint + */ + if (addAppid) { + type = 1; + } else { + type = rd.nextInt(4); + } + switch (type) { + case 0: // header short integer + add = 1; + break; + case 1: // header long int + if (addAppid) { + int bit = 1; + int topBit = 0; + + for (i = 0; i < 31; i++) { + if ((mAppIdValue & bit) > 0) topBit = i; + bit = (bit << 1); + } + add = 2 + topBit/8; + } else { + add = 1 + rd.nextInt(29); + } + break; + case 2: // header string + add = 2 + rd.nextInt(10); + break; + default: // uint32 + add = 6; + } + if (index + add >= len) break; + + // fill field value + switch (type) { + case 0: // header short int + arr[index] = (byte) (0x80 | rd.nextInt(128)); + break; + case 1: // header long int + if (addAppid) { + addAppid = false; + appIdAdded = true; + + arr[index] = (byte) (add - 1); + tmpVal = mAppIdValue; + for (i = add; i > 1; i--) { + arr[index + i - 1] = (byte) (tmpVal & 0xff); + tmpVal = (tmpVal >> 8); + } + } else { + arr[index] = (byte) (add - 1); + for (i = 1; i < add; i++) { + arr[index + i] = (byte) rd.nextInt(255); + } + } + break; + case 2:// header string + for (i = 0; i < add - 1; i++) { + tmpVal = rd.nextInt(127); + if (tmpVal < 32) tmpVal= (32 + tmpVal); + arr[index + i] = (byte) tmpVal; + } + arr[index + i] = (byte) 0x0; + break; + default: // header uvarint + arr[index] = (byte) 31; + tmpVal = rd.nextInt(0x0FFFFFFF); + add = 1 + encodeUint32(tmpVal, null, index + 1); + encodeUint32(tmpVal, arr, index + 1); + break; + + } + + if (LOCAL_LOGV) { + Log.d(LOG_TAG, "field value index:" + index); + Log.d(LOG_TAG, "type:" + typename[type] + ", add:" + add); + if (type != 2) { + for (i = index; i< index + add; i++) { + System.out.print(Integer.toHexString(0xff & arr[i])); + System.out.print(' '); + } + } else { + System.out.print(Integer.toHexString(0xff & arr[index])); + System.out.print(' '); + String str = new String(arr, index + 1, add - 2); + for (i = 0; i < str.length(); i++) { + System.out.print(str.charAt(i)); + System.out.print(' '); + } + } + System.out.print('\n'); + } + index += add; + } + if (noAppId) break; + } + + Log.d(LOG_TAG, HexDump.dumpHexString(arr)); + } + + /** + * Generate Random WSP header with string application ID + */ + protected void createRandomWspHeaderStrAppId(byte[] arr, Random rd, int headerStart, + boolean randomStr) { + + boolean appIdAdded = false; + + Log.d(LOG_TAG, "random arr length:" + arr.length); + String typename[] = new String[] { "short int", "long int", "string", "uint32"}; + + while (!appIdAdded) { + int type; + int index = headerStart; + int len = arr.length; + int i; + boolean addAppid = false; + int tmpVal = 0; + int tmpVal2 = 0; + + while (true) { + int add; + + /* + * field name + * 0: short int + * 1: long int + * 2: text + * (no uint for param value) + */ + type = rd.nextInt(3); + switch (type) { + case 0: // header short integer + if (index > 100 && !appIdAdded) addAppid = true; + add = 1; + break; + case 1: // header long int + add = 1 + rd.nextInt(29); + break; + default: // header string + add = 2 + rd.nextInt(10); + break; + } + if (index + add >= len) break; + + // fill header name + switch (type) { + case 0: // header short integer + if (!addAppid) { + do { + arr[index] = (byte) (0x80 | rd.nextInt(128)); + } while (arr[index] == (byte) 0xaf); + } else { + Log.d(LOG_TAG, "appId added."); + arr[index] = (byte) 0xaf; + } + break; + case 1: // header long int + arr[index] = (byte) (add - 1); + tmpVal2 = 0; + for (i = 1; i < add; i++) { + tmpVal = rd.nextInt(255); + tmpVal2 = (tmpVal2 << 8) | tmpVal; + arr[index + i] = (byte) tmpVal; + } + // don't set application id + if (tmpVal2 == 0x2f) arr[index + 1]++; + break; + default: // header string + for (i = 0; i < add - 1; i++) { + tmpVal = rd.nextInt(127); + if (tmpVal < 32) tmpVal= (32 + tmpVal); + arr[index + i] = (byte) tmpVal; + } + arr[index + i] = (byte) 0x0; + break; + } + + if (LOCAL_LOGV) { + Log.d(LOG_TAG, "field name index:" + index); + Log.d(LOG_TAG, "type:" + typename[type] + ", add:" + add); + if (type != 2) { + for (i = index; i < index + add; i++) { + System.out.print(Integer.toHexString(0xff & arr[i])); + System.out.print(' '); + } + } else { + System.out.print(Integer.toHexString(0xff & arr[index])); + System.out.print(' '); + String str = new String(arr, index + 1, add - 2); + for (i = 0; i < str.length(); i++) { + System.out.print(str.charAt(i)); + System.out.print(' '); + } + } + System.out.print('\n'); + } + index += add; + + + /* + * field value + * 0: short int + * 1: long int + * 2: text + * 3: uint + */ + if (addAppid) { + type = 2; + } else { + type = rd.nextInt(4); + } + switch (type) { + case 0: // header short integer + add = 1; + break; + case 1: // header long int + add = 1 + rd.nextInt(29); + break; + case 2: // header string + if (addAppid) { + if (randomStr) { + add = 1 + rd.nextInt(10); + byte[] randStr= new byte[add]; + for (i = 0; i < add; i++) { + tmpVal = rd.nextInt(127); + if (tmpVal < 32) tmpVal= (32 + tmpVal); + randStr[i] = (byte) tmpVal; + } + mAppIdName = new String(randStr); + } + add = mAppIdName.length() + 1; + } else { + add = 2 + rd.nextInt(10); + } + break; + default: // uint32 + add = 6; + } + if (index + add >= len) break; + + // fill field value + switch (type) { + case 0: // header short int + arr[index] = (byte) (0x80 | rd.nextInt(128)); + break; + case 1: // header long int + arr[index] = (byte) (add - 1); + for (i = 1; i < add; i++) + arr[index + i] = (byte) rd.nextInt(255); + break; + case 2:// header string + if (addAppid) { + addAppid = false; + appIdAdded = true; + for (i = 0; i < add - 1; i++) { + arr[index + i] = (byte) (mAppIdName.charAt(i)); + } + Log.d(LOG_TAG, "mAppIdName added [" + mAppIdName + "]"); + } else { + for (i = 0; i < add - 1; i++) { + tmpVal = rd.nextInt(127); + if (tmpVal < 32) tmpVal= (32 + tmpVal); + arr[index + i] = (byte) tmpVal; + } + } + arr[index + i] = (byte) 0x0; + break; + default: // header uvarint + arr[index] = (byte) 31; + tmpVal = rd.nextInt(0x0FFFFFFF); + add = 1 + encodeUint32(tmpVal, null, index + 1); + encodeUint32(tmpVal, arr, index + 1); + break; + + } + + if (LOCAL_LOGV) { + Log.d(LOG_TAG, "field value index:" + index); + Log.d(LOG_TAG, "type:" + typename[type] + ", add:" + add); + if (type != 2) { + for (i = index; i < index + add; i++) { + System.out.print(Integer.toHexString(0xff & arr[i])); + System.out.print(' '); + } + } else { + System.out.print(Integer.toHexString(0xff & arr[index])); + System.out.print(' '); + String str = new String(arr, index + 1, add - 2); + for (i = 0; i < str.length(); i++) { + System.out.print(str.charAt(i)); + System.out.print(' '); + } + } + System.out.print('\n'); + } + index += add; + } + } + + Log.d(LOG_TAG, "headerStart = " + headerStart + ", mAppIdName = " + mAppIdName); + Log.d(LOG_TAG, HexDump.dumpHexString(arr)); + } + + protected byte[] createPDU(int testNum) { + byte[] array = null; + // byte[] wsp = null; + + switch (testNum) { + // sample pdu + case 1: + byte[] array1 = { + (byte) 0x00, // TID + (byte) 0x06, // Type = wap push + (byte) 0x00, // Length to be set later. + + // Content-Type + (byte) 0x03, (byte) 0x02, + (byte) ((mContentTypeValue >> 8) & 0xff), + (byte) (mContentTypeValue & 0xff), + + // Application-id + (byte) 0xaf, (byte) 0x02, + (byte) ((mAppIdValue >> 8) & 0xff), + (byte) (mAppIdValue& 0xff) + }; + array1[2] = (byte) (array1.length - 3); + mWspHeader = array1; + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length + 7; + mWspHeaderLen = array1.length; + break; + + // invalid wsp header + case 2: + byte[] array2 = { + (byte) 0x00, // invalid data + }; + mWspHeader = array2; + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length; + mWspHeaderLen = array2.length; + break; + + // random wsp header + case 3: + Random rd = new Random(); + int arrSize = 150 + rd.nextInt(100); + byte[] array3 = new byte[arrSize]; + int hdrEncodeLen; + + array3[0] = (byte) 0x0; + array3[1] = (byte) 0x6; + hdrEncodeLen = encodeUint32(array3.length, null, 2); + hdrEncodeLen = encodeUint32(array3.length - hdrEncodeLen - 2, array3, 2); + array3[hdrEncodeLen + 2] = (byte) 0x3; + array3[hdrEncodeLen + 3] = (byte) 0x2; + array3[hdrEncodeLen + 4] = (byte) ((mContentTypeValue >> 8) & 0xff); + array3[hdrEncodeLen + 5] = (byte) (mContentTypeValue & 0xff); + createRandomWspHeader(array3, rd, hdrEncodeLen + 6, false); + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length + hdrEncodeLen + 6; + mWspHeaderLen = array3.length; + + Log.d(LOG_TAG, "mContentTypeValue = " + mContentTypeValue + + "(" + Integer.toHexString(mContentTypeValue) + ")"); + + mWspHeader = array3; + break; + + // random wsp header w/o appid + case 4: + rd = new Random(); + arrSize = 150 + rd.nextInt(100); + array3 = new byte[arrSize]; + + array3[0] = (byte) 0x0; + array3[1] = (byte) 0x6; + hdrEncodeLen = encodeUint32(array3.length, null, 2); + hdrEncodeLen = encodeUint32(array3.length - hdrEncodeLen - 2, array3, 2); + array3[hdrEncodeLen + 2] = (byte) 0x3; + array3[hdrEncodeLen + 3] = (byte) 0x2; + array3[hdrEncodeLen + 4] = (byte) ((mContentTypeValue >> 8) & 0xff); + array3[hdrEncodeLen + 5] = (byte) (mContentTypeValue & 0xff); + createRandomWspHeader(array3, rd, hdrEncodeLen + 6, true); + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length + hdrEncodeLen + 6; + mWspHeaderLen = array3.length; + + Log.d(LOG_TAG, "mContentTypeValue = " + mContentTypeValue + + "(" + Integer.toHexString(mContentTypeValue) + ")"); + + mWspHeader = array3; + break; + + // random wsp header w/ random appid string + case 5: + rd = new Random(); + arrSize = 150 + rd.nextInt(100); + array3 = new byte[arrSize]; + + array3[0] = (byte) 0x0; + array3[1] = (byte) 0x6; + hdrEncodeLen = encodeUint32(array3.length, null, 2); + hdrEncodeLen = encodeUint32(array3.length - hdrEncodeLen - 2, array3, 2); + array3[hdrEncodeLen + 2] = (byte) 0x3; + array3[hdrEncodeLen + 3] = (byte) 0x2; + array3[hdrEncodeLen + 4] = (byte) ((mContentTypeValue >> 8) & 0xff); + array3[hdrEncodeLen + 5] = (byte) (mContentTypeValue & 0xff); + createRandomWspHeaderStrAppId(array3, rd, hdrEncodeLen + 6, true); + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length + hdrEncodeLen + 6; + mWspHeaderLen = array3.length; + + Log.d(LOG_TAG, "mContentTypeValue = " + mContentTypeValue + + "(" + Integer.toHexString(mContentTypeValue) + ")"); + + mWspHeader = array3; + break; + + // random wsp header w/ OMA appid string + case 6: + rd = new Random(); + arrSize = 150 + rd.nextInt(100); + array3 = new byte[arrSize]; + + array3[0] = (byte) 0x0; + array3[1] = (byte) 0x6; + hdrEncodeLen = encodeUint32(array3.length, null, 2); + hdrEncodeLen = encodeUint32(array3.length - hdrEncodeLen - 2, array3, 2); + array3[hdrEncodeLen + 2] = (byte) 0x3; + array3[hdrEncodeLen + 3] = (byte) 0x2; + array3[hdrEncodeLen + 4] = (byte) ((mContentTypeValue >> 8) & 0xff); + array3[hdrEncodeLen + 5] = (byte) (mContentTypeValue & 0xff); + createRandomWspHeaderStrAppId(array3, rd, hdrEncodeLen + 6, false); + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length + hdrEncodeLen + 6; + mWspHeaderLen = array3.length; + + Log.d(LOG_TAG, "mContentTypeValue = " + mContentTypeValue + + "(" + Integer.toHexString(mContentTypeValue) + ")"); + + mWspHeader = array3; + break; + + // random wsp header w/ OMA content type + case 7: + rd = new Random(); + arrSize = 150 + rd.nextInt(100); + array3 = new byte[arrSize]; + + array3[0] = (byte) 0x0; + array3[1] = (byte) 0x6; + hdrEncodeLen = encodeUint32(array3.length, null, 2); + hdrEncodeLen = encodeUint32(array3.length - hdrEncodeLen - 2, array3, 2); + + // encode content type + int contentLen = mContentTypeName.length(); + int next = 2 + hdrEncodeLen; + mWspContentTypeStart = mGsmHeader.length + mUserDataHeader.length + next; + // next += encodeUint32(contentLen, array3, next); + int i; + Log.d(LOG_TAG, "mContentTypeName = " + mContentTypeName + + ", contentLen = " + contentLen); + + for (i = 0; i < contentLen; i++) { + array3[next + i] = (byte) mContentTypeName.charAt(i); + } + array3[next + i] = (byte) 0x0; + + createRandomWspHeader(array3, rd, next + contentLen + 1, false); + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length + + next + contentLen + 1; + mWspHeaderLen = array3.length; + + mWspHeader = array3; + break; + + // random wsp header w/ OMA content type, OMA app ID + case 8: + rd = new Random(); + arrSize = 150 + rd.nextInt(100); + array3 = new byte[arrSize]; + + array3[0] = (byte) 0x0; + array3[1] = (byte) 0x6; + hdrEncodeLen = encodeUint32(array3.length, null, 2); + hdrEncodeLen = encodeUint32(array3.length - hdrEncodeLen - 2, array3, 2); + + // encode content type + contentLen = mContentTypeName.length(); + next = 2 + hdrEncodeLen; + mWspContentTypeStart = mGsmHeader.length + mUserDataHeader.length + next; + // next += encodeUint32(contentLen, array3, next); + Log.d(LOG_TAG, "mContentTypeName = " + mContentTypeName + + ", contentLen = " + contentLen); + + for (i = 0; i < contentLen; i++) { + array3[next + i] = (byte) mContentTypeName.charAt(i); + } + array3[next + i] = (byte) 0x0; + + createRandomWspHeaderStrAppId(array3, rd, next + contentLen + 1, false); + mWspHeaderStart = mGsmHeader.length + mUserDataHeader.length + + next + contentLen + 1; + mWspHeaderLen = array3.length; + + mWspHeader = array3; + break; + + default: + return null; + } + array = new byte[mGsmHeader.length + mUserDataHeader.length + mWspHeader.length + + mMessageBody.length]; + System.arraycopy(mGsmHeader, 0, array, 0, mGsmHeader.length); + System.arraycopy(mUserDataHeader, 0, array, + mGsmHeader.length, mUserDataHeader.length); + System.arraycopy(mWspHeader, 0, array, + mGsmHeader.length + mUserDataHeader.length, mWspHeader.length); + System.arraycopy(mMessageBody, 0, array, + mGsmHeader.length + mUserDataHeader.length + mWspHeader.length, + mMessageBody.length); + return array; + + } + + Intent createIntent(int pduType, int tranId) { + Intent intent = new Intent(); + intent.putExtra("transactionId", tranId); + intent.putExtra("pduType", pduType); + intent.putExtra("header", mGsmHeader); + intent.putExtra("data", mMessageBody); + // intent.putExtra("contentTypeParameters", null); + return intent; + } + + /** + * Message processing test, start activity + */ + public void testProcessMsg1() { + byte[] pdu = createPDU(1); + int headerLen = pdu.length - + (mGsmHeader.length + mUserDataHeader.length + mMessageBody.length); + int pduType = 6; + int tranId = 0; + String originalPackageName = mPackageName; + String originalClassName = mClassName; + + try { + + mClassName = "com.android.smspush.unitTests.ReceiverActivity"; + + // set up data + IWapPushManager iwapman = getInterface(); + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_ACTIVITY, false, false); + + assertTrue((iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)) + & WapPushManagerParams.MESSAGE_HANDLED) == + WapPushManagerParams.MESSAGE_HANDLED); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + } catch (RemoteException e) { + assertTrue(false); + } + + mPackageName = originalPackageName; + mClassName = originalClassName; + } + + /** + * Message processing test, start service + */ + public void testProcessMsg2() { + byte[] pdu = createPDU(1); + int headerLen = pdu.length - (mGsmHeader.length + + mUserDataHeader.length + mMessageBody.length); + int pduType = 6; + int tranId = 0; + String originalPackageName = mPackageName; + String originalClassName = mClassName; + + try { + + mClassName = "com.android.smspush.unitTests.ReceiverService"; + + // set up data + IWapPushManager iwapman = getInterface(); + + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, false, false); + + assertTrue((iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)) + & WapPushManagerParams.MESSAGE_HANDLED) == + WapPushManagerParams.MESSAGE_HANDLED); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + } catch (RemoteException e) { + assertTrue(false); + } + + mPackageName = originalPackageName; + mClassName = originalClassName; + } + + /** + * Message processing test, no signature + */ + public void testProcessMsg3() { + byte[] pdu = createPDU(1); + int headerLen = pdu.length - + (mGsmHeader.length + mUserDataHeader.length + mMessageBody.length); + int pduType = 6; + int tranId = 0; + String originalPackageName = mPackageName; + String originalClassName = mClassName; + + try { + + mPackageName = "com.android.development"; + mClassName = "com.android.development.Development"; + + // set up data + IWapPushManager iwapman = getInterface(); + + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, true, false); + + assertFalse((iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)) + & WapPushManagerParams.MESSAGE_HANDLED) == + WapPushManagerParams.MESSAGE_HANDLED); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + } catch (RemoteException e) { + assertTrue(false); + } + + mPackageName = originalPackageName; + mClassName = originalClassName; + } + + IDataVerify getVerifyInterface() { + while (mIVerify == null) { + // wait for the activity receive data. + try { + Thread.sleep(TIME_WAIT); + } catch (InterruptedException e) {} + } + return mIVerify; + } + + + /** + * Message processing test, received body data verification test + */ + public void testProcessMsg4() { + byte[] originalMessageBody = mMessageBody; + mMessageBody = new byte[] { + (byte) 0xee, + (byte) 0xff, + (byte) 0xee, + (byte) 0xff, + (byte) 0xee, + (byte) 0xff, + (byte) 0xee, + (byte) 0xff, + (byte) 0xee, + (byte) 0xff, + (byte) 0xee, + (byte) 0xff, + }; + + byte[] pdu = createPDU(1); + int headerLen = pdu.length - + (mGsmHeader.length + mUserDataHeader.length + mMessageBody.length); + int pduType = 6; + int tranId = 0; + String originalPackageName = mPackageName; + String originalClassName = mClassName; + + try { + IWapPushManager iwapman = getInterface(); + IDataVerify dataverify = getVerifyInterface(); + + dataverify.resetData(); + + // set up data + mClassName = "com.android.smspush.unitTests.ReceiverActivity"; + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_ACTIVITY, false, false); + + iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + assertTrue(dataverify.verifyData(mMessageBody)); + + // set up data + dataverify.resetData(); + mClassName = "com.android.smspush.unitTests.ReceiverService"; + mMessageBody = new byte[] { + (byte) 0xaa, + (byte) 0xbb, + (byte) 0x11, + (byte) 0x22, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0x11, + (byte) 0x22, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0x11, + (byte) 0x22, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0x11, + (byte) 0x22, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0x11, + (byte) 0x22, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0x11, + (byte) 0x22, + }; + pdu = createPDU(1); + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, false, false); + + iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + // Log.d(LOG_TAG, HexDump.dumpHexString(mMessageBody)); + assertTrue(dataverify.verifyData(mMessageBody)); + } catch (RemoteException e) { + assertTrue(false); + } + + mPackageName = originalPackageName; + mClassName = originalClassName; + mMessageBody = originalMessageBody; + } + + /** + * Message processing test, send invalid sms data + */ + public void testProcessMsg5() { + byte[] pdu = createPDU(2); + int headerLen = pdu.length - + (mGsmHeader.length + mUserDataHeader.length + mMessageBody.length); + int pduType = 6; + int tranId = 0; + String originalPackageName = mPackageName; + String originalClassName = mClassName; + + try { + + mClassName = "com.android.smspush.unitTests.ReceiverActivity"; + + // set up data + IWapPushManager iwapman = getInterface(); + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_ACTIVITY, false, false); + + assertTrue((iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)) + & WapPushManagerParams.MESSAGE_HANDLED) == + WapPushManagerParams.MESSAGE_HANDLED); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + } catch (RemoteException e) { + assertTrue(false); + } + + mPackageName = originalPackageName; + mClassName = originalClassName; + } + + /** + * Message processing test, no receiver application + */ + public void testProcessMsg6() { + byte[] pdu = createPDU(1); + int headerLen = pdu.length - + (mGsmHeader.length + mUserDataHeader.length + mMessageBody.length); + int pduType = 6; + int tranId = 0; + String originalPackageName = mPackageName; + String originalClassName = mClassName; + + try { + + mClassName = "com.android.smspush.unitTests.NoReceiver"; + + // set up data + IWapPushManager iwapman = getInterface(); + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_ACTIVITY, false, false); + + assertFalse((iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)) + & WapPushManagerParams.MESSAGE_HANDLED) == + WapPushManagerParams.MESSAGE_HANDLED); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + // set up data + iwapman.addPackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, false, false); + + assertFalse((iwapman.processMessage( + Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + createIntent(pduType, tranId)) + & WapPushManagerParams.MESSAGE_HANDLED) == + WapPushManagerParams.MESSAGE_HANDLED); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + + } catch (RemoteException e) { + assertTrue(false); + } + + mPackageName = originalPackageName; + mClassName = originalClassName; + } + + /** + * WspTypeDecoder test, normal pdu + */ + public void testDecoder1() { + boolean res; + int originalAppIdValue = mAppIdValue; + Random rd = new Random(); + + for (int i = 0; i < 10; i++) { + mAppIdValue = rd.nextInt(0xFFFF); + byte[] pdu = createPDU(1); + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + res = pduDecoder.seekXWapApplicationId(mWspHeaderStart, + mWspHeaderStart + mWspHeaderLen - 1); + assertTrue(res); + + int index = (int) pduDecoder.getValue32(); + res = pduDecoder.decodeXWapApplicationId(index); + assertTrue(res); + + Log.d(LOG_TAG, "mAppIdValue: " + mAppIdValue + + ", val: " + pduDecoder.getValue32()); + assertTrue(mAppIdValue == (int) pduDecoder.getValue32()); + } + + mAppIdValue = originalAppIdValue; + } + + /** + * WspTypeDecoder test, no header + */ + public void testDecoder2() { + boolean res; + int originalAppIdValue = mAppIdValue; + Random rd = new Random(); + + mAppIdValue = rd.nextInt(0xFFFF); + byte[] pdu = createPDU(2); + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + res = pduDecoder.seekXWapApplicationId(mWspHeaderStart, + mWspHeaderStart + mWspHeaderLen - 1); + assertFalse(res); + + mAppIdValue = originalAppIdValue; + } + + /** + * WspTypeDecoder test, decode appid test + */ + public void testDecoder3() { + boolean res; + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + Random rd = new Random(); + + for (int i = 0; i < 100; i++) { + mAppIdValue = rd.nextInt(0x0FFFFFFF); + mContentTypeValue = rd.nextInt(0x0FFF); + byte[] pdu = createPDU(3); + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + res = pduDecoder.seekXWapApplicationId(mWspHeaderStart, + mWspHeaderStart + mWspHeaderLen - 1); + assertTrue(res); + + int index = (int) pduDecoder.getValue32(); + res = pduDecoder.decodeXWapApplicationId(index); + assertTrue(res); + + Log.d(LOG_TAG, "mAppIdValue: " + mAppIdValue + + ", val: " + pduDecoder.getValue32()); + assertTrue(mAppIdValue == (int) pduDecoder.getValue32()); + } + + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + } + + /* + public void testEnc() { + byte[] arr = new byte[20]; + int index = 0; + index += encodeUint32(0x87a5, arr, index); + index += encodeUint32(0x1, arr, index); + index += encodeUint32(0x9b, arr, index); + index += encodeUint32(0x10, arr, index); + index += encodeUint32(0xe0887, arr, index); + index += encodeUint32(0x791a23d0, arr, index); + + Log.d(LOG_TAG, HexDump.dumpHexString(arr)); + } + */ + + /** + * WspTypeDecoder test, no appid test + */ + public void testDecoder4() { + boolean res; + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + Random rd = new Random(); + + for (int i = 0; i < 100; i++) { + mAppIdValue = rd.nextInt(0x0FFFFFFF); + mContentTypeValue = rd.nextInt(0x0FFF); + byte[] pdu = createPDU(4); + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + res = pduDecoder.seekXWapApplicationId(mWspHeaderStart, + mWspHeaderStart + mWspHeaderLen - 1); + assertFalse(res); + + } + + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + } + + /** + * WspTypeDecoder test, decode string appid test + */ + public void testDecoder5() { + boolean res; + String originalAppIdName = mAppIdName; + int originalContentTypeValue = mContentTypeValue; + Random rd = new Random(); + + for (int i = 0; i < 10; i++) { + mAppIdValue = rd.nextInt(0x0FFFFFFF); + mContentTypeValue = rd.nextInt(0x0FFF); + byte[] pdu = createPDU(5); + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + res = pduDecoder.seekXWapApplicationId(mWspHeaderStart, + mWspHeaderStart + mWspHeaderLen - 1); + assertTrue(res); + + int index = (int) pduDecoder.getValue32(); + res = pduDecoder.decodeXWapApplicationId(index); + assertTrue(res); + + Log.d(LOG_TAG, "mAppIdValue: [" + mAppIdName + "], val: [" + + pduDecoder.getValueString() + "]"); + assertTrue(mAppIdName.equals(pduDecoder.getValueString())); + } + + mAppIdName = originalAppIdName; + mContentTypeValue = originalContentTypeValue; + } + + /** + * WspTypeDecoder test, decode string appid test + */ + public void testDecoder6() { + boolean res; + String originalAppIdName = mAppIdName; + int originalContentTypeValue = mContentTypeValue; + Random rd = new Random(); + + for (int i = 0; i < OMA_APPLICATION_ID_NAMES.length; i++) { + mAppIdName = OMA_APPLICATION_ID_NAMES[i]; + mContentTypeValue = rd.nextInt(0x0FFF); + byte[] pdu = createPDU(6); + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + res = pduDecoder.seekXWapApplicationId(mWspHeaderStart, + mWspHeaderStart + mWspHeaderLen - 1); + assertTrue(res); + + int index = (int) pduDecoder.getValue32(); + res = pduDecoder.decodeXWapApplicationId(index); + assertTrue(res); + + Log.d(LOG_TAG, "mAppIdValue: [" + mAppIdName + "], val: [" + + pduDecoder.getValueString() + "]"); + assertTrue(mAppIdName.equals(pduDecoder.getValueString())); + } + + mAppIdName = originalAppIdName; + mContentTypeValue = originalContentTypeValue; + } + + /** + * WspTypeDecoder test, decode OMA content type + */ + public void testDecoder7() { + boolean res; + String originalAppIdName = mAppIdName; + int originalContentTypeValue = mContentTypeValue; + Random rd = new Random(); + + for (int i = 0; i < OMA_CONTENT_TYPE_NAMES.length; i++) { + mContentTypeName = OMA_CONTENT_TYPE_NAMES[i]; + byte[] pdu = createPDU(7); + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + res = pduDecoder.decodeContentType(mWspContentTypeStart); + assertTrue(res); + + Log.d(LOG_TAG, "mContentTypeName: [" + mContentTypeName + "], val: [" + + pduDecoder.getValueString() + "]"); + assertTrue(mContentTypeName.equals(pduDecoder.getValueString())); + } + + mAppIdName = originalAppIdName; + mContentTypeValue = originalContentTypeValue; + } + + + /** + * Copied from WapPushOverSms. + * The code flow is not changed from the original. + */ + public int dispatchWapPdu(byte[] pdu, IWapPushManager wapPushMan) { + + if (Config.DEBUG) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu)); + + int index = 0; + int transactionId = pdu[index++] & 0xFF; + int pduType = pdu[index++] & 0xFF; + int headerLength = 0; + + if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) && + (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) { + if (Config.DEBUG) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType); + return Intents.RESULT_SMS_HANDLED; + } + + WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu); + + /** + * Parse HeaderLen(unsigned integer). + * From wap-230-wsp-20010705-a section 8.1.2 + * The maximum size of a uintvar is 32 bits. + * So it will be encoded in no more than 5 octets. + */ + if (pduDecoder.decodeUintvarInteger(index) == false) { + if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Length error."); + return Intents.RESULT_SMS_GENERIC_ERROR; + } + headerLength = (int) pduDecoder.getValue32(); + index += pduDecoder.getDecodedDataLength(); + + int headerStartIndex = index; + + /** + * Parse Content-Type. + * From wap-230-wsp-20010705-a section 8.4.2.24 + * + * Content-type-value = Constrained-media | Content-general-form + * Content-general-form = Value-length Media-type + * Media-type = (Well-known-media | Extension-Media) *(Parameter) + * Value-length = Short-length | (Length-quote Length) + * Short-length = <Any octet 0-30> (octet <= WAP_PDU_SHORT_LENGTH_MAX) + * Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE) + * Length = Uintvar-integer + */ + if (pduDecoder.decodeContentType(index) == false) { + if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Content-Type error."); + return Intents.RESULT_SMS_GENERIC_ERROR; + } + + String mimeType = pduDecoder.getValueString(); + long binaryContentType = pduDecoder.getValue32(); + index += pduDecoder.getDecodedDataLength(); + + byte[] header = new byte[headerLength]; + System.arraycopy(pdu, headerStartIndex, header, 0, header.length); + + byte[] intentData; + + if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) { + intentData = pdu; + } else { + int dataIndex = headerStartIndex + headerLength; + intentData = new byte[pdu.length - dataIndex]; + System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length); + } + + /** + * Seek for application ID field in WSP header. + * If application ID is found, WapPushManager substitute the message + * processing. Since WapPushManager is optional module, if WapPushManager + * is not found, legacy message processing will be continued. + */ + if (pduDecoder.seekXWapApplicationId(index, index + headerLength - 1)) { + index = (int) pduDecoder.getValue32(); + pduDecoder.decodeXWapApplicationId(index); + String wapAppId = pduDecoder.getValueString(); + if (wapAppId == null) { + wapAppId = Integer.toString((int) pduDecoder.getValue32()); + } + + String contentType = ((mimeType == null) ? + Long.toString(binaryContentType) : mimeType); + if (Config.DEBUG) Log.v(LOG_TAG, "appid found: " + wapAppId + ":" + contentType); + + try { + boolean processFurther = true; + // IWapPushManager wapPushMan = mWapConn.getWapPushManager(); + if (wapPushMan == null) { + if (Config.DEBUG) Log.w(LOG_TAG, "wap push manager not found!"); + } else { + Intent intent = new Intent(); + intent.putExtra("transactionId", transactionId); + intent.putExtra("pduType", pduType); + intent.putExtra("header", header); + intent.putExtra("data", intentData); + intent.putExtra("contentTypeParameters", + pduDecoder.getContentParameters()); + + int procRet = wapPushMan.processMessage(wapAppId, contentType, intent); + if (Config.DEBUG) Log.v(LOG_TAG, "procRet:" + procRet); + if ((procRet & WapPushManagerParams.MESSAGE_HANDLED) > 0 + && (procRet & WapPushManagerParams.FURTHER_PROCESSING) == 0) { + processFurther = false; + } + } + if (!processFurther) { + return Intents.RESULT_SMS_HANDLED; + } + } catch (RemoteException e) { + if (Config.DEBUG) Log.w(LOG_TAG, "remote func failed..."); + } + } + if (Config.DEBUG) Log.v(LOG_TAG, "fall back to existing handler"); + + return Activity.RESULT_OK; + } + + protected byte[] retrieveWspBody() { + byte[] array = new byte[mWspHeader.length + mMessageBody.length]; + + System.arraycopy(mWspHeader, 0, array, 0, mWspHeader.length); + System.arraycopy(mMessageBody, 0, array, mWspHeader.length, mMessageBody.length); + return array; + } + + protected String getContentTypeName(int ctypeVal) { + int i; + + for (i = 0; i < OMA_CONTENT_TYPE_VALUES.length; i++) { + if (ctypeVal == OMA_CONTENT_TYPE_VALUES[i]) { + return OMA_CONTENT_TYPE_NAMES[i]; + } + } + return null; + } + + protected boolean isContentTypeMapped(int ctypeVal) { + int i; + + for (i = 0; i < OMA_CONTENT_TYPE_VALUES.length; i++) { + if (ctypeVal == OMA_CONTENT_TYPE_VALUES[i]) return true; + } + return false; + } + + /** + * Integration test 1, simple case + */ + public void testIntegration1() { + boolean res; + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + String originalAppIdName = mAppIdName; + String originalContentTypeName = mContentTypeName; + String originalClassName = mClassName; + byte[] originalMessageBody = mMessageBody; + Random rd = new Random(); + + mMessageBody = new byte[100 + rd.nextInt(100)]; + rd.nextBytes(mMessageBody); + + byte[] pdu = createPDU(1); + byte[] wappushPdu = retrieveWspBody(); + + + mClassName = "com.android.smspush.unitTests.ReceiverActivity"; + // Phone dummy = new DummyPhone(getContext()); + // Phone gsm = PhoneFactory.getGsmPhone(); + // GSMPhone gsm = new GSMPhone(getContext(), new SimulatedCommands(), null, true); + // WapPushOverSms dispatcher = new WapPushOverSms(dummy, null); + + try { + // set up data + IWapPushManager iwapman = getInterface(); + IDataVerify dataverify = getVerifyInterface(); + + dataverify.resetData(); + + if (isContentTypeMapped(mContentTypeValue)) { + // content type is mapped + mContentTypeName = getContentTypeName(mContentTypeValue); + Log.d(LOG_TAG, "mContentTypeValue mapping " + + mContentTypeName + ":" + mContentTypeValue); + } else { + mContentTypeName = Integer.toString(mContentTypeValue); + } + iwapman.addPackage(Integer.toString(mAppIdValue), + mContentTypeName, mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_ACTIVITY, false, false); + + dispatchWapPdu(wappushPdu, iwapman); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + mContentTypeName, mPackageName, mClassName); + + assertTrue(dataverify.verifyData(mMessageBody)); + } catch (RemoteException e) { + } + + + mClassName = originalClassName; + mAppIdName = originalAppIdName; + mContentTypeName = originalContentTypeName; + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + mMessageBody = originalMessageBody; + } + + /** + * Integration test 2, random mAppIdValue(int), all OMA content type + */ + public void testIntegration2() { + boolean res; + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + String originalAppIdName = mAppIdName; + String originalContentTypeName = mContentTypeName; + String originalClassName = mClassName; + byte[] originalMessageBody = mMessageBody; + Random rd = new Random(); + + IWapPushManager iwapman = getInterface(); + IDataVerify dataverify = getVerifyInterface(); + mClassName = "com.android.smspush.unitTests.ReceiverActivity"; + + for (int i = 0; i < OMA_CONTENT_TYPE_NAMES.length; i++) { + mContentTypeName = OMA_CONTENT_TYPE_NAMES[i]; + mAppIdValue = rd.nextInt(0x0FFFFFFF); + + mMessageBody = new byte[100 + rd.nextInt(100)]; + rd.nextBytes(mMessageBody); + + byte[] pdu = createPDU(7); + byte[] wappushPdu = retrieveWspBody(); + + try { + dataverify.resetData(); + // set up data + iwapman.addPackage(Integer.toString(mAppIdValue), + mContentTypeName, mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_ACTIVITY, false, false); + + dispatchWapPdu(wappushPdu, iwapman); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + mContentTypeName, mPackageName, mClassName); + + if (mContentTypeName.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) { + assertTrue(dataverify.verifyData(wappushPdu)); + } else { + assertTrue(dataverify.verifyData(mMessageBody)); + } + } catch (RemoteException e) { + } + } + + + mClassName = originalClassName; + mAppIdName = originalAppIdName; + mContentTypeName = originalContentTypeName; + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + mMessageBody = originalMessageBody; + } + + /** + * Integration test 3, iterate OmaApplication ID, random binary content type + */ + public void testIntegration3() { + boolean res; + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + String originalAppIdName = mAppIdName; + String originalContentTypeName = mContentTypeName; + String originalClassName = mClassName; + byte[] originalMessageBody = mMessageBody; + Random rd = new Random(); + + IWapPushManager iwapman = getInterface(); + IDataVerify dataverify = getVerifyInterface(); + mClassName = "com.android.smspush.unitTests.ReceiverService"; + + for (int i = 0; i < OMA_APPLICATION_ID_NAMES.length; i++) { + mAppIdName = OMA_APPLICATION_ID_NAMES[i]; + mContentTypeValue = rd.nextInt(0x0FFF); + + mMessageBody = new byte[100 + rd.nextInt(100)]; + rd.nextBytes(mMessageBody); + + byte[] pdu = createPDU(6); + byte[] wappushPdu = retrieveWspBody(); + + try { + dataverify.resetData(); + // set up data + if (isContentTypeMapped(mContentTypeValue)) { + // content type is mapped to integer value + mContentTypeName = getContentTypeName(mContentTypeValue); + Log.d(LOG_TAG, "mContentTypeValue mapping " + + mContentTypeValue + ":" + mContentTypeName); + } else { + mContentTypeName = Integer.toString(mContentTypeValue); + } + + iwapman.addPackage(mAppIdName, + mContentTypeName, mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, false, false); + + dispatchWapPdu(wappushPdu, iwapman); + + // clean up data + iwapman.deletePackage(mAppIdName, + mContentTypeName, mPackageName, mClassName); + + if (mContentTypeName.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) { + assertTrue(dataverify.verifyData(wappushPdu)); + } else { + assertTrue(dataverify.verifyData(mMessageBody)); + } + } catch (RemoteException e) { + } + } + + mClassName = originalClassName; + mAppIdName = originalAppIdName; + mContentTypeName = originalContentTypeName; + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + mMessageBody = originalMessageBody; + } + + /** + * Integration test 4, iterate OmaApplication ID, Oma content type + */ + public void testIntegration4() { + boolean res; + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + String originalAppIdName = mAppIdName; + String originalContentTypeName = mContentTypeName; + String originalClassName = mClassName; + byte[] originalMessageBody = mMessageBody; + Random rd = new Random(); + + IWapPushManager iwapman = getInterface(); + IDataVerify dataverify = getVerifyInterface(); + mClassName = "com.android.smspush.unitTests.ReceiverService"; + + for (int i = 0; i < OMA_APPLICATION_ID_NAMES.length + + OMA_CONTENT_TYPE_NAMES.length; i++) { + mAppIdName = OMA_APPLICATION_ID_NAMES[rd.nextInt(OMA_APPLICATION_ID_NAMES.length)]; + int contIndex = rd.nextInt(OMA_CONTENT_TYPE_NAMES.length); + mContentTypeName = OMA_CONTENT_TYPE_NAMES[contIndex]; + + mMessageBody = new byte[100 + rd.nextInt(100)]; + rd.nextBytes(mMessageBody); + + byte[] pdu = createPDU(8); + byte[] wappushPdu = retrieveWspBody(); + + try { + dataverify.resetData(); + // set up data + iwapman.addPackage(mAppIdName, + mContentTypeName, mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, false, false); + + dispatchWapPdu(wappushPdu, iwapman); + + // clean up data + iwapman.deletePackage(mAppIdName, + mContentTypeName, mPackageName, mClassName); + + if (mContentTypeName.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) { + assertTrue(dataverify.verifyData(wappushPdu)); + } else { + assertTrue(dataverify.verifyData(mMessageBody)); + } + } catch (RemoteException e) { + } + } + + mClassName = originalClassName; + mAppIdName = originalAppIdName; + mContentTypeName = originalContentTypeName; + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + mMessageBody = originalMessageBody; + } + + /** + * Integration test 5, iterate binary OmaApplication ID, Oma binary content type + */ + public void testIntegration5() { + boolean res; + int originalAppIdValue = mAppIdValue; + int originalContentTypeValue = mContentTypeValue; + String originalAppIdName = mAppIdName; + String originalContentTypeName = mContentTypeName; + String originalClassName = mClassName; + byte[] originalMessageBody = mMessageBody; + Random rd = new Random(); + + IWapPushManager iwapman = getInterface(); + IDataVerify dataverify = getVerifyInterface(); + mClassName = "com.android.smspush.unitTests.ReceiverService"; + + for (int i = 0; i < OMA_APPLICATION_ID_VALUES.length + + OMA_CONTENT_TYPE_VALUES.length; i++) { + mAppIdValue = OMA_APPLICATION_ID_VALUES[rd.nextInt( + OMA_APPLICATION_ID_VALUES.length)]; + mContentTypeValue = + OMA_CONTENT_TYPE_VALUES[rd.nextInt(OMA_CONTENT_TYPE_VALUES.length)]; + + mMessageBody = new byte[100 + rd.nextInt(100)]; + rd.nextBytes(mMessageBody); + + byte[] pdu = createPDU(3); + byte[] wappushPdu = retrieveWspBody(); + + try { + dataverify.resetData(); + // set up data + if (isContentTypeMapped(mContentTypeValue)) { + // content type is mapped to integer value + mContentTypeName = getContentTypeName(mContentTypeValue); + Log.d(LOG_TAG, "mContentTypeValue mapping " + + mContentTypeValue + ":" + mContentTypeName); + } else { + mContentTypeName = Integer.toString(mContentTypeValue); + } + + iwapman.addPackage(Integer.toString(mAppIdValue), + mContentTypeName, mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, false, false); + + dispatchWapPdu(wappushPdu, iwapman); + + // clean up data + iwapman.deletePackage(Integer.toString(mAppIdValue), + mContentTypeName, mPackageName, mClassName); + + if (mContentTypeName.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) { + assertTrue(dataverify.verifyData(wappushPdu)); + } else { + assertTrue(dataverify.verifyData(mMessageBody)); + } + } catch (RemoteException e) { + } + } + + mClassName = originalClassName; + mAppIdName = originalAppIdName; + mContentTypeName = originalContentTypeName; + mAppIdValue = originalAppIdValue; + mContentTypeValue = originalContentTypeValue; + mMessageBody = originalMessageBody; + } + +} diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp index a75e41d..6d4ad9a 100755 --- a/services/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp @@ -217,82 +217,10 @@ AGpsRilCallbacks sAGpsRilCallbacks = { create_thread_callback, }; -static const GpsInterface* get_gps_interface() { +static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { int err; hw_module_t* module; - const GpsInterface* interface = NULL; - - err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); - if (err == 0) { - hw_device_t* device; - err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); - if (err == 0) { - gps_device_t* gps_device = (gps_device_t *)device; - interface = gps_device->get_gps_interface(gps_device); - } - } - - return interface; -} - -static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj) { - // this must be set before calling into the HAL library - if (!mCallbacksObj) - mCallbacksObj = env->NewGlobalRef(obj); - - if (!sGpsInterface) { - sGpsInterface = get_gps_interface(); - if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) { - sGpsInterface = NULL; - return NULL; - } - } - return sGpsInterface; -} - -static const AGpsInterface* GetAGpsInterface(JNIEnv* env, jobject obj) -{ - const GpsInterface* interface = GetGpsInterface(env, obj); - if (!interface) - return NULL; - - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)interface->get_extension(AGPS_INTERFACE); - if (sAGpsInterface) - sAGpsInterface->init(&sAGpsCallbacks); - } - return sAGpsInterface; -} - -static const GpsNiInterface* GetNiInterface(JNIEnv* env, jobject obj) -{ - const GpsInterface* interface = GetGpsInterface(env, obj); - if (!interface) - return NULL; - - if (!sGpsNiInterface) { - sGpsNiInterface = (const GpsNiInterface*)interface->get_extension(GPS_NI_INTERFACE); - if (sGpsNiInterface) - sGpsNiInterface->init(&sGpsNiCallbacks); - } - return sGpsNiInterface; -} - -static const AGpsRilInterface* GetAGpsRilInterface(JNIEnv* env, jobject obj) -{ - const GpsInterface* interface = GetGpsInterface(env, obj); - if (!interface) - return NULL; - - if (!sAGpsRilInterface) { - sAGpsRilInterface = (const AGpsRilInterface*)interface->get_extension(AGPS_RIL_INTERFACE); - if (sAGpsRilInterface) - sAGpsRilInterface->init(&sAGpsRilCallbacks); - } - return sAGpsRilInterface; -} -static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); @@ -300,40 +228,73 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); - method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); + method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", + "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V"); method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V"); + + err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + if (err == 0) { + hw_device_t* device; + err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); + if (err == 0) { + gps_device_t* gps_device = (gps_device_t *)device; + sGpsInterface = gps_device->get_gps_interface(gps_device); + } + } + if (sGpsInterface) { + sGpsXtraInterface = + (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE); + sAGpsInterface = + (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); + sGpsNiInterface = + (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE); + sGpsDebugInterface = + (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE); + sAGpsRilInterface = + (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE); + } } static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) { - return (sGpsInterface != NULL || get_gps_interface() != NULL); + return (sGpsInterface != NULL); } static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (!interface) + // this must be set before calling into the HAL library + if (!mCallbacksObj) + mCallbacksObj = env->NewGlobalRef(obj); + + // fail if the main interface fails to initialize + if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) return false; - if (!sGpsDebugInterface) - sGpsDebugInterface = (const GpsDebugInterface*)interface->get_extension(GPS_DEBUG_INTERFACE); + // if XTRA initialization fails we will disable it by sGpsXtraInterface to null, + // but continue to allow the rest of the GPS interface to work. + if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0) + sGpsXtraInterface = NULL; + if (sAGpsInterface) + sAGpsInterface->init(&sAGpsCallbacks); + if (sGpsNiInterface) + sGpsNiInterface->init(&sGpsNiCallbacks); + if (sAGpsRilInterface) + sAGpsRilInterface->init(&sAGpsRilCallbacks); return true; } static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (interface) - interface->cleanup(); + if (sGpsInterface) + sGpsInterface->cleanup(); } static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (interface) - return (interface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy, + if (sGpsInterface) + return (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy, preferred_time) == 0); else return false; @@ -341,27 +302,24 @@ static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* e static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (interface) - return (interface->start() == 0); + if (sGpsInterface) + return (sGpsInterface->start() == 0); else return false; } static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (interface) - return (interface->stop() == 0); + if (sGpsInterface) + return (sGpsInterface->stop() == 0); else return false; } static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (interface) - interface->delete_aiding_data(flags); + if (sGpsInterface) + sGpsInterface->delete_aiding_data(flags); } static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj, @@ -399,8 +357,8 @@ static void android_location_GpsLocationProvider_agps_set_reference_location_cel jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid) { AGpsRefLocation location; - const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); - if (!interface) { + + if (!sAGpsRilInterface) { LOGE("no AGPS RIL interface in agps_set_reference_location_cellid"); return; } @@ -419,15 +377,15 @@ static void android_location_GpsLocationProvider_agps_set_reference_location_cel return; break; } - interface->set_ref_location(&location, sizeof(location)); + sAGpsRilInterface->set_ref_location(&location, sizeof(location)); } static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env, jobject obj, jbyteArray ni_msg, jint size) { size_t sz; - const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); - if (!interface) { + + if (!sAGpsRilInterface) { LOGE("no AGPS RIL interface in send_ni_message"); return; } @@ -435,21 +393,20 @@ static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* en return; sz = (size_t)size; jbyte* b = env->GetByteArrayElements(ni_msg, 0); - interface->ni_message((uint8_t *)b,sz); + sAGpsRilInterface->ni_message((uint8_t *)b,sz); env->ReleaseByteArrayElements(ni_msg,b,0); } static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, jobject obj, jint type, jstring setid_string) { - const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); - if (!interface) { + if (!sAGpsRilInterface) { LOGE("no AGPS RIL interface in agps_set_id"); return; } const char *setid = env->GetStringUTFChars(setid_string, NULL); - interface->set_set_id(type, setid); + sAGpsRilInterface->set_set_id(type, setid); env->ReleaseStringUTFChars(setid_string, setid); } @@ -469,40 +426,30 @@ static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time, jlong timeReference, jint uncertainty) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (interface) - interface->inject_time(time, timeReference, uncertainty); + if (sGpsInterface) + sGpsInterface->inject_time(time, timeReference, uncertainty); } static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj, jdouble latitude, jdouble longitude, jfloat accuracy) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (interface) - interface->inject_location(latitude, longitude, accuracy); + if (sGpsInterface) + sGpsInterface->inject_location(latitude, longitude, accuracy); } static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj) { - if (!sGpsXtraInterface) { - const GpsInterface* interface = GetGpsInterface(env, obj); - if (!interface) - return false; - sGpsXtraInterface = (const GpsXtraInterface*)interface->get_extension(GPS_XTRA_INTERFACE); - if (sGpsXtraInterface) { - int result = sGpsXtraInterface->init(&sGpsXtraCallbacks); - if (result) { - sGpsXtraInterface = NULL; - } - } - } - return (sGpsXtraInterface != NULL); } static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj, jbyteArray data, jint length) { + if (!sGpsXtraInterface) { + LOGE("no XTRA interface in inject_xtra_data"); + return; + } + jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0); sGpsXtraInterface->inject_xtra_data((char *)bytes, length); env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT); @@ -510,8 +457,7 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) { - const AGpsInterface* interface = GetAGpsInterface(env, obj); - if (!interface) { + if (!sAGpsInterface) { LOGE("no AGPS interface in agps_data_conn_open"); return; } @@ -520,53 +466,49 @@ static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env return; } const char *apnStr = env->GetStringUTFChars(apn, NULL); - interface->data_conn_open(apnStr); + sAGpsInterface->data_conn_open(apnStr); env->ReleaseStringUTFChars(apn, apnStr); } static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) { - const AGpsInterface* interface = GetAGpsInterface(env, obj); - if (!interface) { + if (!sAGpsInterface) { LOGE("no AGPS interface in agps_data_conn_open"); return; } - interface->data_conn_closed(); + sAGpsInterface->data_conn_closed(); } static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) { - const AGpsInterface* interface = GetAGpsInterface(env, obj); - if (!interface) { + if (!sAGpsInterface) { LOGE("no AGPS interface in agps_data_conn_open"); return; } - interface->data_conn_failed(); + sAGpsInterface->data_conn_failed(); } static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, jint type, jstring hostname, jint port) { - const AGpsInterface* interface = GetAGpsInterface(env, obj); - if (!interface) { + if (!sAGpsInterface) { LOGE("no AGPS interface in agps_data_conn_open"); return; } const char *c_hostname = env->GetStringUTFChars(hostname, NULL); - interface->set_server(type, c_hostname, port); + sAGpsInterface->set_server(type, c_hostname, port); env->ReleaseStringUTFChars(hostname, c_hostname); } static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj, jint notifId, jint response) { - const GpsNiInterface* interface = GetNiInterface(env, obj); - if (!interface) { + if (!sGpsNiInterface) { LOGE("no NI interface in send_ni_response"); return; } - interface->respond(notifId, response); + sGpsNiInterface->respond(notifId, response); } static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj) @@ -586,14 +528,14 @@ static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* e static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj, jboolean connected, int type, jboolean roaming, jstring extraInfo) { - const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); - if (interface && interface->update_network_state) { + + if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) { if (extraInfo) { const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL); - interface->update_network_state(connected, type, roaming, extraInfoStr); + sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr); env->ReleaseStringUTFChars(extraInfo, extraInfoStr); } else { - interface->update_network_state(connected, type, roaming, NULL); + sAGpsRilInterface->update_network_state(connected, type, roaming, NULL); } } } diff --git a/telephony/java/com/android/internal/telephony/IWapPushManager.aidl b/telephony/java/com/android/internal/telephony/IWapPushManager.aidl new file mode 100644 index 0000000..d5ecb94 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IWapPushManager.aidl @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.content.Intent; + +interface IWapPushManager { + /** + * Processes WAP push message and triggers the receiver application registered + * in the application ID table. + */ + int processMessage(String app_id, String content_type, in Intent intent); + + /** + * Add receiver application into the application ID table. + * Returns true if inserting the information is successfull. Inserting the duplicated + * record in the application ID table is not allowed. Use update/delete method. + */ + boolean addPackage(String x_app_id, String content_type, + String package_name, String class_name, + int app_type, boolean need_signature, boolean further_processing); + + /** + * Updates receiver application that is last added. + * Returns true if updating the information is successfull. + */ + boolean updatePackage(String x_app_id, String content_type, + String package_name, String class_name, + int app_type, boolean need_signature, boolean further_processing); + + /** + * Delites receiver application information. + * Returns true if deleting is successfull. + */ + boolean deletePackage(String x_app_id, String content_type, + String package_name, String class_name); +} + diff --git a/telephony/java/com/android/internal/telephony/WapPushManagerParams.java b/telephony/java/com/android/internal/telephony/WapPushManagerParams.java new file mode 100644 index 0000000..11e5ff9 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/WapPushManagerParams.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +/** + * WapPushManager constant value definitions + */ +public class WapPushManagerParams { + /** + * Application type activity + */ + public static final int APP_TYPE_ACTIVITY = 0; + + /** + * Application type service + */ + public static final int APP_TYPE_SERVICE = 1; + + /** + * Process Message return value + * Message is handled + */ + public static final int MESSAGE_HANDLED = 0x1; + + /** + * Process Message return value + * Application ID or content type was not found in the application ID table + */ + public static final int APP_QUERY_FAILED = 0x2; + + /** + * Process Message return value + * Receiver application signature check failed + */ + public static final int SIGNATURE_NO_MATCH = 0x4; + + /** + * Process Message return value + * Receiver application was not found + */ + public static final int INVALID_RECEIVER_NAME = 0x8; + + /** + * Process Message return value + * Unknown exception + */ + public static final int EXCEPTION_CAUGHT = 0x10; + + /** + * Process Message return value + * Need further processing after WapPushManager message processing + */ + public static final int FURTHER_PROCESSING = 0x8000; + +} + diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java index 2f5d3ec..7704667 100644 --- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java +++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java @@ -14,15 +14,20 @@ * limitations under the License. */ + package com.android.internal.telephony; import android.app.Activity; import android.content.Context; +import android.content.ComponentName; import android.content.Intent; +import android.content.ServiceConnection; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; import android.util.Config; import android.util.Log; +import android.os.IBinder; +import android.os.RemoteException; /** * WAP push handler class. @@ -42,11 +47,83 @@ public class WapPushOverSms { */ private final int WAKE_LOCK_TIMEOUT = 5000; + private final int BIND_RETRY_INTERVAL = 1000; + /** + * A handle to WapPushManager interface + */ + private WapPushConnection mWapConn = null; + private class WapPushConnection implements ServiceConnection { + private IWapPushManager mWapPushMan; + private Context mOwner; + + public WapPushConnection(Context ownerContext) { + mOwner = ownerContext; + } + + public void onServiceConnected(ComponentName name, IBinder service) { + mWapPushMan = IWapPushManager.Stub.asInterface(service); + if (Config.DEBUG) Log.v(LOG_TAG, "wappush manager connected to " + + mOwner.hashCode()); + } + + public void onServiceDisconnected(ComponentName name) { + mWapPushMan = null; + if (Config.DEBUG) Log.v(LOG_TAG, "wappush manager disconnected."); + // WapPushManager must be always attached. + rebindWapPushManager(); + } + + /** + * bind WapPushManager + */ + public void bindWapPushManager() { + if (mWapPushMan != null) return; + + final ServiceConnection wapPushConnection = this; + + mOwner.bindService(new Intent(IWapPushManager.class.getName()), + wapPushConnection, Context.BIND_AUTO_CREATE); + } + + /** + * rebind WapPushManager + * This method is called when WapPushManager is disconnected unexpectedly. + */ + private void rebindWapPushManager() { + if (mWapPushMan != null) return; + + final ServiceConnection wapPushConnection = this; + new Thread() { + public void run() { + while (mWapPushMan == null) { + mOwner.bindService(new Intent(IWapPushManager.class.getName()), + wapPushConnection, Context.BIND_AUTO_CREATE); + try { + Thread.sleep(BIND_RETRY_INTERVAL); + } catch (InterruptedException e) { + if (Config.DEBUG) Log.v(LOG_TAG, "sleep interrupted."); + } + } + } + }.start(); + } + + /** + * Returns interface to WapPushManager + */ + public IWapPushManager getWapPushManager() { + return mWapPushMan; + } + } + public WapPushOverSms(Phone phone, SMSDispatcher smsDispatcher) { mSmsDispatcher = smsDispatcher; mContext = phone.getContext(); + mWapConn = new WapPushConnection(mContext); + mWapConn.bindWapPushManager(); } + /** * Dispatches inbound messages that are in the WAP PDU format. See * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format. @@ -106,16 +183,15 @@ public class WapPushOverSms { } String mimeType = pduDecoder.getValueString(); - + long binaryContentType = pduDecoder.getValue32(); index += pduDecoder.getDecodedDataLength(); byte[] header = new byte[headerLength]; System.arraycopy(pdu, headerStartIndex, header, 0, header.length); byte[] intentData; - String permission; - if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) { + if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) { intentData = pdu; } else { int dataIndex = headerStartIndex + headerLength; @@ -123,6 +199,62 @@ public class WapPushOverSms { System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length); } + /** + * Seek for application ID field in WSP header. + * If application ID is found, WapPushManager substitute the message + * processing. Since WapPushManager is optional module, if WapPushManager + * is not found, legacy message processing will be continued. + */ + if (pduDecoder.seekXWapApplicationId(index, index + headerLength - 1)) { + index = (int) pduDecoder.getValue32(); + pduDecoder.decodeXWapApplicationId(index); + String wapAppId = pduDecoder.getValueString(); + if (wapAppId == null) { + wapAppId = Integer.toString((int) pduDecoder.getValue32()); + } + + String contentType = ((mimeType == null) ? + Long.toString(binaryContentType) : mimeType); + if (Config.DEBUG) Log.v(LOG_TAG, "appid found: " + wapAppId + ":" + contentType); + + try { + boolean processFurther = true; + IWapPushManager wapPushMan = mWapConn.getWapPushManager(); + + if (wapPushMan == null) { + if (Config.DEBUG) Log.w(LOG_TAG, "wap push manager not found!"); + } else { + Intent intent = new Intent(); + intent.putExtra("transactionId", transactionId); + intent.putExtra("pduType", pduType); + intent.putExtra("header", header); + intent.putExtra("data", intentData); + intent.putExtra("contentTypeParameters", + pduDecoder.getContentParameters()); + + int procRet = wapPushMan.processMessage(wapAppId, contentType, intent); + if (Config.DEBUG) Log.v(LOG_TAG, "procRet:" + procRet); + if ((procRet & WapPushManagerParams.MESSAGE_HANDLED) > 0 + && (procRet & WapPushManagerParams.FURTHER_PROCESSING) == 0) { + processFurther = false; + } + } + if (!processFurther) { + return Intents.RESULT_SMS_HANDLED; + } + } catch (RemoteException e) { + if (Config.DEBUG) Log.w(LOG_TAG, "remote func failed..."); + } + } + if (Config.DEBUG) Log.v(LOG_TAG, "fall back to existing handler"); + + if (mimeType == null) { + if (Config.DEBUG) Log.w(LOG_TAG, "Header Content-Type error."); + return Intents.RESULT_SMS_GENERIC_ERROR; + } + + String permission; + if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_MMS)) { permission = "android.permission.RECEIVE_MMS"; } else { @@ -141,4 +273,4 @@ public class WapPushOverSms { return Activity.RESULT_OK; } -}
\ No newline at end of file +} diff --git a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java index 6bf6b13..c8dd718 100644 --- a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java +++ b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java @@ -37,6 +37,7 @@ public class WspTypeDecoder { private final static HashMap<Integer, String> WELL_KNOWN_PARAMETERS = new HashMap<Integer, String>(); + public static final int PARAMETER_ID_X_WAP_APPLICATION_ID = 0x2f; private static final int Q_VALUE = 0x00; static { @@ -603,6 +604,70 @@ public class WspTypeDecoder { } /** + * Seek for the "X-Wap-Application-Id" field for WSP pdu + * + * @param startIndex The starting position of seek pointer + * @param endIndex Valid seek area end point + * + * @return false when error(not a X-Wap-Application-Id) occur + * return value can be retrieved by getValue32() + */ + public boolean seekXWapApplicationId(int startIndex, int endIndex) { + int index = startIndex; + + try { + for (index = startIndex; index <= endIndex; ) { + /** + * 8.4.1.1 Field name + * Field name is integer or text. + */ + if (decodeIntegerValue(index)) { + int fieldValue = (int) getValue32(); + + if (fieldValue == PARAMETER_ID_X_WAP_APPLICATION_ID) { + unsigned32bit = index + 1; + return true; + } + } else { + if (!decodeTextString(index)) return false; + } + index += getDecodedDataLength(); + if (index > endIndex) return false; + + /** + * 8.4.1.2 Field values + * Value Interpretation of First Octet + * 0 - 30 This octet is followed by the indicated number (0 - 30) + of data octets + * 31 This octet is followed by a uintvar, which indicates the number + * of data octets after it + * 32 - 127 The value is a text string, terminated by a zero octet + (NUL character) + * 128 - 255 It is an encoded 7-bit value; this header has no more data + */ + byte val = wspData[index]; + if (0 <= val && val <= WAP_PDU_SHORT_LENGTH_MAX) { + index += wspData[index] + 1; + } else if (val == WAP_PDU_LENGTH_QUOTE) { + if (index + 1 >= endIndex) return false; + index++; + if (!decodeUintvarInteger(index)) return false; + index += getDecodedDataLength(); + } else if (WAP_PDU_LENGTH_QUOTE < val && val <= 127) { + if (!decodeTextString(index)) return false; + index += getDecodedDataLength(); + } else { + index++; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + //seek application ID failed. WSP header might be corrupted + return false; + } + return false; + } + + /** * Decode the "X-Wap-Content-URI" type for WSP pdu * * @param startIndex The starting position of the "X-Wap-Content-URI" in this pdu diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index c5aa573..15570e4 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -45,7 +45,7 @@ public: mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL), mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), - mMaxResVersion(NULL), mDebugMode(false), mProduct(NULL), + mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL), mArgc(0), mArgv(NULL) {} ~Bundle(void) {} @@ -139,6 +139,8 @@ public: void setMaxResVersion(const char * val) { mMaxResVersion = val; } bool getDebugMode() { return mDebugMode; } void setDebugMode(bool val) { mDebugMode = val; } + bool getNonConstantId() { return mNonConstantId; } + void setNonConstantId(bool val) { mNonConstantId = val; } const char* getProduct() const { return mProduct; } void setProduct(const char * val) { mProduct = val; } @@ -239,6 +241,7 @@ private: const char* mCustomPackage; const char* mMaxResVersion; bool mDebugMode; + bool mNonConstantId; const char* mProduct; /* file specification */ diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index 739b01f..266a02f 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -160,7 +160,11 @@ void usage(void) " product variants\n" " --utf16\n" " changes default encoding for resources to UTF-16. Only useful when API\n" - " level is set to 7 or higher where the default encoding is UTF-8.\n"); + " level is set to 7 or higher where the default encoding is UTF-8.\n" + " --non-constant-id\n" + " Make the resources ID non constant. This is required to make an R java class\n" + " that does not contain the final value but is used to make reusable compiled\n" + " libraries that need to access resources.\n"); } /* @@ -497,6 +501,8 @@ int main(int argc, char* const argv[]) goto bail; } bundle.setProduct(argv[0]); + } else if (strcmp(cp, "-non-constant-id") == 0) { + bundle.setNonConstantId(true); } else { fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp); wantUsage = true; diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index c8ba904..0a4f24f 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -1655,7 +1655,8 @@ static status_t writeLayoutClasses( static status_t writeSymbolClass( FILE* fp, const sp<AaptAssets>& assets, bool includePrivate, - const sp<AaptSymbols>& symbols, const String8& className, int indent) + const sp<AaptSymbols>& symbols, const String8& className, int indent, + bool nonConstantId) { fprintf(fp, "%spublic %sfinal class %s {\n", getIndentSpace(indent), @@ -1665,6 +1666,10 @@ static status_t writeSymbolClass( size_t i; status_t err = NO_ERROR; + const char * id_format = nonConstantId ? + "%spublic static int %s=0x%08x;\n" : + "%spublic static final int %s=0x%08x;\n"; + size_t N = symbols->getSymbols().size(); for (i=0; i<N; i++) { const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i); @@ -1717,7 +1722,7 @@ static status_t writeSymbolClass( if (deprecated) { fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent)); } - fprintf(fp, "%spublic static final int %s=0x%08x;\n", + fprintf(fp, id_format, getIndentSpace(indent), String8(name).string(), (int)sym.int32Val); } @@ -1768,7 +1773,7 @@ static status_t writeSymbolClass( if (nclassName == "styleable") { styleableSymbols = nsymbols; } else { - err = writeSymbolClass(fp, assets, includePrivate, nsymbols, nclassName, indent); + err = writeSymbolClass(fp, assets, includePrivate, nsymbols, nclassName, indent, nonConstantId); } if (err != NO_ERROR) { return err; @@ -1839,7 +1844,7 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets, "\n" "package %s;\n\n", package.string()); - status_t err = writeSymbolClass(fp, assets, includePrivate, symbols, className, 0); + status_t err = writeSymbolClass(fp, assets, includePrivate, symbols, className, 0, bundle->getNonConstantId()); if (err != NO_ERROR) { return err; } |