Implementación de funciones USSD. Vincular un servicio a PhoneUtils sin reiniciar el teléfono en cada actualización

Estoy tratando de implementar una aplicación para enviar, recibir y analizar códigos USSD en android. Hasta ahora he utilizado el código en http://commandus.com/blog/?p=58 para obtener esta funcionalidad. Para que el servicio funcione, es necesario reiniciar el teléfono. Esto no sería un problema la primera vez que el usuario instala la aplicación, pero lo que he notado durante la prueba en el emulador es que el teléfono requerirá un reinicio en cada actualización, incluso si no hay nada nuevo con el servicio. Lo que me gustaría saber es lo siguiente:

  • ¿Podría haber lejos para hacer que los PhoneUtils se unen a mi servicio sin un reinicio? Por lo menos en el tiempo de actualización?
  • En caso de que no haya manera de hacerlo, estoy pensando en crear 2 aplicaciones, una que es la aplicación normal con la que el usuario interactuaría y otra separada que contiene mi servicio. En este caso, se le pedirá al usuario en la primera ejecución, en caso de que necesite alguna de las características de ussd, para instalar la segunda aplicación. Me preocupa que esto sea molesto para el usuario. ¿Cuál crees que sería la mejor manera de abordar este enfoque?

Para la referencia, he incluido el código que utilicé para el servicio como la parte de la interfaz es diferente que el publicado en el sitio web original.

Interfaz:

* 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; } 

Servicio:

 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); } } 

Gracias

Por favor, sea claro, que están completamente fuera de las malas hierbas de las implementaciones internas de la plataforma. Suena como usted está deseando que esto funcione "bien". Lo que estás haciendo no va a funcionar bien, punto. No tiene ninguna garantía de que estas implementaciones internas se mantendrán iguales en las diferentes versiones de las plataformas o incluso en distintas versiones de la plataforma en los dispositivos de fabricante, ni que el comportamiento que se está viendo en esta interfaz funcionará igual en diferentes situaciones.

Esto es sólo malo malo malo. No lo hagas.

  • Cómo obtener respuesta del código USSD de Android?
  • Cómo interactuar con el cuadro de diálogo USSD mediante programación en android
  • ¿Cómo ejecutar comandos USSD en android?
  • Android studio Acción llamada para ejecutar códigos USSD
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.