Implementieren von USSD-Funktionen. Binden eines Dienstes an die PhoneUtils, ohne das Telefon bei jedem Update neu zu starten

Ich versuche, eine Anwendung zum Senden, Empfangen und Analysieren von USSD-Codes auf Android zu implementieren. Bisher habe ich den Code verwendethttp://commandus.com/blog/?p=58 um diese Funktionalität zu erhalten. Damit der Dienst funktioniert, muss das Telefon neu gestartet werden. Dies wäre kein Problem, wenn der Benutzer die Anwendung zum ersten Mal installiert. Beim Testen auf dem Emulator ist mir jedoch aufgefallen, dass das Telefon bei jedem Update neu gestartet werden muss, auch wenn der Dienst nichts Neues enthält. Was ich wissen möchte, ist das folgende:

Könnte es nicht möglich sein, die PhoneUtils ohne Neustart an meinen Dienst zu binden? Zumindest bei Update-Zeit?Für den Fall, dass dies nicht möglich ist, möchte ich zwei Anwendungen erstellen, eine normale Anwendung, mit der der Benutzer interagieren würde, und eine separate, die meinen Dienst enthält. In diesem Fall wird der Benutzer beim ersten Start aufgefordert, die zweite Anwendung zu installieren, falls er eine der ussd-Funktionen benötigt. Ich mache mir allerdings Sorgen, dass dies für den Benutzer ärgerlich ist. Was ist Ihrer Meinung nach der beste Weg, um einen solchen Ansatz in Angriff zu nehmen?

Zu Referenzzwecken habe ich den für den Dienst verwendeten Code eingefügt, da der Schnittstellenteil sich von dem auf der ursprünglichen Website veröffentlichten unterscheidet.

Schnittstelle:

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

Bedienung:

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

   }

Vielen Dank

Antworten auf die Frage(1)

Ihre Antwort auf die Frage