Я пытаюсь реализовать приложение для отправки, получения и анализа 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);
}
}
Спасибо