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

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

Might there be away to make the PhoneUtils bind to my service without a restart? At least on update time? In case there's no way to do so, i'm thinking of creating 2 applications, one that is the normal application the user would interact with and a separate one containing my service. In this case the user will be prompted on first run, in case he/she requires any of the ussd features, to install the second application. I'm worried though that this is annoying for the user. What do you think would be the best way to tackle such approach?

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

Интерфейс:

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

   }

Спасибо

Ответы на вопрос(1)

Ваш ответ на вопрос