From acc5537160f712bacf5c92102e9aa03838429e01 Mon Sep 17 00:00:00 2001 From: Pawit Pornkitprasan Date: Tue, 18 Oct 2011 08:49:11 +0700 Subject: Add SamsungServiceMode (1/4) This is an interface to the radio's control interface. The application is accessable via *#*#197328640#*#* (or an easier to remember submenu of it is accessable via *#*#0011#*#* and use back to get to the main menu). Change-Id: Ie43f54003d9e683e25f05fa6e7f57711edef9e7f --- SamsungServiceMode/Android.mk | 14 ++ SamsungServiceMode/AndroidManifest.xml | 118 +++++++++ SamsungServiceMode/res/layout/list_item.xml | 7 + SamsungServiceMode/res/layout/main.xml | 12 + SamsungServiceMode/res/values/strings.xml | 6 + .../samsungservicemode/OemCommands.java | 110 ++++++++ .../SamsungServiceModeActivity.java | 277 +++++++++++++++++++++ .../SecretBroadcastReceiver.java | 19 ++ 8 files changed, 563 insertions(+) create mode 100644 SamsungServiceMode/Android.mk create mode 100644 SamsungServiceMode/AndroidManifest.xml create mode 100644 SamsungServiceMode/res/layout/list_item.xml create mode 100644 SamsungServiceMode/res/layout/main.xml create mode 100644 SamsungServiceMode/res/values/strings.xml create mode 100644 SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/OemCommands.java create mode 100644 SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SamsungServiceModeActivity.java create mode 100644 SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SecretBroadcastReceiver.java diff --git a/SamsungServiceMode/Android.mk b/SamsungServiceMode/Android.mk new file mode 100644 index 0000000..4437eb3 --- /dev/null +++ b/SamsungServiceMode/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_PACKAGE_NAME := SamsungServiceMode +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + +# Build the test package +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/SamsungServiceMode/AndroidManifest.xml b/SamsungServiceMode/AndroidManifest.xml new file mode 100644 index 0000000..f46af4d --- /dev/null +++ b/SamsungServiceMode/AndroidManifest.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SamsungServiceMode/res/layout/list_item.xml b/SamsungServiceMode/res/layout/list_item.xml new file mode 100644 index 0000000..4f45ed4 --- /dev/null +++ b/SamsungServiceMode/res/layout/list_item.xml @@ -0,0 +1,7 @@ + + diff --git a/SamsungServiceMode/res/layout/main.xml b/SamsungServiceMode/res/layout/main.xml new file mode 100644 index 0000000..6b8cba6 --- /dev/null +++ b/SamsungServiceMode/res/layout/main.xml @@ -0,0 +1,12 @@ + + + + diff --git a/SamsungServiceMode/res/values/strings.xml b/SamsungServiceMode/res/values/strings.xml new file mode 100644 index 0000000..d033037 --- /dev/null +++ b/SamsungServiceMode/res/values/strings.xml @@ -0,0 +1,6 @@ + + + Hello World, SamsungServiceModeActivity! + Service Mode + Send + diff --git a/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/OemCommands.java b/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/OemCommands.java new file mode 100644 index 0000000..ccc2d48 --- /dev/null +++ b/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/OemCommands.java @@ -0,0 +1,110 @@ +package com.cyanogenmod.samsungservicemode; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import android.util.Log; + +class OemCommands { + + private static final String TAG = "OemCommands"; + + public static final char OEM_SERVM_FUNCTAG = 1; + public static final char OEM_SM_ACTION = 0; + public static final char OEM_SM_QUERY = 1; + public static final char OEM_SM_DUMMY = 0; + public static final char OEM_SM_ENTER_MODE_MESSAGE = 1; + public static final char OEM_SM_END_MODE_MESSAGE = 2; + public static final char OEM_SM_PROCESS_KEY_MESSAGE = 3; + public static final char OEM_SM_GET_DISPLAY_DATA_MESSAGE = 4; + public static final char OEM_SM_TYPE_TEST_MANUAL = 1; + public static final char OEM_SM_TYPE_TEST_AUTO = 2; + public static final char OEM_SM_TYPE_NAM_EDIT = 3; + public static final char OEM_SM_TYPE_MONITOR = 4; + public static final char OEM_SM_TYPE_PHONE_TEST = 5; + public static final char OEM_SM_TYPE_SUB_ENTER = 0; + public static final char OEM_SM_TYPE_SUB_SW_VERSION_ENTER = 1; + public static final char OEM_SM_TYPE_SUB_FTA_SW_VERSION_ENTER = 2; + public static final char OEM_SM_TYPE_SUB_FTA_HW_VERSION_ENTER = 3; + public static final char OEM_SM_TYPE_SUB_ALL_VERSION_ENTER = 4; + public static final char OEM_SM_TYPE_SUB_BATTERY_INFO_ENTER = 5; + public static final char OEM_SM_TYPE_SUB_CIPHERING_PROTECTION_ENTER = 6; + public static final char OEM_SM_TYPE_SUB_INTEGRITY_PROTECTION_ENTER = 7; + public static final char OEM_SM_TYPE_SUB_IMEI_READ_ENTER = 8; + public static final char OEM_SM_TYPE_SUB_BLUETOOTH_TEST_ENTER = 9; + public static final char OEM_SM_TYPE_SUB_VIBRATOR_TEST_ENTER = 10; + public static final char OEM_SM_TYPE_SUB_MELODY_TEST_ENTER = 11; + public static final char OEM_SM_TYPE_SUB_MP3_TEST_ENTER = 12; + public static final char OEM_SM_TYPE_SUB_FACTORY_RESET_ENTER = 13; + public static final char OEM_SM_TYPE_SUB_FACTORY_PRECONFIG_ENTER = 14; + public static final char OEM_SM_TYPE_SUB_TFS4_EXPLORE_ENTER = 15; + public static final char OEM_SM_TYPE_SUB_RSC_FILE_VERSION_ENTER = 17; + public static final char OEM_SM_TYPE_SUB_USB_DRIVER_ENTER = 18; + public static final char OEM_SM_TYPE_SUB_USB_UART_DIAG_CONTROL_ENTER = 19; + public static final char OEM_SM_TYPE_SUB_RRC_VERSION_ENTER = 20; + public static final char OEM_SM_TYPE_SUB_GPSONE_SS_TEST_ENTER = 21; + public static final char OEM_SM_TYPE_SUB_BAND_SEL_ENTER = 22; + public static final char OEM_SM_TYPE_SUB_GCF_TESTMODE_ENTER = 23; + public static final char OEM_SM_TYPE_SUB_GSM_FACTORY_AUDIO_LB_ENTER = 24; + public static final char OEM_SM_TYPE_SUB_FACTORY_VF_TEST_ENTER = 25; + public static final char OEM_SM_TYPE_SUB_TOTAL_CALL_TIME_INFO_ENTER = 26; + public static final char OEM_SM_TYPE_SUB_SELLOUT_SMS_ENABLE_ENTER = 27; + public static final char OEM_SM_TYPE_SUB_SELLOUT_SMS_DISABLE_ENTER = 28; + public static final char OEM_SM_TYPE_SUB_SELLOUT_SMS_TEST_MODE_ON = 29; + public static final char OEM_SM_TYPE_SUB_SELLOUT_SMS_PRODUCT_MODE_ON = 30; + public static final char OEM_SM_TYPE_SUB_GET_SELLOUT_SMS_INFO_ENTER = 31; + public static final char OEM_SM_TYPE_SUB_TST_AUTO_ANSWER_ENTER = 32; + public static final char OEM_SM_TYPE_SUB_TST_NV_RESET_ENTER = 33; + public static final char OEM_SM_TYPE_SUB_TST_FTA_SW_VERSION_ENTER = 4098; + public static final char OEM_SM_TYPE_SUB_TST_FTA_HW_VERSION_ENTER = 4099; + + public static byte[] getEnterServiceModeData(int modeType, int subType, int query) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeByte(OEM_SERVM_FUNCTAG); + dos.writeByte(OEM_SM_ENTER_MODE_MESSAGE); + dos.writeShort(7); + dos.writeByte(modeType); + dos.writeByte(subType); + dos.writeByte(query); + return baos.toByteArray(); + } catch (IOException e) { + Log.e(TAG, "", e); + } + return null; + } + + public static byte[] getEndServiceModeData(int modeType) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeByte(OEM_SERVM_FUNCTAG); + dos.writeByte(OEM_SM_END_MODE_MESSAGE); + dos.writeShort(5); + dos.writeByte(modeType); + return baos.toByteArray(); + } catch (IOException e) { + Log.e(TAG, "", e); + } + return null; + } + + public static byte[] getPressKeyData(int keycode, int query) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeByte(OEM_SERVM_FUNCTAG); + dos.writeByte(OEM_SM_PROCESS_KEY_MESSAGE); + dos.writeShort(6); + dos.writeByte(keycode); + dos.writeByte(query); + return baos.toByteArray(); + } catch (IOException e) { + Log.e(TAG, "", e); + } + return null; + } + +} \ No newline at end of file diff --git a/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SamsungServiceModeActivity.java b/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SamsungServiceModeActivity.java new file mode 100644 index 0000000..59c0139 --- /dev/null +++ b/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SamsungServiceModeActivity.java @@ -0,0 +1,277 @@ +package com.cyanogenmod.samsungservicemode; + +import android.app.Activity; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; + +public class SamsungServiceModeActivity extends Activity implements AdapterView.OnItemClickListener { + + private static final String TAG = "SamsungServiceModeActivity"; + + public static final String EXTRA_SECRET_CODE = "secret_code"; + + private static final int ID_SERVICE_MODE_REFRESH = 1001; + private static final int ID_SERVICE_MODE_REQUEST = 1008; + private static final int ID_SERVICE_MODE_END = 1009; + + private static final int CHARS_PER_LINE = 34; + private static final int LINES = 11; + + private ListView mListView; + private String[] mDisplay = new String[LINES]; + + private int mCurrentSvcMode; + private int mCurrentModeType; + + // Disable back when initialized with certain commands due to crash + private boolean mAllowBack; + private boolean mFirstRun = true; + private String mFirstPageHead; + + private Phone mPhone; + private Handler mHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case ID_SERVICE_MODE_REFRESH: + Log.v(TAG, "Tick"); + byte[] data = null; + switch(mCurrentSvcMode) { + case OemCommands.OEM_SM_ENTER_MODE_MESSAGE: + data = OemCommands.getEnterServiceModeData(0, 0, OemCommands.OEM_SM_QUERY); + break; + case OemCommands.OEM_SM_PROCESS_KEY_MESSAGE: + data = OemCommands.getPressKeyData('\0', OemCommands.OEM_SM_QUERY); + break; + default: + Log.e(TAG, "Unknown mode: " + mCurrentSvcMode); + break; + } + + if (data != null) { + sendRequest(data, ID_SERVICE_MODE_REQUEST); + } + break; + case ID_SERVICE_MODE_REQUEST: + AsyncResult result = (AsyncResult)msg.obj; + if (result.exception != null) { + Log.e(TAG, "", result.exception); + return; + } + if (result.result == null) { + Log.v(TAG, "No need to refresh."); + return; + } + byte[] aob = (byte[])result.result; + + if (aob.length == 0) { + Log.v(TAG, "Length = 0"); + return; + } + + int lines = aob.length / CHARS_PER_LINE; + if (lines > LINES) { + Log.e(TAG, "Datasize " + aob.length + " larger than expected"); + return; + } + + for (int i = 0; i < lines; i++) { + StringBuilder strb = new StringBuilder(CHARS_PER_LINE); + for (int j = 2; i < CHARS_PER_LINE; j++) { + int pos = i * CHARS_PER_LINE + j; + if (pos >= aob.length) { + Log.e(TAG, "Unexpected EOF"); + break; + } + if (aob[pos] == 0) { + break; + } + strb.append((char)aob[pos]); + } + mDisplay[i] = strb.toString(); + } + + mListView.setAdapter(new ArrayAdapter( + SamsungServiceModeActivity.this, R.layout.list_item, mDisplay)); + + if (mFirstRun) { + mFirstPageHead = mDisplay[0]; + mFirstRun = false; + } + + if (mDisplay[0].contains("End service mode")) { + finish(); + } else if (((mDisplay[0].contains("[")) && (mDisplay[0].contains("]"))) + || ((mDisplay[1].contains("[")) && (mDisplay[1].contains("]")))) { + // This is a menu, don't refresh + } else if ((mDisplay[0].length() != 0) && (mDisplay[1].length() == 0) + && (mDisplay[0].charAt(1) > 48) && (mDisplay[0].charAt(1) < 58)) { + // Only numerical display, refresh + mHandler.sendEmptyMessageDelayed(ID_SERVICE_MODE_REFRESH, 200); + } else { + // Periodical refresh + mHandler.sendEmptyMessageDelayed(ID_SERVICE_MODE_REFRESH, 1500); + } + break; + case ID_SERVICE_MODE_END: + Log.v(TAG, "Service Mode End"); + break; + } + } + + }; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + mListView = (ListView)findViewById(R.id.displayList); + mListView.setOnItemClickListener(this); + + mPhone = PhoneFactory.getDefaultPhone(); + + // Go to the page specified by the code used to enter service mode + String code = getIntent().getStringExtra(EXTRA_SECRET_CODE); + + // Default to main page + int modeType = OemCommands.OEM_SM_TYPE_TEST_MANUAL; + int subType = OemCommands.OEM_SM_TYPE_SUB_ENTER; + mAllowBack = true; // Some commands don't like having "back" executed on them + + if (TextUtils.isEmpty(code) || code.equals("197328640")) { + // Use default (this exists to prevent NPE when code is null) + } + else if (code.equals("0011")) { + modeType = OemCommands.OEM_SM_TYPE_MONITOR; + subType = OemCommands.OEM_SM_TYPE_SUB_ENTER; + } else if (code.equals("0228")) { // 0BAT + subType = OemCommands.OEM_SM_TYPE_SUB_BATTERY_INFO_ENTER; + } else if (code.equals("32489")) { + subType = OemCommands.OEM_SM_TYPE_SUB_CIPHERING_PROTECTION_ENTER; + } else if (code.equals("2580")) { // ALT0 + subType = OemCommands.OEM_SM_TYPE_SUB_INTEGRITY_PROTECTION_ENTER; + } else if (code.equals("9090") || code.equals("7284")) { // PATH + subType = OemCommands.OEM_SM_TYPE_SUB_USB_UART_DIAG_CONTROL_ENTER; + mAllowBack = false; + } else if (code.equals("0599") || code.equals("301279") || code.equals("279301")) { + subType = OemCommands.OEM_SM_TYPE_SUB_RRC_VERSION_ENTER; + mAllowBack = false; + } else if (code.equals("2263")) { // BAND + subType = OemCommands.OEM_SM_TYPE_SUB_BAND_SEL_ENTER; + mAllowBack = false; + } else if (code.equals("4238378")) { // GCFTEST + subType = OemCommands.OEM_SM_TYPE_SUB_GCF_TESTMODE_ENTER; + mAllowBack = false; + } else if (code.equals("0283")) { // 0AUD + subType = OemCommands.OEM_SM_TYPE_SUB_GSM_FACTORY_AUDIO_LB_ENTER; + } else if (code.equals("1575")) { + subType = OemCommands.OEM_SM_TYPE_SUB_GPSONE_SS_TEST_ENTER; + } else if (code.equals("73876766")) { // SETSMSON + subType = OemCommands.OEM_SM_TYPE_SUB_SELLOUT_SMS_ENABLE_ENTER; + mAllowBack = false; + } else if (code.equals("738767633")) { // SETSMSOFF + subType = OemCommands.OEM_SM_TYPE_SUB_SELLOUT_SMS_DISABLE_ENTER; + mAllowBack = false; + } else if (code.equals("7387678378")) { // SETSMSTEST + subType = OemCommands.OEM_SM_TYPE_SUB_SELLOUT_SMS_TEST_MODE_ON; + mAllowBack = false; + } else if (code.equals("7387677763")) { // SETSMSPROD + subType = OemCommands.OEM_SM_TYPE_SUB_SELLOUT_SMS_PRODUCT_MODE_ON; + mAllowBack = false; + } else if (code.equals("4387264636")) { + subType = OemCommands.OEM_SM_TYPE_SUB_GET_SELLOUT_SMS_INFO_ENTER; + mAllowBack = false; + } else if (code.equals("6984125*") || code.equals("2886")) { // AUTO + // crash + subType = OemCommands.OEM_SM_TYPE_SUB_TST_AUTO_ANSWER_ENTER; + } else if (code.equals("2767*2878")) { + // crash + subType = OemCommands.OEM_SM_TYPE_SUB_TST_NV_RESET_ENTER; + } else if (code.equals("1111")) { + subType = OemCommands.OEM_SM_TYPE_SUB_TST_FTA_SW_VERSION_ENTER; + mAllowBack = false; + } else if (code.equals("2222")) { + subType = OemCommands.OEM_SM_TYPE_SUB_TST_FTA_HW_VERSION_ENTER; + mAllowBack = false; + } + + enterServiceMode(modeType, subType); + } + + @Override + public void onBackPressed() { + if (!mAllowBack && mDisplay[0].equals(mFirstPageHead)) { + Log.v(TAG, "Back disabled. Ending service mode."); + endServiceMode(); + } else { + sendChar((char) 92); + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + String str = mDisplay[position]; + int start = str.indexOf('['); + int end = str.indexOf(']'); + + if (start == -1 || end == -1) { + // This menu is not clickable + return; + } + sendChar(str.charAt(start + 1)); + } + + @Override + public void onPause() { + super.onPause(); + mHandler.removeMessages(ID_SERVICE_MODE_REFRESH); + } + + private void enterServiceMode(int modeType, int subType) { + mCurrentSvcMode = OemCommands.OEM_SM_ENTER_MODE_MESSAGE; + mCurrentModeType = modeType; + byte[] data = OemCommands.getEnterServiceModeData(modeType, subType, OemCommands.OEM_SM_ACTION); + sendRequest(data, ID_SERVICE_MODE_REQUEST); + } + + private void endServiceMode() { + mCurrentSvcMode = OemCommands.OEM_SM_END_MODE_MESSAGE; + mHandler.removeMessages(ID_SERVICE_MODE_REFRESH); + byte[] data = OemCommands.getEndServiceModeData(mCurrentModeType); + sendRequest(data, ID_SERVICE_MODE_END); + finish(); + } + + private void sendChar(char chr) { + mCurrentSvcMode = OemCommands.OEM_SM_PROCESS_KEY_MESSAGE; + mHandler.removeMessages(ID_SERVICE_MODE_REFRESH); + if (chr >= 'a' && chr <= 'f') { + chr = Character.toUpperCase(chr); + } else if (chr == '-') { + chr = '*'; + } + + byte[] data = OemCommands.getPressKeyData(chr, OemCommands.OEM_SM_ACTION); + sendRequest(data, ID_SERVICE_MODE_REQUEST); + } + + private void sendRequest(byte[] data, int id) { + Message msg = mHandler.obtainMessage(id); + mPhone.invokeOemRilRequestRaw(data, msg); + } + +} \ No newline at end of file diff --git a/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SecretBroadcastReceiver.java b/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SecretBroadcastReceiver.java new file mode 100644 index 0000000..b3366f6 --- /dev/null +++ b/SamsungServiceMode/src/com/cyanogenmod/samsungservicemode/SecretBroadcastReceiver.java @@ -0,0 +1,19 @@ +package com.cyanogenmod.samsungservicemode; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class SecretBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + String code = intent.getData().getHost(); + Intent i = new Intent(Intent.ACTION_MAIN); + i.setClass(context, SamsungServiceModeActivity.class); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + i.putExtra(SamsungServiceModeActivity.EXTRA_SECRET_CODE, code); + context.startActivity(i); + } + +} -- cgit v1.1