Would you like to tell us how we are doing?

You bet No thanks

Sorry about the red box, but we really need you to update your browser. Read this excellent article if you're wondering why we are no longer supporting this browser version. Go to Browse Happy for browser suggestions and how to update.

Registering to receive push messages

To receive push messages, the sample application subscribes with the Push Initiator, and registers with the Push Service APIs which start the listener on the application's port that listens for push messages. If you're using the BlackBerry Internet Service as the PPG, the APIs also register the application with the PPG. Registration creates a push channel that the Push Initiator uses to send push messages to the push-enabled application on the device.

Once your application is registered, the APIs start your application automatically in the background when a new push message arrives. This can use up device resources, so it's a good practice to exit your application after it processes a push message. For more information, see Exiting after processing a push message.

If the Push Initiator was written using the Push Service SDK, the Push Initiator requires a username and password that it authenticates before allowing the subscription. The sample application provides a Register dialog box where the user can type any username and password. You can open the Register dialog box by pressing the Menu key on your device, and then clicking Register. The Register dialog box appears.

Register dialog box

After you type the username and password, and click OK in the dialog box, the sample application tries to subscribe with the Push Initiator. If subscribing is successful, the application tries to register with the PPG if you're using the BlackBerry Internet Service. The RegisterCommand class handles the subscription and registration.

protected void execute() throws Exception {
    // first we register with Push Initiator/Content Provider
    ContentProviderProtocol.performCommand( 
       ContentProviderProtocol.CMD_SUBSCRIBE, 
       username, password, isEnterprise, tx );

    // if the registration is successful we register with BPS PPG
    BpasProtocol bpasProtocol = PushLibFactory.getBpasProtocol();
    bpasProtocol.register( tx, isEnterprise );

    // update the registered state
    PersistentStorage.setRegistered( true );
}

In your application, you should subscribe with the Push Initiator so that the Push Initiator can keep an accurate list of subscribed devices. The Push Initiator shouldn't send push messages to devices that aren't subscribed.

If you don't want to use the Push Service SDK to write your Push Initiator, but you still want to use the sample application, you need to include some code in your Push Initiator that accepts the subscription request sent from the sample application, and returns an HTTP response back to the application.

Call performCommand() to subscribe with the Push Initiator

The sample application defines a class to handle the interaction with the Push Initiator called ContentProviderProtocol. This class is responsible for performing subscribe, unsubscribe, suspend, and resume HTTP calls with the Push Initiator. The class performs network commands in a dedicated thread so the caller isn't blocked, and therefore can be executed from the UI application event thread.

The performCommand() method is generic, and handles all four interactions with the Push Initiator (subscribe, unsubscribe, suspend, and resume). The cmd parameter indicates which command to execute. All four commands are HTTP requests, and they expect an HTTP response with a body of rc=200 to be considered successful.

