Tuesday, June 30, 2015

Dissecting MQTT SUBACK message

references:
http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#suback

Dissecting MQTT SUBSCRIBE message

references:
http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#subscribe

Dissecting MQTT PUBACK, PUBREL,PUBREC, messages

references:
http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#puback

Dissecting MQTT PUBLISH message

References:
http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#publish

iOS ABAddressbook concepts Part II

Properties: There are two kind of properties single value and multi value. Multi value properties contains data that can have multiple values. 
Multi value properties can either be mutable or unmutable. 

Following is example to get the single value property 

ABRecordRef personRef = ABPersonCreate();
CFErrorRef anError = NULL;
bool didSet;

didSet = ABRecordSetValue(aRecord,kABPersonFirstNameProperty,CFSTR(“Katie”), &anErr);
CFStringRef firstName = ABRecordCopyValue(aRecord,kABPersonFirstNameProperty);
CFRelease(firstName); 

Multi Value Properties 

MultiValue properties consist of list of values. Each value has a text label and an identifier associated with it. There can be more than one value with the same label, but the identifier is always unique. There are constants defined for some commonly used text labels. For e.g. Phone number of a person can be many. 




References:

https://developer.apple.com/library/prerelease/ios/documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/BasicObjects.html#//apple_ref/doc/uid/TP40007744-CH3-SW1


iOS AddressBook Accessing records - Part I

To use an address book, we need to declare an instance of ABAddressBookRef and set to the value returned from the function ABAddressbookCreate. One can use multiple address book objects, but they are all backed by the same shared database. 

As an important note, instances of ABAddressbookRef cannot be used by multiple threads. Each thread must make its own instance. 

Records
In the address book data base, the information is stored as records. represented by ABRecordRef objects. Each record represents a person group. The function ABRecordGetRecordType returns kABPersonType if the record is a person and kABGroupType if it is a group. Unlike the MacOS record types, here there is no separate classes for different types of records. both person objects and group objects are instances of the same class. 

Record objects cannot be passed across threads safely, instead one should pass the record identifiers. 

Within a record, the data is stored as a collection of properties. The properties available for Group and Person are different, but the function used to access those are the same. The functions ABRecordCopyValue and ABRecordSetValue gets and sets the properties. Properties can also be removed completely. using a function ABRecordRemoveValue. 


Person Records : Person records are made up of both single and multi values properties. Properties that a person can have only one of, such as first name and last name are stored as single value properties. Other properties that a person can have more than one of such as phone number, are multi value properties. 

Group Records. 
Users may organize their contacts into groups for a variety of reasons. For e.g. a user may create a group. Group records have only one property kABGroupNameProperty, which is the name of the group. To get all the members the group, use the function ABGroupCopyArrayOfAllMembers or ABGroupCopyArrayOfAllMembersWithSortOrdering which return a CFArrayRef of ABRecordRef objects.  

References:

Sunday, June 28, 2015

RTCP detailed tutorial

the RTCP packet contains below items 

8 bytes of UDP header 
12 bytes min of RTCP header
Variable, with 32 bit boundary of of RTCP data 



RTCP is delivered over RTP UDP port number + 1
(usually one port number per multi media session) 

Usually, RTCP packets are bundled and may contains several packets which is encapsulated in the same UDP data gram (to reduce the overhead due to headers) 

The RTCP header has the following components

version - 2 bits
Padding bit - 1 bits 
RR count - 5 bits
Packet Type - 8 bits 
Message Length - 16 bits 



The following are the possible packet types possible in the RTCP data 

192 - FIR => Full INTRA frame request 
193 - NACK => Negetive Acknowledgement 
200 - SR => Sender report for transmission and reception statistics from active senders (periodically transmitted) 
201 - RR => Receiver report for reception statistics from participants that are not active senders (periodically transmitted) 
202 - SDES => Source Description items (including CNAME - canonical name) 
203 - BYE => Good bye indicates end of participation 
204 - APP => Application specific functions 
207 - XR => RTCP extension 


RTCP Sender Report 
RTCP receivers provide reception quality feedback using a SR or a RR (if receiver also a sender) 


