Salesforce1 Lightning

Once again the annual Dreamforce event has been and gone leaving most practitioners with an uncomfortable knowledge deficit in terms of the real detail of the wealth of new innovations announced. This autumn period, post-Dreamforce, is often a time for investigation; piecing together information gathered from press releases, blog post, social media and event session replays.

This post provides the output of my own brief investigations into the Salesforce1 Lightning announcement. Note, I may be vague or incorrect in some areas, I have made assumptions (safe I hope).

Salesforce1 Lightning – What is it?
Salesforce1 Lightning is the next generation of the Salesforce1 Platform, it is framed specifically as a platform-as-a-service (PaaS) play and heralded as the world’s number 1. The platform is comprised of a number of new and re-branded technologies that collectively target the rapid delivery of cross-device, responsive applications via clicks-not-code. Responsive in this context relating to dynamic components that adapt their layout to the viewing environment, to provide an optimised viewing experience, regardless of the dimensions (i.e. a single view layer that supports desktop computers, smartphones, tablets and wearables).

Salesforce1 Lightning – Key Features
– Lightning Framework (GA now)
Saleforce developed UI framework for rapid web application development based on the single-page model, loosely coupled components and event-driven programming. The underlying Aura Framework was open-sourced last year and is used internally by Salesforce for the development of Salesforce1 plus recently introduced platform functionality (Opportunity Splits UI etc.). The Lightning Framework represents the availability of a subset of the Aura Framework functionality as a platform service for custom application development.

– Lightning Components (beta now, GA Spring 2015)
In order to build with the Salesforce1 Lightning Framework we need components. Components represent cleanly encapsulated units of functionality from which user interactions are comprised (i.e. apps). Component communication is supported by an event-based-architecture.

Standard Components – e.g. Button, Report Chart, Chatter Feed. Standard Components enable custom applications to be composed that inherit the Lightning UI (meaning the Salesforce1 UI).

Custom Components. Using the Lightning Component Framework, custom components can be developed to deliver any required experience (style, branding, function etc.). Developers build components with predominantly client-side behaviours, Apex can be employed to provide server-side controller functionality.

AppExchange Component. 3rd party commercial components installed from the AppExchange.

– Lightning App Builder (beta Spring 2015)
As the name implies the App Builder enables application composition through the drag-and-drop of components – meaning no-code. The builder provides Desktop, Laptop, Tablet, Phone and Smart Watch views onto which optimal component layouts are configured – the responsive behaviour to the components themselves therefore applies within the device type view – this makes good sense as an optimal laptop experience is not the phone view with proportionally bigger components. This approach is commonplace, wix.com for example works this way – i.e. build a generic device type specific view with components that adjust to the device specific viewing environment.

– Lightning Process Builder (GA Spring 2015)
Re-branded Force.com Flow / Visual Workflow functionality. In this context the point being that the business process logic is configurable through a drag-and-drop visual tool. Edit: my assumption here in relation to re-branding may well be incorrect, it has been suggested that the tool is in fact a distinct technology from Force.com Flow and may coexist. I’ll update this when I understand more – the functional overlap between Force.com Flow and Process Builder looks to be significant.

– Lightning Schema Builder (GA now)
Re-branded Schema Builder functionality. In this context the point being that the data schema is open to visual (i.e. drag-and-drop) manipulation.

– Lightning Connect (GA now)
Re-branded Platform Connect, or External Objects. The ability to configure virtual objects that query external data sources in real-time via the OData protocol. Connect underpins the concept of real-time external data access via the Salesforce1 platform and its constituent mobile applications.

– Lightning Community Builder (beta now, GA Spring 2015)
As the name implies a drag-and-drop tool for the configuration of Salesforce Communities plus the content delivered.

Entry Points
Salesforce1 Lightning Components can be accessed in the following ways.

Standalone App – access via /NAMESPACE/APPNAME.app
Salesforce1 Mobile App Tabs – create a Tab linked to a Lightning Component and add to the Mobile Navigation Menu.
Salesforce1 Mobile App Extensions – currently in Pilot, a means by which custom components can override standard components.