// List of commands 
public static final int CMD_SUBSCRIBE = 0;
public static final int CMD_UNSUBSCRIBE = 1;
public static final int CMD_SUSPEND = 2;
public static final int CMD_RESUME = 3;
public static void performCommand( int cmd, 
        final String username, final String password, 
        final boolean isEnterprise, Transaction tx ) throws IOException {
        
        String url = PushConfig.getContentProviderUrl();
        final String cmdName;
        switch( cmd ) {
            case CMD_SUBSCRIBE:
                url += SUBSCRIBE_URL;
                cmdName = "Subscribe";
                break;
            case CMD_UNSUBSCRIBE:
                url += UNSUBSCRIBE_URL;
                cmdName = "Unsubscribe";
                break;
            case CMD_SUSPEND:
                url += SUSPEND_URL;
                cmdName = "Suspend";
                break;
            case CMD_RESUME:
                url += RESUME_URL;
                cmdName = "Resume";
                break;
            default:
                return;
        }

        // append username, password and other parameters
        url += USERNAME_PARAM + username;
        url += PASSWORD_PARAM + password;
        url += APP_ID_PARAM + PushConfig.getAppId();
        url += PIN_PARAM + Integer.toHexString( DeviceInfo.
            getDeviceId() );
        //#ifdef HANDHELD_VERSION_42
        url += OS_PARAM + "4.2.0";
        //#else
        url += OS_PARAM + DeviceInfo.getSoftwareVersion();
        //#endif
        url += MODEL_PARAM + DeviceInfo.getDeviceName();
        url += TYPE_PARAM + ( isEnterprise ? CLIENT_TYPE_ENTERPRISE : 
			CLIENT_TYPE_PUBLIC );
        
        // Your application can append any additional parameters your
        // server-side application may require, eg:

        url += USER_DEFINED_PARAM + new Random().nextInt( 1000 );

        String response;
        try {
            response = PushUtils.request( url, tx );
        } catch( IOException e ) {
            // subscription failed
            if( !tx.isCancelled() ) {
                Logger.warn( "Content Provider network command [" + 
                  cmdName + "] failed, caused by " + 
                  e.getMessage() );
                throw new IOException( "Network operation [" + 
                  cmdName + "] failed. Make sure that Content 
                  Provider URL is accessible." );
            }
            return;
        }
        
        checkResult( response );
}
private static void checkResult( String response ) throws IOException {
        if( response.equals( "rc=200" ) ) {
            // success
            return;
        } else if( response.equals( "rc=10001" ) ) {
            throw new IOException( "The address specified is null 
            or empty or is longer than 40 characters in length" );
        } else if
		. . .
        }
}

Call register()

The sample application defines an interface called BpasProtocol to handle the interaction with PPG if you're using the BlackBerry Internet Service. The PushLib50 class implements this interface, and handles the registration with the PPG.

The sample application creates a PushApplicationDescriptor that defines the properties of the application. The application then checks to see if the user is already registered or if registration is pending. If neither of these conditions are true, the application calls PushApplicationRegistry.registerApplication() to register with the PPG. The PushApplication#onStatusChange() callback method notifies the application with the result of the registration. If registration is successful, the Push Service APIs start the listener on the application's port to listen for push messages.

public void register( Transaction tx, boolean isEnterprise ) throws Exception {
        int port = PushConfig.getPort();
        String appId = PushConfig.getAppId();
        String bpsUrl = PushConfig.getBpsUrl();
        ApplicationDescriptor ad = 
		  ApplicationDescriptor.currentApplicationDescriptor();
        
        // server type depends whether we get pushes through BES or BIS
        byte serverType = isEnterprise ? 
		  PushApplicationDescriptor.SERVER_TYPE_NONE 
		  PushApplicationDescriptor.SERVER_TYPE_BPAS;

        // if enterprise network then there is no server URL
        bpsUrl = isEnterprise ? null : bpsUrl;

        // Create a PushApplicationDescriptor
        PushApplicationDescriptor pad = new PushApplicationDescriptor( 
          appId, port, bpsUrl, serverType, ad );

        // check whether already registered or registration pending
        PushApplicationStatus pushApplicationStatus = 
		  PushApplicationRegistry.getStatus( pad );
        byte pasStatus = pushApplicationStatus.getStatus();
        if( pasStatus == PushApplicationStatus.STATUS_ACTIVE ) {
            // we already registered, update the statuses
            Logger.log( "Already registered with Push API" );
            return;
            
        } else if( pasStatus == PushApplicationStatus.STATUS_PENDING ) {
            // we already scheduled registration, wait for its result
            Logger.log( "Registration with Push API already scheduled");
            setCurrentTransaction( tx );
            tx.waitForNotification();
            
        } else {
            // not registered yet, perform registeration
		    // final outcome will be available via 
			// PushApplication#onStatusChange() callback
            Logger.log( "Scheduled registration with Push API");
            PushApplicationRegistry.registerApplication( pad );
            setCurrentTransaction( tx );
            tx.waitForNotification();
        }
        readRegistrationResult();
}

The sample application stores the registration status in a local database. In your application, you might also want to store the registration status, but you should also register periodically because registration with the PPG can be cancelled without your application being notified. You could register once a week, once a month, or when the user restarts the device.