The Sender Report is having two main blocks apart from the header. 
1. Sender Information Block
2. Reception Report Block (for each source) 

Sender Information Block is having below items
- NTP timestamp (the absolute wall clock time when report was sent) 
- RTP timestamp (relative timestamp used in RTP packets) 
- Sender's packet count (RTP packets transmitted by this sender so far in this session) 
- Sender's octect count (same but the total number of RTP payloads)

Reception Report Block contains the below main items 
- Fraction lost (fraction of RTP packets from this source lost since last report) 
- Commutative number of lost packets
- Extended highest sequence number received 
- Inter arrival Jitter (estimate of jitter of RTP data from SSRC) 
- Last SR timestamp received from this source. 
- Delay since receiving the last SR report from this source. 


References:

Tuesday, June 23, 2015

Dissecting MQTT Connect CONNACK message

CONNACK message is sent in response to the CONNECT request. 

Below are the components in a CONNACK Request 

1. Fixed Header
2. Variable Header 

There is no PAYLOAD for the CONNACK request. 

Below is a Wireshark trace for the CONNACK message. 



Fixed header is again two bytes

Message Type will indicate value 2, so the first byte will look like 20 
Second byte tell the remaining length, which is again 02, which represents the variable length header

In the variable header, which is again 2 bytes, the first byte is not used and it is reserved as of now. 
Second byte represents the response code for the CONNECT request. Below are the  response codes possible for CONNECT request

0 - connection accepted 
1 - Connection refused, unacceptable protocol version
2 - connection refused, identifier rejected
3 - connection refused, server unavailable 
4 - connection refused, bad user name or password 
5 - connection refused, not authorized
6 to 255 - reserved for future use. 


References:

Monday, June 22, 2015

MQTT dissecting CONNECT message

Below is the trace from wireshark for an MQTT connect message.


The main components of an MQTT message are

1. Fixed Length header
2. Variable Length header
3. Payload

In the figure above, highlighted the fixed length header and updated image is given below.

The first two bytes constitutes the fixed header. This is highlighted in red in the above image.

Byte 1 => has value 10 which has the bit format of 0001 0000

Bit 0 (right most bit) indicates whether the message should be retained
Bit 1 & 2 indicate the QoS level, values being 0, 1, 2
Bit 3 indicates the DUP flag, server sets this if the message is a DUPlicate
Bits 4, 5, 6, 7 altogether mentions the message type. In this case, it is 1, indicating the message as CONNECT

byte 2 of the Fixed length header denotes the length of the remaining data. In this case, it is Hex 49.

Next is variable length header, this is highlighted in green in the image above.
in the variable length header area, first comes the protocol name the first and second byte are respectively 0, 6 and then the word MQIsdp. The the protocol version number, which is 3 in the image above. Byte 10 in this section represents the Connect flags, each bit in this Byte has meaning below.

bit 7 => user name flag (if present or not)
bit 6 => password flag (if present or not)
bit 5, Will RETAIN => 0 for CONNECT message
bit 4, 3 Will QoS => 01 for will QOS in connect message
bit 2 will flag
bit 1 clean session => 1 indicates that it is a clean session
bit 0 is not used as of now

byte 11 and 12 denotes the keep alive timer value in this case 00 C2 value in decimal is 60 seconds.

Next is Payload of the CONNECT message
Below are the main components in Payload for Connect

For variable length header, each of the filed is having a prefix that represents the length of that field.

The first item in the variable length area is client Id, below image in green under line shows the variable header total content, and the red highlight box shows the client Id, first two digits being the length, 13 Hex, which is 19 chars.





1. Client Identifier : This is a UTF encoded string, the length can be from 1 to 23, This uniquely identifies device to the server. If the length exceeds, the CONNACK response with 2 indicating the identifier rejected.

Other items in the variable header are 2. Will topic, 3. Will message, 4. User name , 5. Password

references:


Sunday, June 21, 2015

Paho MQTT Java Client

Pho Java client is a MQTT client library written in Java. Paho Java client provides two APIs. 

Having decided to build from source, ran the below commands in Terminal 