Future – All Visualforce entry points should ultimately become options for Lightning Components. This one is definitely an assumption. Standard components with which exhibit the standard Salesforce (Aloha) styling would be required for this.

Considerations
The following list represents some initial thoughts regarding the significance of Salesforce1 Lightning – formed without the insight gained through practical experience.

– Mobile-first.
The design principle is simple, the most effective way to build compelling user experiences across multiple devices is to start with the simplest (or perhaps smallest) case, i.e. the mobile. Note, the introduction of wearables possibly invalidates this slightly. The alternate approach of trying to shoe-horn complex desktop experiences onto smaller viewing environments rarely produces anything worthwhile.

– Rapid Development.
Quickly, faster, speed-of-business plus various other speed-related adverbs litter the press releases for Salesforce1 Lightning. If the name itself isn’t sufficient to highlight this, the platform is all about rapid development. In context rapid is realised by configuration-over-code; assembling apps with pre-fabricated, road-tested components delivers the shortest development cycle. That said, regardless of whatever form development takes a development lifecycle is absolutely necessary – the vision of analysts configuring apps over lunch and releasing immediately to business users is prone to disaster; I don’t believe this to be the message of Salesforce1 Lightning however.

– Technical Barriers versus Organisational Friction.
Removing technical barriers to rapid application development is only one part of the equation, organisations need to be culturally ready to embrace and therefore benefit from such agility. Building an enterprise app in a week makes little sense if it takes 3 months for acceptance, approval and adoption processes to run. The concept of turning IT departments into centres of innovation is an incredibly powerful aspiration, however this relies heavily on empowerment, trust and many other agile principles some organisations struggle with.

– Development model.
The Lightning development model is fully consistent with the age-old Salesforce philosophy of rapid declarative development via pre-fabricated componentry. Application architects, admins, analysts etc. assemble the apps with components supplied by Salesforce, built in-house or procured from the AppExchange. Developers will therefore focus more on building robust and reusable components than actual applications – which makes good sense assuming appropriate skills are applied to component specification and application design. The model requires non-technical resource to adopt a development mindset, this may be problematic for some.

– Developer Skills.
To build with the Salesforce1 Lightning Component Framework developers must be proficient in JavaScript, beyond intermediate level in my view. Lightning is a comprehensive component-based client-server UI framework with an event driven architecture. Developers with previous exposure limited to basic JavaScript augmentations to Visualforce face a learning curve. Anyone still under the false impression that JavaScript programming is simple compared to languages such as Java, C, C++ etc. may want to reconsider this before embarking on a Lightning project.

– Use Cases.
The viability of the proposed development model may ultimately come down to the complexity of the use cases/user experiences that can be supported without reverting to custom component development. By their very nature mobile interactions should be simplistic, but for desktop interactions it will be interesting to understand the scope of the potential for complex applications.

– Adoption.
Salesforce1 Lightning follows a similar paradigm to both Site.com and Force.com Flow, where historically technically oriented tasks are made possible for non-technical users; drag and drop visual composition of business process realisations and interactive web site development respectively. Both technologies, as innovative and empowering as they are, do not appear to have radically changed the development models to which they pertain. An obvious question therefore is whether the empowering technology alone is enough to drive adoption.

References
Aura Documentation Site
Lightning Components Developer’s Guide
Lightning QuickStart

Salesforce Application Types

In a typical development process requirements are captured and the information synthesised to form a solution design. The constituent components of the solution design are ultimately translated into physical concepts such as a class, page or sub-page view. This analysis, design, build cycle could be iterative in nature or fixed and may have different degrees of detail emerging at different points, however the applied principle is consistent. In considering the design element of the cycle, interaction design techniques suggest a patterns-based approach where features are mapped to a limited set of well-defined and robust user interface patterns, complemented by policies for concepts that transcend the patterns such as error handling, validation messages, stylistic aspects (fonts, dimensionality etc.). This process delivers efficiency in terms of reusability of code and reduced technical design and testing, but also critically provides a predictable, consistent end-user experience. When building custom applications using the declarative tools, we gain all of these advantages using pre-defined patterns and pre-fabricated building blocks. When building using the programmatic aspects of the platform a similar approach should be taken, meaning follow established patterns and use as much of the pre-fabricated components as possible. I can never fathom the driver to invent bespoke formats for pages that display within the standard UI, the end result is jarring for the end-user and expensive to build and maintain. In addition to delivering a consistent, predicative end-user experience at the component level, the containing application itself should be meaningful and appropriate in type. This point is becoming increasingly more significant as the range of application types grows release-on-release and the expanding platform capabilities introduce relevance to user populations outside of the front-office. The list below covers the application types possible at the time of writing (Spring ’14).

