Реализация функций USSD. Связывание службы с PhoneUtils без перезапуска телефона при каждом обновлении

Я пытаюсь реализовать приложение для отправки, получения и анализа USSD-кодов на Android. До сих пор я использовал код на http://commandus.com/blog/?p=58 , чтобы получить эту функциональность. Чтобы служба работала, телефон необходимо перезапустить. Это не будет проблемой при первой установке пользователем приложения, но то, что я заметил при тестировании на эмуляторе, заключается в том, что для каждого обновления потребуется перезагрузка телефона, даже если в сервисе нет ничего нового. Я хотел бы знать следующее:

  • Может ли быть причиной того, что PhoneUtils свяжется с моей службой без перезагрузки? По крайней мере, на время обновления?
  • Если нет способа сделать это, я думаю о создании 2 приложений, которые являются обычным приложением, с которым пользователь взаимодействует, и отдельной, содержащей мою службу. В этом случае пользователю будет предложено выполнить первый запуск, если он / она потребует какие-либо функции ussd, для установки второго приложения. Я волнуюсь, хотя это раздражает для пользователя. Как вы считаете, как лучше всего решить такой подход?

Для справки, я включил код, который я использовал для службы, поскольку часть интерфейса отличается от той, что была размещена на исходном веб-сайте.

Интерфейс:

* This file is auto-generated. DO NOT MODIFY. package com.android.internal.telephony; /** * Interface used to interact with extended MMI/USSD network service. */ public interface IExtendedNetworkService extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.android.internal.telephony.IExtendedNetworkService { private static final java.lang.String DESCRIPTOR = "com.android.internal.telephony.IExtendedNetworkService"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an * com.android.internal.telephony.IExtendedNetworkService interface, * generating a proxy if needed. */ public static com.android.internal.telephony.IExtendedNetworkService asInterface( android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = (android.os.IInterface) obj .queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.android.internal.telephony.IExtendedNetworkService))) { return ((com.android.internal.telephony.IExtendedNetworkService) iin); } return new com.android.internal.telephony.IExtendedNetworkService.Stub.Proxy( obj); } public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_setMmiString: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); this.setMmiString(_arg0); reply.writeNoException(); return true; } case TRANSACTION_getMmiRunningText: { data.enforceInterface(DESCRIPTOR); java.lang.CharSequence _result = this.getMmiRunningText(); reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); android.text.TextUtils .writeToParcel( _result, reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_getUserMessage: { data.enforceInterface(DESCRIPTOR); java.lang.CharSequence _arg0; if ((0 != data.readInt())) { _arg0 = android.text.TextUtils.CHAR_SEQUENCE_CREATOR .createFromParcel(data); } else { _arg0 = null; } java.lang.CharSequence _result = this.getUserMessage(_arg0); reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); android.text.TextUtils .writeToParcel( _result, reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_clearMmiString: { data.enforceInterface(DESCRIPTOR); this.clearMmiString(); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.android.internal.telephony.IExtendedNetworkService { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } /** * Set a MMI/USSD command to ExtendedNetworkService for further * process. This should be called when a MMI command is placed from * panel. * * @param number * the dialed MMI/USSD number. */ public void setMmiString(java.lang.String number) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(number); mRemote.transact(Stub.TRANSACTION_setMmiString, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } /** * return the specific string which is used to prompt MMI/USSD is * running */ public java.lang.CharSequence getMmiRunningText() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.CharSequence _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getMmiRunningText, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { _result = android.text.TextUtils.CHAR_SEQUENCE_CREATOR .createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } /** * Get specific message which should be displayed on pop-up dialog. * * @param text * original MMI/USSD message response from framework * @return specific user message correspond to text. null stands for * no pop-up dialog need to show. */ public java.lang.CharSequence getUserMessage( java.lang.CharSequence text) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.CharSequence _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((text != null)) { _data.writeInt(1); android.text.TextUtils.writeToParcel(text, _data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_getUserMessage, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { _result = android.text.TextUtils.CHAR_SEQUENCE_CREATOR .createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } /** * Clear pre-set MMI/USSD command. This should be called when user * cancel a pre-dialed MMI command. */ public void clearMmiString() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_clearMmiString, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_setMmiString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getMmiRunningText = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_getUserMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_clearMmiString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); } /** * Set a MMI/USSD command to ExtendedNetworkService for further process. * This should be called when a MMI command is placed from panel. * * @param number * the dialed MMI/USSD number. */ public void setMmiString(java.lang.String number) throws android.os.RemoteException; /** * return the specific string which is used to prompt MMI/USSD is running */ public java.lang.CharSequence getMmiRunningText() throws android.os.RemoteException; /** * Get specific message which should be displayed on pop-up dialog. * * @param text * original MMI/USSD message response from framework * @return specific user message correspond to text. null stands for no * pop-up dialog need to show. */ public java.lang.CharSequence getUserMessage(java.lang.CharSequence text) throws android.os.RemoteException; /** * Clear pre-set MMI/USSD command. This should be called when user cancel a * pre-dialed MMI command. */ public void clearMmiString() throws android.os.RemoteException; } 

Обслуживание:

 package net.g_el.mobile.mtc; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.IBinder; import android.os.PatternMatcher; import android.os.RemoteException; import android.util.Log; import com.android.internal.telephony.IExtendedNetworkService; /** * Service implements IExtendedNetworkService interface. * USSDDumbExtendedNetworkService Service must have name * "com.android.ussd.IExtendedNetworkService" of the intent declared in the * Android manifest file so com.android.phone.PhoneUtils class bind to this * service after system rebooted. Please note service is loaded after system * reboot! Your application must check is system rebooted. * * @see Util#syslogHasLine(String, String, String, boolean) */ public class USSDDumbExtendedNetworkService extends Service { public static final String TAG = "MobileServices"; public static final String LOG_STAMP = "*USSDTestExtendedNetworkService bind successfully*"; public static final String URI_SCHEME = "ussd"; public static final String URI_AUTHORITY = "g_el.net"; public static final String URI_PATH = "/"; public static final String URI_PAR = "return"; public static final String URI_PARON = "on"; public static final String URI_PAROFF = "off"; public static final String MAGIC_ON = ":ON;)"; public static final String MAGIC_OFF = ":OFF;("; public static final String MAGIC_RETVAL = ":RETVAL;("; private static boolean mActive = false; private static CharSequence mRetVal = null; private Context mContext = null; private String msgUssdRunning = "G Testing..."; final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_INSERT.equals(intent.getAction())) { mContext = context; if (mContext != null) { msgUssdRunning = mContext.getString(R.string.msgRunning); mActive = true; Log.d(TAG, "activate"); } } else if (Intent.ACTION_DELETE.equals(intent.getAction())) { mContext = null; mActive = false; Log.d(TAG, "deactivate"); } } }; private final IExtendedNetworkService.Stub mBinder = new IExtendedNetworkService.Stub() { @Override public void setMmiString(String number) throws RemoteException { Log.d(TAG, "setMmiString: " + number); } @Override public CharSequence getMmiRunningText() throws RemoteException { Log.d(TAG, "getMmiRunningText: " + msgUssdRunning); return msgUssdRunning; } @Override public CharSequence getUserMessage(CharSequence text) throws RemoteException { if (MAGIC_ON.contentEquals(text)) { mActive = true; Log.d(TAG, "control: ON"); return text; } else { if (MAGIC_OFF.contentEquals(text)) { mActive = false; Log.d(TAG, "control: OFF"); return text; } else { if (MAGIC_RETVAL.contentEquals(text)) { mActive = false; Log.d(TAG, "control: return"); return mRetVal; } } } if (!mActive) { Log.d(TAG, "getUserMessage deactivated: " + text); //return null;//Use this in order to cancel the output on the screen. return text; } String s = text.toString(); // store s to the ! Uri uri = new Uri.Builder().scheme(URI_SCHEME).authority(URI_AUTHORITY).path(URI_PATH).appendQueryParameter(URI_PAR,text.toString()).build(); sendBroadcast(new Intent(Intent.ACTION_GET_CONTENT, uri)); mActive = false; mRetVal = text; Log.d(TAG, "getUserMessage: " + text + "=" + s); return null; } @Override public void clearMmiString() throws RemoteException { Log.d(TAG, "clearMmiString"); } }; /** * Put stamp to the system log when PhoneUtils bind to the service after * Android has rebooted. Application must call * {@link Util#syslogHasLine(String, String, String, boolean)} to check is * phone rebooted or no. Without reboot phone application does not bind tom * this service! */ @Override public IBinder onBind(Intent intent) { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_INSERT); filter.addAction(Intent.ACTION_DELETE); filter.addDataScheme(URI_SCHEME); filter.addDataAuthority(URI_AUTHORITY, null); filter.addDataPath(URI_PATH, PatternMatcher.PATTERN_LITERAL); registerReceiver(mReceiver, filter); // Do not localize! Log.i(TAG, LOG_STAMP); return mBinder; } public IBinder asBinder() { Log.d(TAG, "asBinder"); return mBinder; } @Override public boolean onUnbind(Intent intent) { unregisterReceiver(mReceiver); return super.onUnbind(intent); } } 

спасибо

Пожалуйста, будьте ясны, вы полностью ушли в сорняки внутренних реализаций платформы. Похоже, вы хотите, чтобы это работало «хорошо». То, что вы делаете, не будет работать хорошо, период. У вас нет гарантии, что эти внутренние реализации будут оставаться неизменными в разных версиях платформ или даже на разных сборках платформы на устройствах-изготовителях, а также то, что поведение, которое вы видите вокруг этого интерфейса, будет работать одинаково в разных ситуациях.

Это просто плохо плохо. Не делай этого.