git clone http://git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.java.git

while trying to install using maven, using sudo install maven, it gave the below error. 

notice:configure --->  Configuring maven
:debug:configure Using compiler 'Xcode Clang'
:debug:configure Executing proc-pre-org.macports.configure-configure-0
:error:configure maven is a stub, use maven1 instead.
:error:configure org.macports.configure for port maven returned: obsolete port
:debug:configure Error code: NONE
:debug:configure Backtrace: obsolete port
    while executing

This was corrected and the maven installed by just changing to sudo port install maven1 

also tried with the brew install maven
which installed maven 3.3 

after this ran the command 

mvn package -DskipTests

However, this seemed to fail with some compiler errors. 

I then decided to go with the source files to learn things on how the formatting is done etc.

References:

MQTT protocol overview - Part II

Agnostic Payload for Flexible Delivery: The payload can be in any format, binary, text, picture data. 
Message retaining for last value caching: Client can ask MQTT broker to retain the last message it sent 
The message almost looks like below 

CONNECT id=thing1
PUBLISH thing1/battery {“value” : “95”} RETAIN 
PUBLISH thing1/battery {“value” : “94”} RETAIN
PUBLISH thing1/battery {“value” : “93”} RETAIN
DISCONNECT 

CONNECT ID=thing2
SUBSCRIBE thing1/battery 
<- :="" battery="" nbsp="" publish="" span="" thing1="" value="">

MQTT has client ID and cleanSession for Session State

CONNECT ID=thing1, cleanSession=FALSE
SUBSCRIBE chat/myRoom QoS=2
DISCONNECT 

CONNECT ID=thing2
PUBLISH chat/myRoom “Hello Thing1” QoS=1
PUBLISH chat/myRoom “Are you there?” QoS=2

CONNECT ID=thing1, cleanSession=FALSE
chat/myRoom “Hellow thing1” PUBLISH
chat/myRoom “Are you there?” PUBLISH
PUBLISH chat/myRoom “Am there now!” QoS=1

MQTT has last will and testament for presence

CONNECT ID=thing2
SUBSCRIBE thing1/status

CONNECT ID=thing1 LWT=thing1/status “Bye”
PINGREQ -> 
<- nbsp="" pingres="" span="">
(client now has network problem)
(keep alive seconds pass)
<- bye="" nbsp="" publish="" span="" status="" thing1="">

References:

Saturday, June 20, 2015

Android Listing App in Share Menu

The concept is really simple in Android. Just mention the mime type the app supports and from anywhere within the system when user chooses the share option, 
the application will be listed in that share option.  

<activity
   
android:name=".grid.MainActivity"
   
android:configChanges="orientation|screenSize"
   
android:label="@string/app_name" >
    <
intent-filter>
        <
action android:name="android.intent.action.SEND" />
        <
category android:name="android.intent.category.DEFAULT" />
        <
data android:mimeType="image/*" />
    </
intent-filter>
    <
intent-filter>
        <
action android:name="android.intent.action.SEND" />
        <
category android:name="android.intent.category.DEFAULT" />
        <
data android:mimeType="text/plain" />
    </
intent-filter>
    <
intent-filter>
        <
action android:name="android.intent.action.SEND_MULTIPLE" />
        <
category android:name="android.intent.category.DEFAULT" />
        <
data android:mimeType="image/*" />
    </
intent-filter>

</
activity>

Once the app is receiving the intent, below code can be used to hadle it 

Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();

if (Intent.ACTION_SEND.equals(action) && type != null) {
    if ("text/plain".equals(type)) {
        handleSendText(intent); // Handle text being sent
    } else if (type.startsWith("image/")) {
        handleSendImage(intent); // Handle single image being sent
    }
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
    if (type.startsWith("image/")) {
        handleSendMultipleImages(intent); // Handle multiple images being sent
    }
} else {
    // Handle other intents, such as being started from the home screen

}

void handleSendText(Intent intent) {
    String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
    if (sharedText != null) {
        // Update UI to reflect text being shared
        Toast.makeText(AppUtils.getAppContext(), sharedText , Toast.LENGTH_SHORT).show();
    }
}