Standard Browser App
Standard Browser App (Custom UI)
Console (Sales, Service, Custom)
Subtab App
Community (Internal, External, Standard or Custom UI)
Salesforce1 Mobile
Custom Mobile App (Native, Hybrid, browser-based)
Site.com Site
Force.com Site

An important skill for Salesforce implementation practitioners is the accurate mapping of required end user interactions to application types within an appropriate license model. This is definitely an area where upfront thinking and a documented set of design principles is necessary to deliver consistency.

By way of illustration, the following exemplar design principles strive to deliver consistency across end user interactions.

1. Where the interaction is simple, confined to a single User, the data relates to the User and is primarily modifiable by the User only and has no direct business relevance then a Subtab App (Self) is appropriate. Examples: “My Support Tickets”, “Work.com – Recognition”.
2. Where a grouping of interactions form a usage profile that requires streamlined, efficient navigation of discrete, immersive, process centric tasks then a Console app is appropriate. Examples: “IT Helpdesk”, “Account Management”
3. Where a grouping of interactions from a usage profile that is non-immersive, non-complex (i.e. aligned with the pattern of record selection and view/edit) and likely to be conducted on constrained devices then Salesforce1 Mobile is appropriate. Examples: “Field Sales”, “Executive Insight”.

Design principles should also provide a strong definition for each application type covering all common design aspects to ensure consistency. For example, all Subtab apps should be built the same way technically, to the same set of standards, and deliver absolute consistency in the end user experiences provided.

Salesforce1 App Customisation

At the time I started writing this post we were living in a Chatter Mobile world, this is no longer the case. As announced recently at Dreamforce ’13 we have entered the Salesforce1 era, the direction of which will no doubt become clearer as we transition to the Spring ’14 release. What is clear now however is that the unified platform is the focus this time, providing mobile enablement (apps) via a rich set of platform services (APIs x 10). A rich set of robust APIs is always great news for any development community, whether you’re connecting a mobile device or sensor device (IoT). I won’t venture further into what Salesforce1 is in concept or the implications, some of this is yet to be seen. In any case this blog is focused on the practical application of the Salesforce and Force.com technologies, and as such the following summary is a point-in-time outline of the information available at the time of writing.

So, on to the topic in hand, customisation options for the Salesforce1 mobile application.

As with most things in life, to make good design decisions it helps to understand the full set of options available (and to see the big picture). This obvious point is fundamental in architecting Salesforce platform solutions; it’s key to have knowledge of the complete standard feature set and extension points (declarative build model) such that technical solution components are minimised. Simply put, in the mobile context this guiding principle means exhaust the potential of the standard apps (meaning Salesforce1) and the customisation options before building a new custom mobile app from scratch.

The following summary notes attempt to clarify the function of the Salesforce1 app and the various customisation options.

The Salesforce1 App – What is it?
In application development terms the Salesforce1 app provides a flexible mobile container into which a blend of standard and custom functionality can be presented on a variety of connected devices (mobile, tablet etc.). The container itself comes in 2 forms; downloadable native app (iOS and Android) and mobile browser app. In either form Salesforce1 employs a feed-first paradigm, with publisher actions and a notification platform. The mobile browser app must be enabled from the setup menu under Mobile Administration->Salesforce1 and becomes the default when accessing Salesforce from supported devices (as-per Salesforce Touch). Salesforce1 does not replace the standard Salesforce web app, or Full Site as it is referred. Salesforce1 does replace Salesforce Touch, Chatter Mobile and Salesforce mobile apps.

