Adobe CQ 5.5 - Mobile Improvements

22 March 2012
Jan Kuzniak
Frink_Cognifide_2016_HeaderImages_0117
I remember that gleam in the marketer's eyes when Investec demoed the first CQ5 mobile microsite at the Day Ignite 2010 Conference in Berlin. Everyone's minds were spinning somewhere along the lines of "I'll flip a switch and get a mobile site! Me wants!". The appetite and expectations were huge.

But on the other side of this beautiful postcard was sweat, tears and blood of developers working on a beta version of the new platform. That was a great challenge and thanks to the support of the Adobe guys (mostly Florian and Bertrand) - a great deal of fun. But then, a final version was released and while it all got tidied up, I was surprised to find some rough edges - mostly around the just added mobile module.

Problems with mobile detection

CQ5 uses the WURFL database with over 17,000 devices defined. Each request is matched against this database and assigned to a device group and along with it - an appropriate mobile view of the requested page. The detection and mapping part is where it gets tricky. WURFL provides over 500 capabilities for each device from which five used downstream: screen size, device rotation, images, CSS and JavaScript. Sure, we'd have liked to extend this input set, but it's hardcoded. One way around would be to specify a regular expression on user agent (there's support for that), but good luck matching all the touch phones out there in the market with it. Unfortunately, there was no way to expand the built-in detection mechanism and fully leverage WURFL capabilities.

When we started working on a full-blown mobile site and engaged with a mobile agency, we hit a wall. Did you know you need independent designs for devices with different input methods? Big buttons for touch phones, small for joystick based, and the list went on. To add to the fun, there are a lot of touch phones that don't support JavaScript properly and that you should consider separate template for tablet devices - rich-like desktop, but then again touch-based? The mobile agency guys could talk about these differences for hours and we were quickly convinced that we will easily end up with 23 templates, and that we need some smarter device detection.

 Adobe was challenged with those requirements, and it didn't take long to convince their architects to include our case on the product strategy roadmap. We worked on that together and soon after feature pack #36363 was released.

Salvation

There are two important things you must know about the mentioned feature pack.
 1 - it made it into the CQ 5.5 mobile module!
 2 - it allows you to extend mobile detection and fully leverage the WURFL database. In addition to the original 5 criteria, another filtering mechanism was added:
  • You can register your own filter (as an OSGi component) that will either let a request be assigned to a given mobile group, or deny it.
  • You can assign many filters to a mobile group and a request will be assigned to it only when all filters pass.
  • Inside a filter you have access to WURFL-mapped capabilities of the device that made the request.
That's it in a nutshell. Now, how do you implement it?

Step 1 - Implement the filter

First step is to implement your filter. It's done by exposing an OSGi component that implements the com.day.cq.wcm.mobile.api.device.DeviceGroupFilter interface. A key here is the matches method that provides the filter's logic: returning true means a device passes the filter. This method is executed on every request from a mobile device, and a map of WURFL capabilities is passed in a parameter. All you have to do now is to check WURFL documentation and find which WURFL capabilities you really need. The real life example below implements a simple touch filter that matches only phones and tablets with a touch screen. I used Felix SCR Annotations and maven-scr-plugin to generate OSGi metadata for the component.
package com.cognifide.simple.filters;

import java.util.Map;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;

import com.day.cq.wcm.mobile.api.device.DeviceGroup;
import com.day.cq.wcm.mobile.api.device.DeviceGroupFilter;

@Component
@Service
public class TouchFilter implements DeviceGroupFilter {

	@Override
	public String getDescription() {
		return "Includes mobile phones and tablets with touch screens";
	}

	@Override
	public String getTitle() {
		return "Touch screen devices";
	}

	@Override
	public boolean matches(DeviceGroup deviceGroup, String s,
			Map capabilities) {
		boolean isTouchScreen = isTouchScreen(capabilities);
		boolean isMobilePhone = isMobilePhone(capabilities);
		boolean isTablet = isTablet(capabilities);

		return isTouchScreen && (isMobilePhone || isTablet);
	}

	private boolean isTouchScreen(Map capabilities) {
		return "touchscreen".equals(capabilities.get("pointing_method"));
	}

	public boolean isMobilePhone(Map capabilities) {
		return "true".equals(capabilities.get("can_assign_phone_number"));
	}

	public boolean isTablet(Map capabilities) {
		return "true".equals(capabilities.get("is_tablet"));
	}
}

Step 2 - Assign the filter

With the touch filter implemented, let's use it in the pre-defined touch device group (/etc/mobile/groups/touch). Open the page, click the Edit button to fire the dialog and go to the Filters tab. Your filter should be already available in the drop-down - choose it instead of the default one and confirm. Since this filter implements all the touch-device logic you need, it's safe to get rid of the legacy logic. Yes, you can uncheck all capabilities from the first tab of the dialog.

CQ5 touch device group in WCM CQ5 device group filters dialog

If your filter is not there, double check how your bundle got installed in the OSGi console (/system/console/bundles). It should expose your filter as a service, and it should also be visible as a component of the same name (/system/console/components). If it's not - check your build / maven-scr-plugin.

Step 3 - Test and debug

With all that set, time to test if it works. In order to do that you need a publish instance with your touch group there (activate it from author) and have your code deployed. Get a touch phone, or a browser with custom user agent (e.g. Firefox with User Agent Switcher), or simply use cURL and pass touch phone's user agent as a parameter. Anything that makes a mobile request to your site works. Since we changed one of the default device groups, we can test it on the Geometrixx Mobile site: /content/geometrixx_mobile/en.html. If the filter works correctly, you should get redirected to en.touch.html for touch-device requests (e.g. iPhone, iPad), and to other group for non-touch devices (e.g. BlackBerry 9650).

If your device is not matching the desired group, don't despair. The mobile module has a very verbose debug log. I recommend you create a separate log file for that: just use com.day.cq.wcm.mobile for your filter. Hint: when debugging, we recommend using cURL, so that other requests (e.g. for .css) don't pollute your log.

Conclusion

With CQ 5.5, the mobile module gets a great boost. From a toy to play with in microsites, it has transformed into an extensible mobile solution. It may not be ideal - integrating with the legacy solution (capabilities ticks) seems awkward, and filters cannot be joined in advanced logical expressions (e.g. touch and not tablet; tablet or desktop). But even with all that, we can finally satisfy the marketers' hunger for mobile sites with minimal effort on the development side. Since it's no longer sweat and blood, I wouldn't be surprised to find more and more CQ5 sites going mobile very soon.

 Time to feed the marketeers.