void handleSendImage(Intent intent) {
    Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
    if (imageUri != null) {
        // Update UI to reflect image being shared
        Toast.makeText(AppUtils.getAppContext(), imageUri.toString() , Toast.LENGTH_SHORT).show();
    }
}

void handleSendMultipleImages(Intent intent) {
    ArrayList imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
    if (imageUris != null) {
        // Update UI to reflect multiple images being shared
    }

}

References:

Friday, June 19, 2015

Android Map, Markers

Makers can be added to the Map using GoogleMap.addMarker(markerOptions) API. Markers can receive click events, and often used as event listeners to bring up the Info Window. Marker can have draggable settings which will allow user to drag the marker. 

static final LatLng PERTH = new LatLng(-31.90, 115.86);
Marker perth = mMap.addMarker(new MarkerOptions()
        .position(PERTH)
        .draggable(true));

Below code can be used for adding marker to the map. 

SupportMapFragment fragment =  (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
Log.v(LOG_TAG, "fragment is " + fragment);
if(fragment != null)
{
    Log.v(LOG_TAG,"map framgment is not null");
    GoogleMap map = fragment.getMap();
    if(map != null)
    {
        Log.v(LOG_TAG,"map is not null");
        map.setMyLocationEnabled(true);
    }
    fragment.getMapAsync(new OnMapReadyCallback() {
        @Override
       
public void onMapReady(GoogleMap googleMap) {
            Marker marker = googleMap.addMarker(new MarkerOptions()
                    .position(new LatLng(10,10))
                    .title("Hello world"));
        }
    });
}

Marker class also have a method remove() to remove the marker from the map.
References:

Thursday, June 18, 2015

Network Connection In Android

Network operations should be performed in a separate thread. The AsyncTask provides one of the simplest ways to fire off a new tasks from the UI thread. 
Application can create one class that is subclass of AsyncTask and implement the doInBackground, onPostExecute methods and return  the results to the UI

A simple implementation of async task will be like this. 

public class HttpConnectorAsyncTask extends AsyncTask {

    private  static final String LOG_TAG = "HCAT";
    private HttpConnectorAsyncTaskListener listener = null;

    public void setConnectionListener(HttpConnectorAsyncTaskListener listener)
    {
        this.listener = listener;
    }

    @Override
   
protected String doInBackground(String... urls) {

        // params comes from the execute() call: params[0] is the url.
       
try {
            return downloadUrl(urls[0]);
        } catch (IOException e) {
            return "Unable to retrieve web page. URL may be invalid.";
        }
    }
    // onPostExecute displays the results of the AsyncTask.
   
@Override
   
protected void onPostExecute(String result) {
//        textView.setText(result);
       
if(this.listener != null)
        {
            this.listener.connectionResponseDataReceived(result);
        }
    }

    private String downloadUrl(String myurl) throws IOException {
        InputStream is = null;
        // Only display the first 500 characters of the retrieved
        // web page content.
       
int len = 500;

        try {
            URL url = new URL(myurl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(10000 /* milliseconds */);
            conn.setConnectTimeout(15000 /* milliseconds */);
            conn.setRequestMethod("GET");
            conn.setDoInput(true);
            // Starts the query
           
conn.connect();
            int response = conn.getResponseCode();
            Log.d(LOG_TAG, "The response is: " + response);
            is = conn.getInputStream();

            // Convert the InputStream into a string
           
String contentAsString = readIt(is, len);
            return contentAsString;

            // Makes sure that the InputStream is closed after the app is
            // finished using it.
       
} finally {
            if (is != null) {
                is.close();
            }
        }
    }

    // Reads an InputStream and converts it to a String.
   
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
        Reader reader = null;
        reader = new InputStreamReader(stream, "UTF-8");
        char[] buffer = new char[len];
        reader.read(buffer);
        return new String(buffer);
    }
}

to note: 

- This method reads only 500 chars 
- upon getting connection error, need to handle cases

References

A Few Notes on MQTT

A Few Notes on MQTT 

MQTT decouples SUBSCRIBERS for PUBLISHERS 

- Anyone can PUBLISH and any one can SUBSCRIBE to the data. As long as the data is in the understandable format, the exchange will be smooth. 

MQTT allows wildcard subscriptions 

Some of the Published data can be as below 

scores/football/big12/Texas
scores/football/big12/TexasTech
scores/football/big12/Okalahoma
scores/football/big12/IowaState

Everyone of the above will PUBLISH to the MQTT broker. 

The interested parties and their SUBSCRIPTION can be below 

Texas Fan => scores/football/big12/Texas
Big12 Fan => scores/football/big12/+
ESPN => scores/#

+ represents single level wild card
# represents multi level wild card 

Some of the network properties of MQTT are: 

Small Packet Size: 
PUBLISH is 2-4 bytes
CONNECT is 14 bytes 
HTTP is 0.1 - 1 KB

the headers is binary payload and it is not text 
Small clients that has 30KB foot print and as well as huge memory foot print clients can be well supported at the same time 

Minimal protocol exchanges between ends. MQTT has a configurable keep alive 2 byte PINGREQ/PINGRES

MQTT supports QoS for reliable messaging:
There are 3 QoS levels 
1. QoS 0: at most once  (PUBLISH) 
- Doesn’t survive failure
- Doesn’t repeat 

2. QoS 1: At least once (PUBLISH, PUBLIC ACK) 
Survives connection loss
can be duplicated 
3. QoS 2 : exactly once (PUBLISH, PUBREC, PUBREL, PUBCOMP)
Service connection loss,
Never duplicated 




References:

Wednesday, June 17, 2015

Log 4J in Android

Download the log4j-1.2.17.jar and android-logging-log4j-1.0.3.jar from the links given in the references. (the version number could vary in the file name, as of this writing these are the files i was able to download)

After this added the gradle build file using Open Module Settings -> Dependencies -> File Dependancies 

The build.gradle file looked like this 

dependencies {
    compile fileTree(
include: ['*.jar'], dir: 'libs')
    compile
'com.android.support:appcompat-v7:22.1.1'
   
compile 'com.android.support:support-v4:22.1.1'
   
compile 'com.google.android.gms:play-services:7.3.0'
   
compile files('libs/android-logging-log4j-1.0.3.jar')
    compile files(
'libs/log4j-1.2.17.jar')
}
Now added the Log4jHelper class like this below. 

package mypackage;

import android.os.Environment;
import de.mindpipe.android.logging.log4j.LogConfigurator;


public class Log4jHelper {
    private final static LogConfigurator mLogConfigrator = new LogConfigurator();

    static {
        configureLog4j();
    }

    private static void configureLog4j() {
        String fileName = Environment.getExternalStorageDirectory() + "/" + "log4j.log";
        String filePattern = "%d - [%c] - %p : %m%n";
        int maxBackupSize = 10;
        long maxFileSize = 1024 * 1024;

        configure( fileName, filePattern, maxBackupSize, maxFileSize );
    }

    private static void configure( String fileName, String filePattern, int maxBackupSize, long maxFileSize ) {
        mLogConfigrator.setFileName( fileName );
        mLogConfigrator.setMaxFileSize( maxFileSize );
        mLogConfigrator.setFilePattern(filePattern);
        mLogConfigrator.setMaxBackupSize(maxBackupSize);
        mLogConfigrator.setUseLogCatAppender(true);
        mLogConfigrator.configure();

    }

    public static org.apache.log4j.Logger getLogger( String name ) {
        org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger( name );
        return logger;
    }
}


From the application code, call the below, 

org.apache.log4j.Logger logger= Log4jHelper.getLogger("MainActivity");
logger.info(
"This is a sample message as info");
logger.trace(
"This is a sample message as trace");
logger.warn(
"This is a sample message as warn");


Thats it! . i was able to see the log4j.log file under storage in sdcard. 

References:

Extracting and Displaying Certificate information from a p12 file

On iOS the code is bit simple, like given below. 

-(IBAction) loadCertificate:(id)sender
{
    NSString *str=[[NSBundle mainBundle] pathForResource:@“cert1” ofType:@"p12"];
    NSData *fileData = [NSData dataWithContentsOfFile:str];
    SecIdentityRef identityRef;
    SecTrustRef outTrust;
    CFStringRef passwordRef = (__bridge CFStringRef)@“pass123”;
    CFDataRef cfdata = CFDataCreate(NULL, [fileData bytes], [fileData length]);
    OSStatus status = extractIdentityAndTrust(cfdata,&identityRef,&outTrust,passwordRef);
    
    NSLog(@"--status of import is :%d",(int)status);
    
    NSString *summaryStr = copySummaryString(identityRef);
    NSLog(@"--Summary :%@",summaryStr);
    
}

OSStatus extractIdentityAndTrust(CFDataRef inPKCS12Data,
                                 SecIdentityRef *outIdentity,
                                 SecTrustRef *outTrust,
                                 CFStringRef keyPassword)
{
    OSStatus securityError = errSecSuccess;
    
    
    const void *keys[] =   { kSecImportExportPassphrase };
    const void *values[] = { keyPassword };
    CFDictionaryRef optionsDictionary = NULL;
    
    /* Create a dictionary containing the passphrase if one
     was specified.  Otherwise, create an empty dictionary. */
    optionsDictionary = CFDictionaryCreate(
                                           NULL, keys,
                                           values, (keyPassword ? 1 : 0),
                                           NULL, NULL);  // 1
    
    CFArrayRef items = NULL;
    securityError = SecPKCS12Import(inPKCS12Data,
                                    optionsDictionary,
                                    &items);                    // 2
    
    
    //
    if (securityError == 0) {                                   // 3
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,
                                             kSecImportItemIdentity);
        CFRetain(tempIdentity);
        *outIdentity = (SecIdentityRef)tempIdentity;
        const void *tempTrust = NULL;
        tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
        
        CFRetain(tempTrust);
        *outTrust = (SecTrustRef)tempTrust;
    }
    
    if (optionsDictionary)                                      // 4
        CFRelease(optionsDictionary);
    
    if (items)
        CFRelease(items);
    
    return securityError;
}