Ok, so assuming we’re comfortable with the idea that Salesforce1 is a application container, how can we extend the functionality of the container to deliver custom application interactions?

Customisation Options
The following summary notes attempt to clarify the customisation options available with the Salesforce1 mobile app. Also included in the list are standard capabilities of the container app, provided for completeness. The Salesforce1 App Development Guide provides a comprehensive coverage of the topics including example code that can be loaded into a development org (via github) to experiment with.

— Mobile Navigation
Within the setup menu under Mobile Administration, the Mobile Navigation option provides the ability to define the content and structure of the left hand side menu of the container app (as shown in the screenshot below).

Salesforce1 Tablet

Note. The first item in the list becomes the home page.

— Custom Objects (declarative)
Self explanatory. Recently searched for objects appear under the Recent section in the mobile menu structure according to profile permissions. It would appear that page layouts are shared between Salesforce1 and the standard Salesforce web app. This may prove difficult in terms of providing a balanced structure that is effective in both views.

— Flexible Page Tabs (declarative and technical)
I’m not 100% clear on the use cases for Flexible pages, however they do exist and can be added to Flexible page Tabs and ultimately rendered in the container app via inclusion in the menu structure (via Mobile Navigation). I need to do some further investigation into the potential of Flexible Pages, perhaps I’m missing something obvious.

A Flexible Page can have global publisher actions, list views and scoped recently used items. A maximum of 25 components can be added to the page, this constraint applies to listviews and recently used items.

In terms of definition a Flexible page is manually created in XML and deployed to an org via the Force.com Migration Tool or IDE. Once a Flexible page exists in an org the Create->Tabs page will present a Flexible Page Tabs list (as per Visualforce tabs etc.).

— Publisher Actions (declarative and technical)
Publisher actions are accessed via the (+) button on the home page, Chatter tab, Chatter group and record detail pages.

Actions can be Standard or Custom and Global or Object scoped.

Standard actions include;
Create a Record – respects Validation Rules etc. A Create action defined for a object will automatically relate created child records.
Log a Call – record a completed Task
Update – update a record from the Chatter feed

Default standard actions are provided for the core standard objects (create and update), such actions have configurable layouts and the ability to predefine field values.

Custom actions include;
Visualforce pages
Canvas apps

Interestingly actions can be described and invoked via the REST API, resource paths below.
/services/data/v29.0/quickActions (Global)
/services/data/v29.0/sobjects/[object]/quickActions (Object)

— Compact Layouts (declarative)
Compact layouts are defined at the object level and are simply an ordered list of fields by definition. Compact layouts apply in the following areas;

Record highlights fields (first 4 fields in the ordered field list). The record highlights are displayed in the top region of a record detail display under the icon.
Defines the fields that appear in the Chatter feed if a record us created via publisher action.
Enhanced lookup mobile card (more on this below)
Object record preview card

— Mobile Cards (declarative)
Page layouts now have a section for Mobile Cards, the following items can be added which then appear as a swipe-to card within the record detail view within the Salesforce1 app only.

Visualforce Page
Expanded Lookup. Related object (via Lookup) Custom Layout fields are displayed.

— Visualforce Pages (technical)
There are a number of extension points within the Salesforce1 app where Visualforce pages can be employed.

Mobile Card
Custom Publisher Action
Visualforce Tab added to the Mobile Navigation

In all cases the page must be mobile enabled and designed specifically for rendering on constrained devices, i.e mobile plus tablet on a variety of form factors. A best practice to consider in this respect is the development of adaptable pages that support both Salesforce1 and standard Salesforce web app execution. There are 3 development models in this respect classic Visualforce, Visualforce mixed with JavaScript, JavaScript and static HTML only with JS remoting. In all models the recently added (to Visualforce) ability to pass through attributes (HTML5) will be of use. Additionally, Salesforce1 comes with a highly useful navigation framework JavaScript library.

