Tuesday, May 31, 2011

BlackBerry Connectivity Issues

Search for Available Transports on the Device:

In order to connect to the internet from our blackberry applications we first need to search for the available transports. For a transport to be available we need to check whether there is sufficient coverage for that transport on the device and that there is a ServiceRecord available for that transport.

Searching for ServiceRecords:

The ServiceBook object should be used to get the ServiceRecords:
ServiceBook sb = ServiceBook.getSB();
ServiceRecord[] records = sb.getRecords();
Now that we have got all the service records in the records[]array we can traverse all the records and identify the available transports by checking the cid and uid of each ServiceRecords as follows:
/** Stores transport ServiceBooks if found. Otherwise, null */
private ServiceRecord srMDS, srBIS, srWAP, srWAP2, srWiFi, srUnit; 
/** Flags indicating the coverage status of each transport */
private boolean
    coverageTCP = false,
    coverageMDS = false,
    coverageBIS = false,
    coverageWAP = false,
    coverageWAP2 = false,
    coverageWiFi = false,
    coverageUnite = false;

for (int i = 0; i < records.length; i++) {
ServiceRecord myRecord = records[i];
      String cid, uid;

      if (myRecord.isValid() && !myRecord.isDisabled()) {
          cid = myRecord.getCid().toLowerCase();
          uid = myRecord.getUid().toLowerCase();
          // BIS
          if (cid.indexOf("ippp") != -1 && uid.indexOf("gpmds") != -1) {
              srBIS = myRecord;
          }

          // BES
          if (cid.indexOf("ippp") != -1 && uid.indexOf("gpmds") == -1) {
              srMDS = myRecord;
          }
          // WiFi
          if (cid.indexOf("wptcp") != -1 && uid.indexOf("wifi") != -1) {
              srWiFi = myRecord;
          }
          // Wap1.0
          if (getConfigType(myRecord) == CONFIG_TYPE_WAP && cid.equalsIgnoreCase("wap")) {
              srWAP = myRecord;
          }
          // Wap2.0
          if (cid.indexOf("wptcp") != -1 && uid.indexOf("wifi") == -1 && uid.indexOf("mms") == -1) {
              srWAP2 = myRecord;
          }
          // Unite
          if (getConfigType(myRecord) == CONFIG_TYPE_BES && myRecord.getName().equals(UNITE_NAME)) {
              srUnite = myRecord;
          }
      }
}


Searching For Coverages:

Now by using the CoverageInfo class (net.rim.device.api.system.CoverageInfo) we have to determine the transports for which we have sufficient coverage.
if (CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_BIS_B)) {
coverageBIS = true;
}

if (CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_MDS)) {
    coverageMDS = true;
    coverageUnite = true;
}
/**
 * In JDE 4.5 CoverageInfo changed the name of COVERAGE_CARRIER to COVERAGE_DIRECT
 * The constant value for both is the same, '1', so we can ALSO use 1 to avoid any
 * dependency on JDE 4.5
 */
if (CoverageInfo.isCoverageSufficient(1)) {
    coverageTCP = true;
    coverageWAP = true;
    coverageWAP2 = true;
}

//if(WLANInfo.getWLANState()==WLANInfo.WLAN_STATE_CONNECTED){  // <-- This line requires JDE 4.5 or later (WLANInfo)
if (CoverageInfo.isCoverageSufficient(1, RadioInfo.WAF_WLAN, false)) {
    coverageWiFi = true;
}

Necessary Utilities Methods are given below:

/**
     * Gets the config type of a ServiceRecord using getDataInt below
     * @param record    A ServiceRecord
     * @return  configType of the ServiceRecord
     */
    private int getConfigType(ServiceRecord record) {
        return getDataInt(record, 12);
    }

    /**
     * Gets the config type of a ServiceRecord. Passing 12 as type returns the configType.   
     * @param record    A ServiceRecord
     * @param type      dataType
     * @return  configType
     */
    private int getDataInt(ServiceRecord record, int type) {
        DataBuffer buffer = null;
        buffer = getDataBuffer(record, type);

        if (buffer != null) {
            try {
                return ConverterUtilities.readInt(buffer);
            } catch (EOFException e) {
                return -1;
            }
        }
        return -1;
    }

    /** 
     * Utility Method for getDataInt()
     */
    private DataBuffer getDataBuffer(ServiceRecord record, int type) {
        byte[] data = record.getApplicationData();
        if (data != null) {
            DataBuffer buffer = new DataBuffer(data, 0, data.length, true);
            try {
                buffer.readByte();
            } catch (EOFException e1) {
                return null;
            }
            if (ConverterUtilities.findType(buffer, type)) {
                return buffer;
            }
        }
        return null;
    }
Now that we have got ServiceRecords and Coverage information for all the available transports, we can use these information to connect to the internet.

http://www.blackberry.com/developers/docs/4.7.0api/javax/microedition/io/Connector.html

Adding Connection Parameter String with the URL:

For each type of connection method specific connection parameters should be appended with the base url. The connection parameters for each transport are as follows:
MDS (BES):
connection_parameter = ";deviceside=false";

BIS:
connection_parameter = ";deviceside=false;ConnectionType=" + "mds-public";

Direct TCP:
connection_parameter = ";deviceside=true";

WAP 1.0:
connection_parameter =
  ";WapGatewayIP=" + gatewayIP
+ ";WapGatewayPort=" + gatewayPort 
+ ";WapSourceIP=" + 
+ ";WapSourcePort=" + sourcePort
+ ";TunnelAuthUsername=" + username
+ ";TunnelAuthPassword=" + password
+ ";WapEnableWTLS=true";

WAP 2.0:
connection_parameter = ";deviceside=true" + ((srWAP2 == null) ? "" : (";ConnectionUID=" + srWAP2.getUid()));

WiFi:
connection_parameter = ";interface=wifi";

Appending this connection_parameter  with the base url we have got the final URL (suppose full_url). An HttpConnection object can be made with this URL to start an Http Connection.

Useful links:
supportforums.blackberry.com - Different ways to make an HTTP or socket connection