NSString *copySummaryString(SecIdentityRef identity)
{
    // Get the certificate from the identity.
    SecCertificateRef myReturnedCertificate = NULL;
    OSStatus status = SecIdentityCopyCertificate (identity,
                                                  &myReturnedCertificate);  // 1
    
    if (status) {
        NSLog(@"SecIdentityCopyCertificate failed.\n");
        return NULL;
    }
    
    CFStringRef certSummary = SecCertificateCopySubjectSummary
    (myReturnedCertificate);  // 2
    
    NSString* summaryString = [[NSString alloc]
                               initWithString:(__bridge NSString *)certSummary];  // 3
    
    CFRelease(certSummary);
    
    return summaryString;
}

References:

Tuesday, June 16, 2015

Android Interacting with the Map

Developer can decide which of the built in UI components will appear on the map, which of the gestures are allowed on and how to respond to click events from end users. 

the built in UIControls of the map can be controlled using the UISettings class which is obtained by calling the GoogleMap.getUISettings method. The initial configuration can be specified in the XML file also. Below is a sample XML file 

Zoom control can be specified using the UiSettings.setZoomControlsEnabled(true); 
Compass can be enabled using the UiSettings.setCompassEnabled(true)
For MyLocationButton, map.setMyLocationEnabled(true)
Level Picker which is used for picking which floor, can be enabled using GoogleMap.getUISettings.setIndoorLevelPickerEnabled(true);
MapToolbar : The toolbar that appears at the bottom right of the map. this toolbar gives quick access to the Google map mobile app. UiSettings.setMaptoolbarEnabled(true);