In short, where branded or complex UI interactions are required Visualforce provides a good option. Such pages must be carefully designed to deliver a optimal mobile experience and where possible be adaptable to also work in the standard Salesforce web app. This latter point relates to the cost of development and maintenance, adaptability is better than duplication – at the cost of smart design.

— Force.com Canvas Apps (technical)
There are a number of extension points within the Salesforce1 app where Force.com Canvas apps can be employed. Pilot program currently.

Custom Publisher action – post to the feed from a Canvas app
Chatter Feed – Canvas app rendered in a feed item

The use cases for the above will be varied and no doubt very interesting. Over time I think we’ll see more traction in the area of application composition. The ability to compose experiences and interactions across applications seamlessly (with context) and securely is a powerful concept.

— Smart Search Items
Recently searched for objects for the user. Searches performed in the full web app appear can appear In the left navigation menu, pin objects in the full site to keep at the top of this list.

— Notifications (declarative)
The Salesforce1 notifications platform supports 2 types of notification;

In App – Appear in the app itself and can be accessed manually via the bell icon (top right hand corner)
Push – Mobile device applications only, push notifications not supported by the mobile browser app. Such notifications will appear as badges on the app icon etc.

The notifications are limited to Chatter (mentions, posts, comments etc.) and Approval requests. Notifications are enabled at the org-level, not per-user.

Final Thoughts
In application development terms, Salesforce1 provides a rich set of declarative and programmatic techniques for the development of mobile interactions. Building out compelling mobile experiences that replace or augment existing Saleforce functionality (custom or standard) should be highly achievable whether you’re technically minded or not. This in my view is the real power of the Saleforce1 app, once you accept the proprietary approach there are no barriers to rapid mobile enablement.

Two-Factor Authentication

Winter ’14 introduces two-factor authentication (2FA) for both User Interface and API logins, a long-awaited security feature enabled through User Profile, or Permission Set. The relevant permissions are:

Two-Factor Authentication for User Interface Logins
Two-Factor Authentication for API Logins

The second factor in question being a time-based token generated by a Salesforce supplied, device specific authenticator app (something similar to the RSA SecurID soft-token mobile app I would expect).

User Interface Login

For User Interface logins the authentication process is shown in the screenshot below. A Salesforce generated code is entered (or scanned via QR Code) into the authenticator app which generates the 6-digit time-based token to authenticate with. At the time of writing the authenticator app download link redirects to salesforce.com/mobile path, so the end-to-end process can’t be tested as yet.

auth_time_based_token_entry

API Login

Two-factor authentication for User Interface logins is a pre-requisite for API logins. In this context the time-based token replaces the standard security token in the API login call.

The time-based token is generated via the mobile authenticator app and added to a field on the User record, as shown below.

user_time_vased_token_input

Identity Confirmation
Time-based tokens can also be used during login verification to activate a computer/device.

I’ll update this post once the authenticator apps become available and the end to end process can be tested. I need to do some investigation also into the specifics of the persisted tokens (how long-lived are they etc.?).

Update 2013-10-23
I notice that the authenticator app information is at the bottom of the salesforce.com/mobile page. Instead of providing a proprietary approach the commonly used Google Authenticator service and related apps are used. iOS screenshot below.

photo

For more information on Google Authenticator refer to here and here.

Salesforce Analytics API

With Winter ’14 the new Analytics API turns GA. This RESTful style of API consumes standard API call limits, uses OAuth authentication and JSON request/response message formats (representations).

The key functionality of the Analytics API is the execution of reports (in synchronous or asynchronous modes), the application of dynamic filtering and the inspection of report metadata.

Note, in experimenting/testing any of the RESTful APIs (Force.com REST API, Chatter REST API, Analytics API etc.) the Apigee Salesforce API Consoles are an extremely convenient and useful tool – screenshot below.

apigee_screenshot

Core API Resources

– Report metadata (GET /services/data/v29.0/analytics/reports/report_ID/describe)

– List recently viewed reports (GET /services/data/v29.0/analytics/reports/list)
Note to obtain a full list of reports the standard REST API should be used to query the Report resource (via Soql).