Below are the API settings the gestures 
Zoom Gesture 

- Double tap increases the zoom, 
- two finger tap decreases the zoom by 1 
- two finger pinch/stretch 

scroll/pan gestures . This can be enabled or disabled by UiSettings.setScrollGestureEnabled 
Tilt gestures can be enabled or disabled by UiSettings.setTiltGestureEnabled 
Rotate Gesture UiSettigns.setRotateGestureEnabled 

Below are the settings for Map Events 
Map Click events : If app want to listen to user clicking on specific point in the map, can do so by adding listener onMapClickListener by calling GoogleMap.setOnMapClickListener. This will result in the onMapClick event. Long click listener can be enabled by MapView.setOnLongClickListener

The click events on the map can be altogether avoided if we set false to setClickable. 
OnCameraChangeListener can be used for getting the camera position change events. Indoor map stage changes can be obtained using onIndoorStateChangeListener.

references:

Monday, June 15, 2015

Managing OS X with Configuration Profiles - Advantages

Configuration profiles were introduced from OS X Lion. Apple brought configuration profile and MDM technologies to OS X . Some of the benefits of having profile based approach are: 

Changes in configuration profiles can be coordinated between an MDM server and managed computers via the APNs, so that changes can be quickly made on client computers. The flexibility of MDM server is that users can also enroll themselves in the management system. 

When integrated with an MDM server, configuration profiles can be wirelessly distributed to the Mac for handsfree management of deployment. All users need to do is to enroll their Mac for management with the MDM server, and system will handle the rest. 

Below are the advantages of using configuration profiles

Provides great power and flexibility 

Prior to configuration profiles, it was Managed preferences. Profiles offer much more advantages over managed preferences. The existing managed preferences features such as controlling arbitrary apps are still available with the config profiles, but it also allows additional functionalities such as configuring 802.1 or install certificates on the keychain of Mac OS X. 

Enables Mobile Device Management 

A large amount of iOS management with configuration profiles is done via MDM servers. OS X now supports MDM as well, providing flexibility on Mac that organizations expect on mobile devices

Leverages existing file format 
uses same xml profile file format that uses in iOS

Establishes commonality between iOS 
Apple now has commonality between iOS and OS X profiles.


References:

Saturday, June 13, 2015

Google Maps Integrating to Android App

Integration of Google map onto an Android Activity involves multiple steps 

1. Include Google Services SDK into the project and include in the dependency list
2. Create API key for the application 
3. Test and verify everything works 

All these steps are detailed neatly in the links in references. 

Below given are some of the hiccups faced while integrating the map. 

The main one was getting the right SHA1 key. The steps to get the SHA key is 

keytool -list -v -keystore andruks.jks

This gets the SHA1 of the keystone. But during the running via debug, it may be different keystone and the SHA could be different. If we run the app, the log will suggest what should be the SHA1 key to be used. 