– Synchronous report execution (/services/data/v29.0/analytics/reports/report_ID)
GET for a simple execution (add includeDetail=true to the Querystring if required)
POST to apply filtering.

– Asynchronous report execution (/services/data/v29.0/analytics/reports/report_ID/instances) – POST to request an execution.
GET to retrieve a list of the execution instances.
GET to the ../instances/instance_ID to request the results of a single execution.

– Fact Maps
The JSON message format for a report execution, synchronous or asynchronous, provides the detail and summary data in a Fact Map structure. In short, the keys provided in the structured groupings (across and down) data provided in the embedded report metadata are concatenated to provide a composite lookup key to detail row (hasDetailRows response flag indicates the existence of detail rows) and aggregate data held in the data map.

For more on Fact Maps refer to the “Decode the Fact Map” section in the Analytics API Reference.

Use Cases
The Analytics API is a long awaited key enabler for mobile/tablet analytics use cases, allowing on-platform reports to be executed and the results accessed in a constrained-device friendly lightweight format. Without this API mobile app developers have been limited to the execution of Soql queries via the standard REST API. With the API such developers have access to the recently viewed reports for a specific user, the report metadata, the ability to execute reports and then to pass the report results up to the graphics library of choice using a standard data format.

Outside of the mobile context, the API offers the same patterns to composite applications such as complementary web applications and 3rd party tools where datasets can be defined on-platform using reports (by end-users perhaps) and the data picked up for services such as mass email marketing etc.

Key Limitations
– 500 synchronous report executions per hour
– 1200 synchronous report execution requests per hour
– Asynchronous report results are available for 24 hours from execution

Report Response Example – Matrix Report

HTTP/1.1 200 OK
Sforce-Limit-Info:api-usage=21/5000000
Date:Sat, 28 Sep 2013 18:30:16 GMT
Content-Length:8705
Content-Type:application/json;charset=UTF-8

{
  "hasDetailRows": false,
  "attributes": {
    "describeUrl": "/services/data/v29.0/analytics/reports/00O300000041iFQEAX/describe",
    "instancesUrl": "/services/data/v29.0/analytics/reports/00O300000041iFQEAX/instances",
    "type": "Report",
    "reportId": "00O300000041iFQEAX",
    "reportName": "Example Report"
  },
  "groupingsDown": {
    "groupings": [
      {
        "value": "001Q000000PUcCtIAX",
        "key": "0",
        "groupings": [
          {
            "value": "2013-08-28",
            "key": "0_0",
            "groupings": [],
            "label": "2013/08/28 - 2013/09/03"
          }
        ],
        "label": "New Business"
      },
      {
        "value": "001Q000000Q0wLMIAX",
        "key": "1",
        "groupings": [
          {
            "value": "2013-09-18",
            "key": "1_0",
            "groupings": [],
            "label": "2013/09/18 - 2013/09/24"
          }
        ],
        "label": "Existing Business"
      },
      {
        "value": "001Q000000OwobqIAX",
        "key": "2",
        "groupings": [
          {
            "value": "2013-07-31",
            "key": "2_0",
            "groupings": [],
            "label": "2013/07/31 - 2013/08/06"
          }
        ],
        "label": "Prospects"
      }
    ]
  },
  "groupingsAcross": {
    "groupings": [
      {
        "value": "Product Sales",
        "key": "0",
        "groupings": [
          {
            "value": "a0AQ00000054Q0uMAX",
            "key": "0_0",
            "groupings": [],
            "label": "Product A"
          },
          {
            "value": "a0AQ0000004YV8xMAX",
            "key": "0_1",
            "groupings": [],
            "label": "Product B"
          }
        ],
        "label": "Product Sales"
      },
      {
        "value": "Services",
        "key": "1",
        "groupings": [
          {
            "value": "a0AQ0000005G0OpMAX",
            "key": "1_0",
            "groupings": [],
            "label": "Service A"
          }
        ],
        "label": "Services"
      }
    ]
  },
  "reportMetadata": {
    "name": "Example Report",
    "id": "00O300000041iFQEAX",
    "aggregates": [
      "RowCount"
    ],
    "groupingsDown": [
      {
        "name": "Client__c.Name",
        "sortOrder": "Asc",
        "dateGranularity": "None"
      },
      {
        "name": "Projection__c.Date__c",
        "sortOrder": "Asc",
        "dateGranularity": "Week"
      }
    ],
    "groupingsAcross": [
      {
        "name": "MyProduct__c.Classification__c",
        "sortOrder": "Asc",
        "dateGranularity": "None"
      },
      {
        "name": "MyProduct__c.Name",
        "sortOrder": "Asc",
        "dateGranularity": "None"
      }
    ],
    "reportType": {
      "type": "MyProduct_CRT__c",
      "label": "My Product CRT"
    },
    "reportBooleanFilter": null,
    "reportFilters": [],
    "detailColumns": [],
    "reportFormat": "MATRIX",
    "currency": null,
    "developerName": "Example_Report"
  },
  "factMap": {
    "1_0!T": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "0!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!T": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "0!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0!0_1": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "1!1": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "T!1": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "1!0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2_0!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2_0!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!0": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "2_0!0_0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "T!0": {
      "aggregates": [
        {
          "value": 7,
          "label": "7"
        }
      ]
    },
    "1_0!1_0": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "2_0!0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "2_0!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1_0!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1_0!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "T!1_0": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "0!0": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "1_0!1": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "1_0!0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!0_0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "0_0!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!0_1": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "2!0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "T!T": {
      "aggregates": [
        {
          "value": 8,
          "label": "8"
        }
      ]
    },
    "0!T": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "1!T": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "2!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!T": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "T!0_0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "1!1_0": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "T!0_1": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "2_0!T": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "0_0!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    }
  },
  "allData": true
}

Salesforce Touch Platform Guide

The newly released Salesforce Touch Platform Guide provides a very useful consolidation of both technical information and design guidance pertinent to mobile development on the Force.com platform. Topics covered include Identity, Connected Apps, Mobile Components for Visualforce etc. All in all an essential read for anyone considering mobile app development.

Of particular interest is the content related to the Hybrid model of mobile application development (chapter 6 & 7), combining the benefits of native app development, i.e. on-device integration (Contacts, Calendar, local storage etc.), with the rapid development and ease of update of HTML5 development and web apps.

Visualforce User Agent Detection

The code below provides an example of a page action method used to detect a mobile user-agent and perform redirection. Alternatively the same approach could be used with dynamic Visualforce components to switch between mobile/web optimised page composition.

	public PageReference redirectDevice(){
		String userAgent = ApexPages.currentPage().getHeaders().get('USER-AGENT');
		
		//& some devices use custom headers for the user-agent.
		if (userAgent==null || userAgent.length()==0){
			userAgent = ApexPages.currentPage().getHeaders().get('HTTP_X_OPERAMINI_PHONE_UA');
		}		
		if (userAgent==null || userAgent.length()==0){
			userAgent = ApexPages.currentPage().getHeaders().get('HTTP_X_SKYFIRE_PHONE');
		}
		 		
  		//& replace with custom setting - using (?i) case insensitive mode.		
		String deviceReg = '(?i)(iphone|ipod|ipad|blackberry|android|palm|windows\\s+ce)';
		String desktopReg = '(?i)(windows|linux|os\\s+[x9]|solaris|bsd)';
		String botReg = '(?i)(spider|crawl|slurp|bot)';
		
		Boolean isDevice=false, isDesktop=false, isBot=false;
		
		Matcher m = Pattern.compile(deviceReg).matcher(userAgent);
		if (m.find()){
			isDevice = true;
		} else {
			//& don't compile the patterns unless required.
			m = Pattern.compile(desktopReg).matcher(userAgent);
			if (m.find()) isDesktop = true;
			
			m = Pattern.compile(botReg).matcher(userAgent);
			if (m.find()) isBot = true;
		}
		//& Default is mobile - unless a desktop or bot user-agent identified.					
		if (!isDevice && (isDesktop || isBot)) return null; //& no redirect.						
		return new PageReference('/apex/MobileIndex'); //& redirect.
	}