06-14 00:35:53.546  16860-17073/lcom.mydomain.myapp E/Google Maps Android API Authorization failure.  Please see https://developers.google.com/maps/documentation/android/start for how to correctly set up the map.
06-14 00:35:53.552  16860-17073/com.mydomain.myapp E/Google Maps Android API In the Google Developer Console (https://console.developers.google.com)
    Ensure that the "Google Maps Android API v2" is enabled.
    Ensure that the following Android Key exists:
    API Key: AIzaSyBgURIAyTk3ENONDMXaXAklVgbtbiqN2Qw
    Android Application (;): 3D:B8:EC:FC:4A:19:0F:1A:1B:C5:1F:EA:E5:C0:F2:96:00:36:10:0C;com.mydomain.myapp

This helps one to copy this and add this in the developer console. 

Another hiccup was when added the Android map via the Activity, it added an additional meta data info and in effect, the below was getting duplicated 

<meta-data
   
android:name="com.google.android.geo.API_KEY"
   
android:value="AIzaSyBgURIAyTk3ENONDMXaXAklVgbtbiqN2Qw" />

This caused the Activity to get crashed as and when it was launched. Just removed the duplicate one and it all worked fine. Below is one screenshot




References:
https://developers.google.com/maps/documentation/android/start
https://console.developers.google.com/project/
https://developers.google.com/maps/documentation/android/start#get-key

Android Socket connection

Android Socket Connections is better to be started in service so that the Connections is always active in the background. This can be made as BoundServices so that Activities can interact with it easily using the Binder interface as well. 

Below two are important ingredients in making the whole thing work 

<uses-permission android:name="android.permission.INTERNET"/>

<service
   
android:name=".connectivity.SocketService"
   
android:enabled="true"
   
android:exported="true" >
</
service>

Need to add the above two in Manifest file. 

As such making a socket connection is easy, below two lines will make the connection 

InetAddress serverAddr = InetAddress.getByName(SERVERIP);

Socket socket = new Socket(serverAddr, SERVERPORT);

try
{
PrintWriter  out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
out.println(“Hello”);
out.flush();

}
catch(Exception ex)
{
}

references:

The Google Inbox story of Code Sharing

In the new world of variety of mobile platforms. the denominator now contains below programming languages

iOS => Objective C, and / or Swift
Android => Java or NDK 
Web => Javascript / CSS / HTML 5

Google tackled this problem and withe the Inbox app, it shares roughly 2/3 of its code across, Android , iOS and the Web 

These three platforms share most of the back end logic that powers the app, while the unique parts are mostly the user interface for each app. Google has built itself a good enough arsenel of cross compilers that it can write an app’s logic once on Android, in Java and then cross-compile to Objective C for iOS and Javascript for web. Java to Javascript is handled by the Google Web Toolkit SDK, which has been around for sometime. 

The Real enabler for Inbox is called j2objc, which as the name implies, covers the Java code meant for Android into iOS ready Objective C Code. 

j2ObjC is an open source project which Google went public last year. The project was used previously in Google Sheets, but the biggest usage is now in Inbox. 

In case of Google Inbox, a lot of shared code defines things like conversations, reminders and contacts. It also deals with the difficult tasks of network management and offline synchronization, where the app is used offline. Sharing the code is a big time saver, since it has to be written and debugged only once. It also makes the app consistent across both platforms. 

The tool does not convert UI pieces from Android to iOS, because that may lead to aweful UX. Google wants developers to write logic once in Java, transpile into other platforms and then make ui natively using the SDK for each platform. 

It is worth trying the j2ObjC having read this article. 

References:

16:9 and 4:3 aspect ratios

16:9 is an aspect ratio with a width of 16 units and height of 9. Since 2009, it has become the most common aspect ratio for sold televisions and computer monitors and is also the international standard format of HDTV, Full HD, non HD television and analog widescreen television. 

A 4:3 aspect ratio will produce more box-like picture, because the screen is only slightly wider than it is high. 4:3 means for every 4 units of width in an image, it will have 3 units of height. it mathematical terms it comes like width is 33% higher than it is high. the 4:3 aspect ratio has been around since early days of television back to 1940’s and 50s. A television that has an aspect ratio of 4:3 is often referred as being NTSC, or pan and scan. The majority of cable channels still broadcast in 4:3 

There are a few aspect ratio calculators and below table gives the height and width some of the applications can use that an preserve the 16:9 aspect ratio. 

320x180(16:9)   
320x240 (4:3)

352x19816:9)   
352x264(4:3)

there is a nice calculator available to do this easily and the links are below 

http://size43.com/jqueryVideoTool-4x3.html


References



Wednesday, June 10, 2015

Touch ID integration in iOS few notes

When integrating the touch ID, found that it takes a lot of time to return back from the authentication success state. Below code was added to mitigate this. The main part was the dispatch_async(dispatch_get_main_queue() in the success block. 

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
    
    [myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
              localizedReason:myLocalizedReasonString
                        reply:^(BOOL success, NSError *error) {
     
     if (success) {
     // User authenticated successfully, take appropriate action
     dispatch_async(dispatch_get_main_queue(), ^{
                    // write all your code here
                    });
     } else {
     // User did not authenticate successfully, look at error and take appropriate action
     }
     
     }];
} else {
    // Could not evaluate policy; look at authError and present an appropriate message to user
}


Another item that left out of notice was the use of “Enter password”. When clicking on Enter password on the popup, it calls back with any of the below errors depending on the scenario


case UserCancel
case UserFallback
case SystemCancel
case PasscodeNotSet
case TouchIDNotAvailable
case TouchIDNotEnrolled
case TouchIDLockout
case AppCancel

appliation can then redirect to an existing password text field within the app possibly 

References: