diff --git a/wlauto/common/android/ApplaunchInterface.class b/wlauto/common/android/ApplaunchInterface.class
new file mode 100644
index 00000000..0bd8e053
Binary files /dev/null and b/wlauto/common/android/ApplaunchInterface.class differ
diff --git a/wlauto/common/android/BaseUiAutomation$1.class b/wlauto/common/android/BaseUiAutomation$1.class
index 5a216cc3..8298936c 100644
Binary files a/wlauto/common/android/BaseUiAutomation$1.class and b/wlauto/common/android/BaseUiAutomation$1.class differ
diff --git a/wlauto/common/android/BaseUiAutomation.class b/wlauto/common/android/BaseUiAutomation.class
index 2188bd5f..b20d2376 100644
Binary files a/wlauto/common/android/BaseUiAutomation.class and b/wlauto/common/android/BaseUiAutomation.class differ
diff --git a/wlauto/common/android/UiAutoUtils.class b/wlauto/common/android/UiAutoUtils.class
new file mode 100644
index 00000000..fb1da9af
Binary files /dev/null and b/wlauto/common/android/UiAutoUtils.class differ
diff --git a/wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class b/wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class
index d793d013..a62db9e1 100644
Binary files a/wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class and b/wlauto/common/android/UxPerfUiAutomation$GestureTestParams.class differ
diff --git a/wlauto/common/android/UxPerfUiAutomation$GestureType.class b/wlauto/common/android/UxPerfUiAutomation$GestureType.class
index 8cc30f68..fc2cf4d2 100644
Binary files a/wlauto/common/android/UxPerfUiAutomation$GestureType.class and b/wlauto/common/android/UxPerfUiAutomation$GestureType.class differ
diff --git a/wlauto/common/android/UxPerfUiAutomation.class b/wlauto/common/android/UxPerfUiAutomation.class
index 1be53c1f..016b784f 100644
Binary files a/wlauto/common/android/UxPerfUiAutomation.class and b/wlauto/common/android/UxPerfUiAutomation.class differ
diff --git a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/ApplaunchInterface.java b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/ApplaunchInterface.java
new file mode 100644
index 00000000..b53c7bb4
--- /dev/null
+++ b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/ApplaunchInterface.java
@@ -0,0 +1,54 @@
+
+/*    Copyright 2013-2016 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package com.arm.wlauto.uiauto;
+
+import android.os.Bundle;
+import android.util.Log;
+
+// Import the uiautomator libraries
+import com.android.uiautomator.core.UiObject;
+
+/**
+ * ApplaunchInterface.java
+ * Interface used for enabling uxperfapplaunch workload.
+ * This interface gets implemented by all workloads that support application launch
+ * instrumentation.
+ */
+
+public interface ApplaunchInterface {
+
+    /**
+     * Sets the launchEndObject of a workload, which is a UiObject that marks
+     * the end of the application launch.
+     */
+    public UiObject getLaunchEndObject();
+
+    /**
+     * Runs the Uiautomation methods for clearing the initial run
+     * dialogues on the first time installation of an application package.
+     */
+    public void runApplicationInitialization() throws Exception;
+
+    /**
+     * Provides the application launch command of the application which is
+     * constructed as a string from the workload.
+     */
+    public String getLaunchCommand();
+
+    /** Passes the workload parameters. */
+    public void setWorkloadParameters(Bundle parameters);
+}
diff --git a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java
index eb1e583b..1a234d52 100755
--- a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java
+++ b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/BaseUiAutomation.java
@@ -228,6 +228,9 @@ public class BaseUiAutomation extends UiAutomatorTestCase {
         UiDevice.getInstance().pressEnter();
     }
 
+    public void pressHome() {
+        UiDevice.getInstance().pressHome();
+    }
 
     public void pressBack() {
         UiDevice.getInstance().pressBack();
diff --git a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UiAutoUtils.java b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UiAutoUtils.java
new file mode 100644
index 00000000..35bebd03
--- /dev/null
+++ b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UiAutoUtils.java
@@ -0,0 +1,36 @@
+/*    Copyright 2013-2016 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package com.arm.wlauto.uiauto;
+
+import android.os.Bundle;
+import java.util.logging.Logger;
+
+public final class UiAutoUtils {
+    
+    /** Construct launch command of an application. */
+    public static String createLaunchCommand(Bundle parameters) {
+        String launchCommand;
+        String activityName = parameters.getString("launch_activity");
+        String packageName = parameters.getString("package");
+        if (activityName.equals("None")) {
+            launchCommand = String.format("am start %s", packageName);
+        } 
+        else {
+            launchCommand = String.format("am start -n %s/%s", packageName, activityName);
+        }
+        return launchCommand;
+    }
+}
diff --git a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java
index 10367015..68ec38fc 100644
--- a/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java
+++ b/wlauto/external/uiauto/src/com/arm/wlauto/uiauto/UxPerfUiAutomation.java
@@ -16,8 +16,19 @@
 package com.arm.wlauto.uiauto;
 
 import java.util.logging.Logger;
+import android.os.Bundle;
 
 public class UxPerfUiAutomation extends BaseUiAutomation {
+    
+    protected Bundle parameters;
+    protected String packageName;
+    protected String packageID;
+
+    //Get application package parameters and create package ID
+    public void getPackageParameters() {
+        packageName = parameters.getString("package");
+        packageID = packageName + ":id/";
+    }
 
     private Logger logger = Logger.getLogger(UxPerfUiAutomation.class.getName());
 
diff --git a/wlauto/instrumentation/fps/__init__.py b/wlauto/instrumentation/fps/__init__.py
index 54fb353d..9cadeebd 100755
--- a/wlauto/instrumentation/fps/__init__.py
+++ b/wlauto/instrumentation/fps/__init__.py
@@ -39,10 +39,9 @@ from wlauto.instrumentation import instrument_is_installed
 from wlauto.exceptions import (InstrumentError, WorkerThreadError, ConfigError,
                                DeviceNotRespondingError, TimeoutError)
 from wlauto.utils.types import boolean, numeric
-from wlauto.utils.fps import FpsProcessor, SurfaceFlingerFrame, GfxInfoFrame, GFXINFO_EXEMPT
+from wlauto.utils.fps import (FpsProcessor, SurfaceFlingerFrame, GfxInfoFrame, GFXINFO_EXEMPT,
+                              VSYNC_INTERVAL)
 
-
-VSYNC_INTERVAL = 16666667
 PAUSE_LATENCY = 20
 EPSYLON = 0.0001
 
diff --git a/wlauto/result_processors/uxperf.py b/wlauto/result_processors/uxperf.py
index ff9027f8..6221afde 100755
--- a/wlauto/result_processors/uxperf.py
+++ b/wlauto/result_processors/uxperf.py
@@ -14,17 +14,13 @@
 #
 
 import os
-import re
-import logging
-
-from collections import defaultdict
 from distutils.version import LooseVersion
+
 from wlauto import ResultProcessor, Parameter
 from wlauto.instrumentation import instrument_is_enabled
-from wlauto.instrumentation.fps import VSYNC_INTERVAL
 from wlauto.exceptions import ResultProcessorError, ConfigError
-from wlauto.utils.fps import FpsProcessor, SurfaceFlingerFrame, GfxInfoFrame
 from wlauto.utils.types import numeric, boolean
+from wlauto.utils.uxperf import UxPerfParser
 
 try:
     import pandas as pd
@@ -77,6 +73,7 @@ class UxPerfResultProcessor(ResultProcessor):
     ]
 
     def initialize(self, context):
+        # needed for uxperf parser
         if not pd or LooseVersion(pd.__version__) < LooseVersion('0.13.1'):
             message = ('uxperf result processor requires pandas Python package '
                        '(version 0.13.1 or higher) to be installed.\n'
@@ -101,161 +98,3 @@ class UxPerfResultProcessor(ResultProcessor):
         if self.add_frames:
             self.logger.debug('Adding per-action frame metrics')
             parser.add_action_frames(framelog, self.drop_threshold, self.generate_csv)
-
-
-class UxPerfParser(object):
-    '''
-    Parses logcat messages for UX Performance markers.
-
-    UX Performance markers are output from logcat under a debug priority. The
-    logcat tag for the marker messages is UX_PERF. The messages associated with
-    this tag consist of a name for the action to be recorded and a timestamp.
-    These fields are delimited by a single space. e.g.
-
-    <TAG>   : <MESSAGE>
-    UX_PERF : gestures_swipe_left_start 861975087367
-    ...
-    ...
-    UX_PERF : gestures_swipe_left_end 862132085804
-
-    Timestamps are produced using the running Java Virtual Machine's
-    high-resolution time source, in nanoseconds.
-    '''
-    def __init__(self, context):
-        self.context = context
-        self.actions = defaultdict(list)
-        self.logger = logging.getLogger('UxPerfParser')
-        # regex for matching logcat message format:
-        self.regex = re.compile(r'UX_PERF.*?:\s*(?P<message>.*\d+$)')
-
-    def parse(self, log):
-        '''
-        Opens log file and parses UX_PERF markers.
-
-        Actions delimited by markers are captured in a dictionary with
-        actions mapped to timestamps.
-        '''
-        loglines = self._read(log)
-        self._gen_action_timestamps(loglines)
-
-    def add_action_frames(self, frames, drop_threshold, generate_csv):  # pylint: disable=too-many-locals
-        '''
-        Uses FpsProcessor to parse frame.csv extracting fps, frame count, jank
-        and vsync metrics on a per action basis. Adds results to metrics.
-        '''
-        refresh_period = self._parse_refresh_peroid()
-
-        for action in self.actions:
-            # default values
-            fps, frame_count, janks, not_at_vsync = float('nan'), 0, 0, 0
-            p90, p95, p99 = [float('nan')] * 3
-            metrics = (fps, frame_count, janks, not_at_vsync)
-
-            df = self._create_sub_df(self.actions[action], frames)
-            if not df.empty:  # pylint: disable=maybe-no-member
-                fp = FpsProcessor(df, action=action)
-                try:
-                    per_frame_fps, metrics = fp.process(refresh_period, drop_threshold)
-                    fps, frame_count, janks, not_at_vsync = metrics
-
-                    if generate_csv:
-                        name = action + '_fps'
-                        filename = name + '.csv'
-                        fps_outfile = os.path.join(self.context.output_directory, filename)
-                        per_frame_fps.to_csv(fps_outfile, index=False, header=True)
-                        self.context.add_artifact(name, path=filename, kind='data')
-
-                    p90, p95, p99 = fp.percentiles()
-                except AttributeError:
-                    self.logger.warning('Non-matched timestamps in dumpsys output: action={}'
-                                        .format(action))
-
-            self.context.result.add_metric(action + '_FPS', fps)
-            self.context.result.add_metric(action + '_frame_count', frame_count)
-            self.context.result.add_metric(action + '_janks', janks, lower_is_better=True)
-            self.context.result.add_metric(action + '_not_at_vsync', not_at_vsync, lower_is_better=True)
-            self.context.result.add_metric(action + '_frame_time_90percentile', p90, 'ms', lower_is_better=True)
-            self.context.result.add_metric(action + '_frame_time_95percentile', p95, 'ms', lower_is_better=True)
-            self.context.result.add_metric(action + '_frame_time_99percentile', p99, 'ms', lower_is_better=True)
-
-    def add_action_timings(self):
-        '''
-        Add simple action timings in millisecond resolution to metrics
-        '''
-        for action, timestamps in self.actions.iteritems():
-            # nanosecond precision, but not necessarily nanosecond resolution
-            # truncate to guarantee millisecond precision
-            ts_ms = tuple(int(ts) for ts in timestamps)
-            if len(ts_ms) == 2:
-                start, finish = ts_ms
-                duration = finish - start
-                result = self.context.result
-
-                result.add_metric(action + "_start", start, units='ms')
-                result.add_metric(action + "_finish", finish, units='ms')
-                result.add_metric(action + "_duration", duration, units='ms', lower_is_better=True)
-            else:
-                self.logger.warning('Expected two timestamps. Received {}'.format(ts_ms))
-
-    def _gen_action_timestamps(self, lines):
-        '''
-        Parses lines and matches against logcat tag.
-        Groups timestamps by action name.
-        Creates a dictionary of lists with actions mapped to timestamps.
-        '''
-        for line in lines:
-            match = self.regex.search(line)
-
-            if match:
-                message = match.group('message')
-                action_with_suffix, timestamp = message.rsplit(' ', 1)
-                action, _ = action_with_suffix.rsplit('_', 1)
-                self.actions[action].append(timestamp)
-
-    def _parse_refresh_peroid(self):
-        '''
-        Reads the first line of the raw dumpsys output for the refresh period.
-        '''
-        raw_path = os.path.join(self.context.output_directory, 'surfaceflinger.raw')
-        if os.path.isfile(raw_path):
-            raw_lines = self._read(raw_path)
-            refresh_period = int(raw_lines.next())
-        else:
-            refresh_period = VSYNC_INTERVAL
-
-        return refresh_period
-
-    def _create_sub_df(self, action, frames):
-        '''
-        Creates a data frame containing fps metrics for a captured action.
-        '''
-        if len(action) == 2:
-            start, end = map(int, action)
-            df = pd.read_csv(frames)
-            # SurfaceFlinger Algorithm
-            if df.columns.tolist() == list(SurfaceFlingerFrame._fields):  # pylint: disable=maybe-no-member
-                field = 'actual_present_time'
-            # GfxInfo Algorithm
-            elif df.columns.tolist() == list(GfxInfoFrame._fields):  # pylint: disable=maybe-no-member
-                field = 'FrameCompleted'
-            else:
-                field = ''
-                self.logger.error('frames.csv not in a recognised format. Cannot parse.')
-            if field:
-                df = df[start < df[field]]
-                df = df[df[field] <= end]
-        else:
-            self.logger.warning('Discarding action. Expected 2 timestamps, got {}!'.format(len(action)))
-            df = pd.DataFrame()
-        return df
-
-    def _read(self, log):
-        '''
-        Opens a file a yields the lines with whitespace stripped.
-        '''
-        try:
-            with open(log, 'r') as rfh:
-                for line in rfh:
-                    yield line.strip()
-        except IOError:
-            self.logger.error('Could not open {}'.format(log))
diff --git a/wlauto/utils/fps.py b/wlauto/utils/fps.py
index 84016622..735be824 100755
--- a/wlauto/utils/fps.py
+++ b/wlauto/utils/fps.py
@@ -29,6 +29,8 @@ GfxInfoFrame = collections.namedtuple('GfxInfoFrame', 'Flags IntendedVsync Vsync
 # Android M: WindowLayoutChanged | SurfaceCanvas
 GFXINFO_EXEMPT = 1 | 4
 
+VSYNC_INTERVAL = 16666667
+
 
 class FpsProcessor(object):
     """
diff --git a/wlauto/utils/uxperf.py b/wlauto/utils/uxperf.py
new file mode 100644
index 00000000..36b9ee06
--- /dev/null
+++ b/wlauto/utils/uxperf.py
@@ -0,0 +1,170 @@
+import os
+import re
+import logging
+from collections import defaultdict
+
+from wlauto.utils.fps import FpsProcessor, SurfaceFlingerFrame, GfxInfoFrame, VSYNC_INTERVAL
+
+try:
+    import pandas as pd
+except ImportError:
+    pd = None
+
+
+class UxPerfParser(object):
+    '''
+    Parses logcat messages for UX Performance markers.
+
+    UX Performance markers are output from logcat under a debug priority. The
+    logcat tag for the marker messages is UX_PERF. The messages associated with
+    this tag consist of a name for the action to be recorded and a timestamp.
+    These fields are delimited by a single space. e.g.
+
+    <TAG>   : <MESSAGE>
+    UX_PERF : gestures_swipe_left_start 861975087367
+    ...
+    ...
+    UX_PERF : gestures_swipe_left_end 862132085804
+
+    Timestamps are produced using the running Java Virtual Machine's
+    high-resolution time source, in nanoseconds.
+    '''
+    def __init__(self, context, prefix=''):
+        self.context = context
+        self.prefix = prefix
+        self.actions = defaultdict(list)
+        self.logger = logging.getLogger('UxPerfParser')
+        # regex for matching logcat message format:
+        self.regex = re.compile(r'UX_PERF.*?:\s*(?P<message>.*\d+$)')
+
+    def parse(self, log):
+        '''
+        Opens log file and parses UX_PERF markers.
+
+        Actions delimited by markers are captured in a dictionary with
+        actions mapped to timestamps.
+        '''
+        loglines = self._read(log)
+        self._gen_action_timestamps(loglines)
+
+    def add_action_frames(self, frames, drop_threshold, generate_csv):  # pylint: disable=too-many-locals
+        '''
+        Uses FpsProcessor to parse frame.csv extracting fps, frame count, jank
+        and vsync metrics on a per action basis. Adds results to metrics.
+        '''
+        refresh_period = self._parse_refresh_peroid()
+
+        for action in self.actions:
+            # default values
+            fps, frame_count, janks, not_at_vsync = float('nan'), 0, 0, 0
+            p90, p95, p99 = [float('nan')] * 3
+            metrics = (fps, frame_count, janks, not_at_vsync)
+
+            df = self._create_sub_df(self.actions[action], frames)
+            if not df.empty:  # pylint: disable=maybe-no-member
+                fp = FpsProcessor(df, action=action)
+                try:
+                    per_frame_fps, metrics = fp.process(refresh_period, drop_threshold)
+                    fps, frame_count, janks, not_at_vsync = metrics
+
+                    if generate_csv:
+                        name = action + '_fps'
+                        filename = name + '.csv'
+                        fps_outfile = os.path.join(self.context.output_directory, filename)
+                        per_frame_fps.to_csv(fps_outfile, index=False, header=True)
+                        self.context.add_artifact(name, path=filename, kind='data')
+
+                    p90, p95, p99 = fp.percentiles()
+                except AttributeError:
+                    self.logger.warning('Non-matched timestamps in dumpsys output: action={}'
+                                        .format(action))
+
+            self.context.result.add_metric(self.prefix + action + '_FPS', fps)
+            self.context.result.add_metric(self.prefix + action + '_frame_count', frame_count)
+            self.context.result.add_metric(self.prefix + action + '_janks', janks, lower_is_better=True)
+            self.context.result.add_metric(self.prefix + action + '_not_at_vsync', not_at_vsync, lower_is_better=True)
+            self.context.result.add_metric(self.prefix + action + '_frame_time_90percentile', p90, 'ms', lower_is_better=True)
+            self.context.result.add_metric(self.prefix + action + '_frame_time_95percentile', p95, 'ms', lower_is_better=True)
+            self.context.result.add_metric(self.prefix + action + '_frame_time_99percentile', p99, 'ms', lower_is_better=True)
+
+    def add_action_timings(self):
+        '''
+        Add simple action timings in millisecond resolution to metrics
+        '''
+        for action, timestamps in self.actions.iteritems():
+            # nanosecond precision, but not necessarily nanosecond resolution
+            # truncate to guarantee millisecond precision
+            ts_ms = tuple(int(ts) for ts in timestamps)
+            if len(ts_ms) == 2:
+                start, finish = ts_ms
+                duration = finish - start
+                result = self.context.result
+
+                result.add_metric(self.prefix + action + "_start", start, units='ms')
+                result.add_metric(self.prefix + action + "_finish", finish, units='ms')
+                result.add_metric(self.prefix + action + "_duration", duration, units='ms', lower_is_better=True)
+            else:
+                self.logger.warning('Expected two timestamps. Received {}'.format(ts_ms))
+
+    def _gen_action_timestamps(self, lines):
+        '''
+        Parses lines and matches against logcat tag.
+        Groups timestamps by action name.
+        Creates a dictionary of lists with actions mapped to timestamps.
+        '''
+        for line in lines:
+            match = self.regex.search(line)
+
+            if match:
+                message = match.group('message')
+                action_with_suffix, timestamp = message.rsplit(' ', 1)
+                action, _ = action_with_suffix.rsplit('_', 1)
+                self.actions[action].append(timestamp)
+
+    def _parse_refresh_peroid(self):
+        '''
+        Reads the first line of the raw dumpsys output for the refresh period.
+        '''
+        raw_path = os.path.join(self.context.output_directory, 'surfaceflinger.raw')
+        if os.path.isfile(raw_path):
+            raw_lines = self._read(raw_path)
+            refresh_period = int(raw_lines.next())
+        else:
+            refresh_period = VSYNC_INTERVAL
+
+        return refresh_period
+
+    def _create_sub_df(self, action, frames):
+        '''
+        Creates a data frame containing fps metrics for a captured action.
+        '''
+        if len(action) == 2:
+            start, end = map(int, action)
+            df = pd.read_csv(frames)
+            # SurfaceFlinger Algorithm
+            if df.columns.tolist() == list(SurfaceFlingerFrame._fields):  # pylint: disable=maybe-no-member
+                field = 'actual_present_time'
+            # GfxInfo Algorithm
+            elif df.columns.tolist() == list(GfxInfoFrame._fields):  # pylint: disable=maybe-no-member
+                field = 'FrameCompleted'
+            else:
+                field = ''
+                self.logger.error('frames.csv not in a recognised format. Cannot parse.')
+            if field:
+                df = df[start < df[field]]
+                df = df[df[field] <= end]
+        else:
+            self.logger.warning('Discarding action. Expected 2 timestamps, got {}!'.format(len(action)))
+            df = pd.DataFrame()
+        return df
+
+    def _read(self, log):
+        '''
+        Opens a file a yields the lines with whitespace stripped.
+        '''
+        try:
+            with open(log, 'r') as rfh:
+                for line in rfh:
+                    yield line.strip()
+        except IOError:
+            self.logger.error('Could not open {}'.format(log))
diff --git a/wlauto/workloads/adobereader/com.arm.wlauto.uiauto.adobereader.jar b/wlauto/workloads/adobereader/com.arm.wlauto.uiauto.adobereader.jar
index a99b0d70..a49643bf 100644
Binary files a/wlauto/workloads/adobereader/com.arm.wlauto.uiauto.adobereader.jar and b/wlauto/workloads/adobereader/com.arm.wlauto.uiauto.adobereader.jar differ
diff --git a/wlauto/workloads/adobereader/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java b/wlauto/workloads/adobereader/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
index 4fff0d41..9f8af678 100755
--- a/wlauto/workloads/adobereader/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
+++ b/wlauto/workloads/adobereader/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
@@ -16,6 +16,7 @@
 package com.arm.wlauto.uiauto.adobereader;
 
 import android.os.Bundle;
+import android.util.Log;
 
 // Import the uiautomator libraries
 import com.android.uiautomator.core.UiObject;
@@ -23,6 +24,8 @@ import com.android.uiautomator.core.UiObjectNotFoundException;
 import com.android.uiautomator.core.UiSelector;
 
 import com.arm.wlauto.uiauto.UxPerfUiAutomation;
+import com.arm.wlauto.uiauto.ApplaunchInterface;
+import com.arm.wlauto.uiauto.UiAutoUtils;
 
 import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_ID;
 import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_TEXT;
@@ -34,27 +37,21 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 
-public class UiAutomation extends UxPerfUiAutomation {
-
-    protected Bundle parameters;
-    protected String packageName;
-    protected String packageID;
+public class UiAutomation extends UxPerfUiAutomation implements ApplaunchInterface {
 
     private long networkTimeout =  TimeUnit.SECONDS.toMillis(20);
     private long searchTimeout =  TimeUnit.SECONDS.toMillis(20);
 
     public void runUiAutomation() throws Exception {
         parameters = getParams();
-        packageName = parameters.getString("package");
-        packageID = packageName + ":id/";
 
         String filename = parameters.getString("filename").replace("0space0", " ");
         String[] searchStrings =
             parameters.getString("search_string_list").replace("0space0", " ").split("0newline0");
 
         setScreenOrientation(ScreenOrientation.NATURAL);
+        runApplicationInitialization();
 
-        dismissWelcomeView();
         openFile(filename);
         gesturesTest();
         searchPdfTest(searchStrings);
@@ -62,6 +59,31 @@ public class UiAutomation extends UxPerfUiAutomation {
 
         unsetScreenOrientation();
     }
+    
+    // Get application parameters and clear the initial run dialogues of the application launch.
+    public void runApplicationInitialization() throws Exception {
+        getPackageParameters();
+        dismissWelcomeView();
+    }
+    
+    // Sets the UiObject that marks the end of the application launch.
+    public UiObject getLaunchEndObject() {
+        UiObject launchEndObject = new UiObject(new UiSelector().textContains("RECENT")
+                                         .className("android.widget.TextView"));
+        return launchEndObject;
+    }
+    
+    // Returns the launch command for the application.
+    public String getLaunchCommand() {
+        String launch_command;
+        launch_command = UiAutoUtils.createLaunchCommand(parameters);
+        return launch_command;
+    }
+    
+    // Pass the workload parameters, used for applaunch
+    public void setWorkloadParameters(Bundle workload_parameters) {
+        parameters = workload_parameters;
+    }
 
     private void dismissWelcomeView() throws Exception {
         UiObject welcomeView = getUiObjectByResourceId("android:id/content",
diff --git a/wlauto/workloads/applaunch/__init__.py b/wlauto/workloads/applaunch/__init__.py
index 40dcb7b7..19fcac96 100644
--- a/wlauto/workloads/applaunch/__init__.py
+++ b/wlauto/workloads/applaunch/__init__.py
@@ -1,189 +1,169 @@
-#    Copyright 2013-2015 ARM Limited
+#    Copyright 2015 ARM Limited
 #
-# Licensed under the Apache License, Version 2.0 (the "License");
+# Licensed under the Apache License, Version 2.0 (the 'License');
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
 #     http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
+# distributed under the License is distributed on an 'AS IS' BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-# pylint: disable=E1101
-
-from __future__ import division
+# pylint: disable=attribute-defined-outside-init
 import os
 
-try:
-    import jinja2
-except ImportError:
-    jinja2 = None
+from time import sleep
 
-from wlauto import Workload, settings, Parameter
-from wlauto.exceptions import WorkloadError
-from wlauto.utils.hwmon import discover_sensors
-from wlauto.utils.misc import get_meansd
-from wlauto.utils.types import boolean, identifier, list_of_strs
+from wlauto import Workload, AndroidBenchmark, AndroidUxPerfWorkload, UiAutomatorWorkload
+from wlauto import Parameter
+from wlauto import ExtensionLoader
+from wlauto import File
+from wlauto import settings
+from wlauto.exceptions import ConfigError
+from wlauto.exceptions import ResourceError
+from wlauto.utils.android import ApkInfo
+from wlauto.utils.uxperf import UxPerfParser
+
+import wlauto.common.android.resources
 
 
-THIS_DIR = os.path.dirname(__file__)
-TEMPLATE_NAME = 'device_script.template'
-SCRIPT_TEMPLATE = os.path.join(THIS_DIR, TEMPLATE_NAME)
-
-APP_CONFIG = {
-    'browser': {
-        'package': 'com.android.browser',
-        'activity': '.BrowserActivity',
-        'options': '-d about:blank',
-    },
-    'calculator': {
-        'package': 'com.android.calculator2',
-        'activity': '.Calculator',
-        'options': '',
-    },
-    'calendar': {
-        'package': 'com.android.calendar',
-        'activity': '.LaunchActivity',
-        'options': '',
-    },
-}
-
-
-class ApplaunchWorkload(Workload):
+class Applaunch(AndroidUxPerfWorkload):
 
     name = 'applaunch'
-    description = """
-    Measures the time and energy used in launching an application.
+    description = '''
+    This workload launches and measures the launch time of applications for supporting workloads.
+    
+    Currently supported workloads are the ones that implement ``ApplaunchInterface``. For any
+    workload to support this workload, it should implement the ``ApplaunchInterface``.
+    The corresponding java file of the workload associated with the application being measured
+    is executed during the run. The application that needs to be
+    measured is passed as a parametre ``workload_name``. The parameters required for that workload
+    have to be passed as a dictionary which is captured by the parametre ``workload_params``.
+    This information can be obtained by inspecting the workload details of the specific workload.
 
-    """
+    The workload allows to run multiple iterations of an application
+    launch in two modes:
+
+    1. Launch from background
+    2. Launch from long-idle
+
+    These modes are captured as a parameter applaunch_type.
+
+    ``launch_from_background``
+        Launches an application after the application is sent to background by
+        pressing Home button.
+
+    ``launch_from_long-idle``
+        Launches an application after killing an application process and
+        clearing all the caches.
+
+    **Test Description:**
+
+    -   During the initialization and setup, the application being launched is launched 
+        for the first time. The jar file of the workload of the application
+        is moved to device at the location ``workdir`` which further implements the methods
+        needed to measure the application launch time.
+
+    -   Run phase calls the UiAutomator of the applaunch which runs in two subphases.
+            A.  Applaunch Setup Run:
+                    During this phase, welcome screens and dialogues during the first launch
+                    of the instrumented application are cleared.
+            B.  Applaunch Metric Run:
+                    During this phase, the application is launched multiple times determined by
+                    the iteration number specified by the parametre ``applaunch_iterations``.
+                    Each of these iterations are instrumented to capture the launch time taken
+                    and the values are recorded as UXPERF marker values in logfile.
+    '''
     supported_platforms = ['android']
 
     parameters = [
-        Parameter('app', default='browser', allowed_values=['calculator', 'browser', 'calendar'],
-                  description='The name of the application to measure.'),
-        Parameter('set_launcher_affinity', kind=bool, default=True,
-                  description=('If ``True``, this will explicitly set the affinity of the launcher '
-                               'process to the A15 cluster.')),
-        Parameter('times', kind=int, default=8,
-                  description='Number of app launches to do on the device.'),
-        Parameter('measure_energy', kind=boolean, default=False,
+        Parameter('workload_name', kind=str,
+                  description='Name of the uxperf workload to launch',
+                  default='gmail'),
+        Parameter('workload_params', kind=dict, default={},
                   description="""
-                  Specfies wether energy measurments should be taken during the run.
-
-                  .. note:: This depends on appropriate sensors to be exposed through HWMON.
-
+                  parameters of the uxperf workload whose application launch
+                  time is measured
+                  """),
+        Parameter('applaunch_type', kind=str, default='launch_from_background',
+                  allowed_values=['launch_from_background', 'launch_from_long-idle'],
+                  description="""
+                  Choose launch_from_long-idle for measuring launch time
+                  from long-idle. These two types are described in the class
+                  description.
+                  """),
+        Parameter('applaunch_iterations', kind=int, default=1,
+                  description="""
+                  Number of iterations of the application launch
+                  """),
+        Parameter('report_results', kind=bool, default=True,
+                  description="""
+                  Choose to report results of the application launch time.
                   """),
-        Parameter('io_stress', kind=boolean, default=False,
-                  description='Specifies whether to stress IO during App launch.'),
-        Parameter('io_scheduler', allowed_values=['noop', 'deadline', 'row', 'cfq', 'bfq'],
-                  description='Set the IO scheduler to test on the device.'),
-        Parameter('cleanup', kind=boolean, default=True,
-                  description='Specifies whether to clean up temporary files on the device.'),
     ]
 
     def __init__(self, device, **kwargs):
-        super(ApplaunchWorkload, self).__init__(device, **kwargs)
-        if not jinja2:
-            raise WorkloadError('Please install jinja2 Python package: "sudo pip install jinja2"')
-        filename = '{}-{}.sh'.format(self.name, self.app)
-        self.host_script_file = os.path.join(settings.meta_directory, filename)
-        self.device_script_file = os.path.join(self.device.working_directory, filename)
-        self._launcher_pid = None
-        self._old_launcher_affinity = None
-        self.sensors = []
+        super(Applaunch, self).__init__(device, **kwargs)
 
-    def on_run_init(self, context):  # pylint: disable=W0613
-        if self.measure_energy:
-            self.sensors = discover_sensors(self.device, ['energy'])
-            for sensor in self.sensors:
-                sensor.label = identifier(sensor.label).upper()
+    def init_resources(self, context):
+        super(Applaunch, self).init_resources(context)
+        loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
+        self.workload_params['markers_enabled'] = True
+        self.workload = loader.get_workload(self.workload_name, self.device,
+                                            **self.workload_params)
+        self.init_workload_resources(context)
+
+    def init_workload_resources(self, context):
+        self.workload.uiauto_file = context.resolver.get(wlauto.common.android.resources.JarFile(self.workload))
+        if not self.workload.uiauto_file:
+            raise ResourceError('No UI automation JAR file found for workload {}.'.format(self.workload.name))
+        self.workload.device_uiauto_file = self.device.path.join(self.device.working_directory, os.path.basename(self.workload.uiauto_file))
+        if not self.workload.uiauto_package:
+            self.workload.uiauto_package = os.path.splitext(os.path.basename(self.workload.uiauto_file))[0]
+
+    def validate(self):
+        super(Applaunch, self).validate()
+        self.workload.validate()
+        self.pass_parameters()
+
+    def pass_parameters(self):
+        self.uiauto_params['workload'] = self.workload.name
+        self.uiauto_params['package'] = self.workload.package
+        self.uiauto_params['binaries_directory'] = self.device.binaries_directory
+        self.uiauto_params.update(self.workload.uiauto_params)
+        if self.workload.activity:
+            self.uiauto_params['launch_activity'] = self.workload.activity
+        else:
+            self.uiauto_params['launch_activity'] = "None"
+        self.uiauto_params['applaunch_type'] = self.applaunch_type
+        self.uiauto_params['applaunch_iterations'] = self.applaunch_iterations
 
     def setup(self, context):
-        self.logger.debug('Creating script {}'.format(self.host_script_file))
-        with open(self.host_script_file, 'w') as wfh:
-            env = jinja2.Environment(loader=jinja2.FileSystemLoader(THIS_DIR))
-            template = env.get_template(TEMPLATE_NAME)
-            wfh.write(template.render(device=self.device,  # pylint: disable=maybe-no-member
-                                      sensors=self.sensors,
-                                      iterations=self.times,
-                                      io_stress=self.io_stress,
-                                      io_scheduler=self.io_scheduler,
-                                      cleanup=self.cleanup,
-                                      package=APP_CONFIG[self.app]['package'],
-                                      activity=APP_CONFIG[self.app]['activity'],
-                                      options=APP_CONFIG[self.app]['options'],
-                                      busybox=self.device.busybox,
-                                      ))
-        self.device_script_file = self.device.install(self.host_script_file)
-        if self.set_launcher_affinity:
-            self._set_launcher_affinity()
-        self.device.clear_logcat()
+        AndroidBenchmark.setup(self.workload, context)
+        if not self.workload.launch_main:
+            self.workload.launch_app()
+        UiAutomatorWorkload.setup(self, context)
+        self.workload.device.push_file(self.workload.uiauto_file, self.workload.device_uiauto_file)
 
     def run(self, context):
-        self.device.execute('sh {}'.format(self.device_script_file), timeout=300, as_root=self.io_stress)
+        UiAutomatorWorkload.run(self, context)
 
-    def update_result(self, context):  # pylint: disable=too-many-locals
-        result_files = ['time.result']
-        result_files += ['{}.result'.format(sensor.label) for sensor in self.sensors]
-        metric_suffix = ''
-        if self.io_stress:
-            host_scheduler_file = os.path.join(context.output_directory, 'scheduler')
-            device_scheduler_file = '/sys/block/mmcblk0/queue/scheduler'
-            self.device.pull_file(device_scheduler_file, host_scheduler_file)
-            with open(host_scheduler_file) as fh:
-                scheduler = fh.read()
-                scheduler_used = scheduler[scheduler.index("[") + 1:scheduler.index("]")]
-                metric_suffix = '_' + scheduler_used
-        for filename in result_files:
-            self._extract_results_from_file(context, filename, metric_suffix)
+    def update_result(self, context):
+        super(Applaunch, self).update_result(context)
+        if self.report_results:
+            parser = UxPerfParser(context, prefix='applaunch_')
+            logfile = os.path.join(context.output_directory, 'logcat.log')
+            parser.parse(logfile)
+            parser.add_action_timings()
 
     def teardown(self, context):
-        if self.set_launcher_affinity:
-            self._reset_launcher_affinity()
-        if self.cleanup:
-            self.device.delete_file(self.device_script_file)
-
-    def _set_launcher_affinity(self):
-        try:
-            self._launcher_pid = self.device.get_pids_of('com.android.launcher')[0]
-            result = self.device.execute('taskset -p {}'.format(self._launcher_pid), busybox=True, as_root=True)
-            self._old_launcher_affinity = int(result.split(':')[1].strip(), 16)
-
-            cpu_ids = [i for i, x in enumerate(self.device.core_names) if x == 'a15']
-            if not cpu_ids or len(cpu_ids) == len(self.device.core_names):
-                self.logger.debug('Cannot set affinity.')
-                return
-
-            new_mask = reduce(lambda x, y: x | y, cpu_ids, 0x0)
-            self.device.execute('taskset -p 0x{:X} {}'.format(new_mask, self._launcher_pid), busybox=True, as_root=True)
-        except IndexError:
-            raise WorkloadError('Could not set affinity of launcher: PID not found.')
-
-    def _reset_launcher_affinity(self):
-        command = 'taskset -p 0x{:X} {}'.format(self._old_launcher_affinity, self._launcher_pid)
-        self.device.execute(command, busybox=True, as_root=True)
-
-    def _extract_results_from_file(self, context, filename, metric_suffix):
-        host_result_file = os.path.join(context.output_directory, filename)
-        device_result_file = self.device.path.join(self.device.working_directory, filename)
-        self.device.pull_file(device_result_file, host_result_file)
-
-        with open(host_result_file) as fh:
-            if filename == 'time.result':
-                values = [v / 1000 for v in map(int, fh.read().split())]
-                _add_metric(context, 'time' + metric_suffix, values, 'Seconds')
-            else:
-                metric = filename.replace('.result', '').lower()
-                numbers = iter(map(int, fh.read().split()))
-                deltas = [(after - before) / 1000000 for before, after in zip(numbers, numbers)]
-                _add_metric(context, metric, deltas, 'Joules')
-
-
-def _add_metric(context, metric, values, units):
-    mean, sd = get_meansd(values)
-    context.result.add_metric(metric, mean, units)
-    context.result.add_metric(metric + ' sd', sd, units, lower_is_better=True)
+        super(Applaunch, self).teardown(context)
+        AndroidBenchmark.teardown(self.workload, context)
+        UiAutomatorWorkload.teardown(self.workload, context)
+        #Workload uses Dexclass loader while loading the jar file of the instrumented workload.
+        #Dexclassloader unzips and generates .dex file in the .jar directory during the run.
+        device_uiauto_dex_file = self.workload.device_uiauto_file.replace(".jar", ".dex")
+        self.workload.device.delete_file(self.device.path.join(self.device.binaries_directory, device_uiauto_dex_file))
diff --git a/wlauto/workloads/applaunch/com.arm.wlauto.uiauto.applaunch.jar b/wlauto/workloads/applaunch/com.arm.wlauto.uiauto.applaunch.jar
new file mode 100644
index 00000000..c10edd6f
Binary files /dev/null and b/wlauto/workloads/applaunch/com.arm.wlauto.uiauto.applaunch.jar differ
diff --git a/wlauto/workloads/applaunch/device_script.template b/wlauto/workloads/applaunch/device_script.template
deleted file mode 100644
index 1e940d70..00000000
--- a/wlauto/workloads/applaunch/device_script.template
+++ /dev/null
@@ -1,88 +0,0 @@
-#!{{ device.binaries_directory.rstrip('/') }}/sh
-
-
-{% for sensor in sensors %}
-GET_{{ sensor.label }}="cat {{ sensor.filepath }}"
-{% endfor %}
-
-LAUNCH_COMMAND="am start -W -n {{ package }}/{{ activity }} {{ options }}"
-STOP_COMMAND="am force-stop {{ package }}"
-TEMP_FILE=tmp.txt
-
-TIME_RESULT=""
-{% for sensor in sensors %}
-{{ sensor.label }}=""
-{% endfor %}
-
-cd {{ device.working_directory }}
-
-# esc esc down down down ENTER (this should bring up the apps menu)
-input keyevent 111
-sleep 1
-input keyevent 111
-sleep 1
-input keyevent 20
-sleep 1
-input keyevent 20
-sleep 1
-input keyevent 20
-sleep 1
-input keyevent 66
-sleep 1
-
-# Warm up caches.
-$LAUNCH_COMMAND
-$STOP_COMMAND
-$LAUNCH_COMMAND
-$STOP_COMMAND
-$LAUNCH_COMMAND
-$STOP_COMMAND
-
-{% if io_scheduler != None %}
-echo {{ io_scheduler }} > /sys/block/mmcblk0/queue/scheduler
-{% endif %}
-
-for i in $({{ busybox }} seq 1 {{ iterations }})
-do
-    {% for sensor in sensors %}
-    {{ sensor.label }}="${{ sensor.label }} `$GET_{{ sensor.label }}`"
-    {% endfor %}
-
-    {% if io_stress %}
-    # Drop caches to get a cold start.
-    sync; echo 3 > /proc/sys/vm/drop_caches
-    # Run IO stress during App launch.
-    {{ busybox }} dd if=/dev/zero of=write.img bs=1048576 count=2000 conv=fsync > dd_write.txt 2>&1 &
-    io_write=$!
-    {{ busybox }} dd if=/dev/block/mmcblk0 of=/dev/null bs=1048576 > dd_read.txt 2>&1 &
-    io_read=$!
-    {% endif %}
-
-    $LAUNCH_COMMAND > $TEMP_FILE
-    
-    {% for sensor in sensors %}
-    {{ sensor.label }}="${{ sensor.label }} `$GET_{{ sensor.label }}`"
-    {% endfor %}
-
-    TIME=`{{ busybox }} awk '{if($1~"TotalTime") print $2}' $TEMP_FILE`
-    TIME_RESULT="$TIME_RESULT $TIME"
-    {% if cleanup %}
-    rm $TEMP_FILE
-    {% if io_stress %}
-    kill $io_write
-    kill $io_read
-    rm -f write.img
-    {% endif %}
-    {% endif %}
-
-    $STOP_COMMAND
-    sleep 2
-done
-
-{% for sensor in sensors %}
-echo ${{ sensor.label }} > {{ sensor.label }}.result
-{% endfor %}
-echo $TIME_RESULT > time.result
-# esc esc down down down ENTER (this should bring up the apps menu)
-input keyevent 111
-sleep 1
diff --git a/wlauto/workloads/applaunch/uiauto/build.sh b/wlauto/workloads/applaunch/uiauto/build.sh
new file mode 100755
index 00000000..1c5233c5
--- /dev/null
+++ b/wlauto/workloads/applaunch/uiauto/build.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# CD into build dir if possible - allows building from any directory
+script_path='.'
+if `readlink -f $0 &>/dev/null`; then
+    script_path=`readlink -f $0 2>/dev/null`
+fi
+script_dir=`dirname $script_path`
+cd $script_dir
+
+# Ensure build.xml exists before starting
+if [[ ! -f build.xml ]]; then
+    echo 'Ant build.xml file not found! Check that you are in the right directory.'
+    exit 9
+fi
+
+# Copy base classes from wlauto dist
+class_dir=bin/classes/com/arm/wlauto/uiauto
+base_classes=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', '*.class')"`
+mkdir -p $class_dir
+cp $base_classes $class_dir
+
+# Build and return appropriate exit code if failed
+ant build
+exit_code=$?
+if [[ $exit_code -ne 0 ]]; then
+    echo "ERROR: 'ant build' exited with code $exit_code"
+    exit $exit_code
+fi
+
+# If successful move JAR file to workload folder (overwrite previous)
+package=com.arm.wlauto.uiauto.applaunch.jar
+rm -f ../$package
+if [[ -f bin/$package ]]; then
+    cp bin/$package ..
+else
+    echo 'ERROR: UiAutomator JAR could not be found!'
+    exit 9
+fi
diff --git a/wlauto/workloads/applaunch/uiauto/build.xml b/wlauto/workloads/applaunch/uiauto/build.xml
new file mode 100644
index 00000000..b4e76972
--- /dev/null
+++ b/wlauto/workloads/applaunch/uiauto/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="com.arm.wlauto.uiauto.applaunch" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: VERSION_TAG -->
+    <import file="${sdk.dir}/tools/ant/uibuild.xml" />
+
+</project>
diff --git a/wlauto/workloads/applaunch/uiauto/project.properties b/wlauto/workloads/applaunch/uiauto/project.properties
new file mode 100644
index 00000000..ce39f2d0
--- /dev/null
+++ b/wlauto/workloads/applaunch/uiauto/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-18
diff --git a/wlauto/workloads/applaunch/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java b/wlauto/workloads/applaunch/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
new file mode 100755
index 00000000..b0e9f80f
--- /dev/null
+++ b/wlauto/workloads/applaunch/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
@@ -0,0 +1,220 @@
+/*    Copyright 2014-2016 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.arm.wlauto.uiauto.applaunch;
+
+import android.os.Bundle;
+import android.util.Log;
+
+// Import the uiautomator libraries
+import com.android.uiautomator.core.UiObject;
+import com.android.uiautomator.core.UiObjectNotFoundException;
+import com.android.uiautomator.core.UiSelector;
+
+import com.arm.wlauto.uiauto.ApplaunchInterface;
+import com.arm.wlauto.uiauto.UxPerfUiAutomation;
+
+import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_ID;
+import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_TEXT;
+import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_DESC;
+
+import java.util.concurrent.TimeUnit;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Map.Entry;
+import dalvik.system.DexClassLoader;
+import java.lang.reflect.Method;
+
+
+public class UiAutomation extends UxPerfUiAutomation {
+
+    /** 
+     * Uiobject that marks the end of launch of an application, which is workload
+     * specific and added in the workload Java file by a method called getLaunchEndObject().
+     */
+    public UiObject launchEndObject;
+    /** Timeout to wait for application launch to finish. */
+    private Integer launch_timeout = 10;
+    public String applaunchType;
+    public String applaunchIterations;
+    public String activityName;
+    public ApplaunchInterface launch_workload;
+
+    /** Uiautomator function called by the applaunch workload. */
+    public void runUiAutomation() throws Exception{
+        parameters = getParams();
+
+        // Get workload jar file parameters
+        String workload = parameters.getString("workload");
+        String binariesDirectory = parameters.getString("binaries_directory");
+        String workloadJarPath = parameters.getString("workdir");
+        String workloadJarName = String.format("com.arm.wlauto.uiauto.%1s.jar",workload);
+        String workloadJarFile = String.format("%1s/%2s",workloadJarPath, workloadJarName);
+
+        // Load the jar file
+        File jarFile = new File(workloadJarFile);
+        if(!jarFile.exists()) {
+            throw new Exception(String.format("Jar file not found: %s", workloadJarFile));
+        }
+        DexClassLoader classloader = new DexClassLoader(jarFile.toURI().toURL().toString(),
+                                     binariesDirectory, null, ClassLoader.getSystemClassLoader());
+        Class uiautomation = null;
+        Object uiautomation_interface = null;
+        String workloadClass = String.format("com.arm.wlauto.uiauto.%1s.UiAutomation",workload);
+        try {
+            uiautomation = classloader.loadClass(workloadClass);
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+        Log.d("Class loaded:", uiautomation.getCanonicalName());
+        uiautomation_interface = uiautomation.newInstance();
+
+        // Create an Application Interface object from the workload
+        launch_workload = ((ApplaunchInterface)uiautomation_interface);
+
+        // Get parameters for application launch
+        getPackageParameters();
+        applaunchType = parameters.getString("applaunch_type");
+        applaunchIterations = parameters.getString("applaunch_iterations");
+        activityName = parameters.getString("launch_activity");
+
+        // Run the workload for application launch initialization
+        runApplaunchSetup();
+
+        // Run the workload for application launch measurement
+        for (int iteration = 0; iteration < Integer.parseInt(applaunchIterations); iteration++) {
+            Log.d("Applaunch iteration number: ", applaunchIterations);
+            sleep(20);//sleep for a while before next iteration
+            killBackground();
+            runApplaunchIteration(iteration);
+            closeApplication();
+        }
+    }
+
+    /**
+     * Setup run for applaunch workload that clears the initial
+     * run dialogues on launching an application package.
+     */
+    public void runApplaunchSetup() throws Exception{
+        setScreenOrientation(ScreenOrientation.NATURAL);
+        launch_workload.setWorkloadParameters(parameters);
+        launch_workload.runApplicationInitialization();
+        launchEndObject = launch_workload.getLaunchEndObject();
+        unsetScreenOrientation();
+        closeApplication();
+    }
+
+    /**
+     * This method performs multiple iterations of application launch and
+     * records the time taken for each iteration.
+     */
+    public void runApplaunchIteration(Integer iteration_count) throws Exception{
+        String testTag = "applaunch" + iteration_count;
+        String launchCommand = launch_workload.getLaunchCommand();
+        AppLaunch applaunch = new AppLaunch(testTag, launchCommand);
+        applaunch.startLaunch();//Launch the application and start timer
+        applaunch.endLaunch();//marks the end of launch and stops timer
+    }
+
+    /*
+     * AppLaunch class implements methods that facilitates launching applications
+     * from the uiautomator. It has methods that are used for one complete iteration of application
+     * launch instrumentation.
+     * ActionLogger class is instantiated within the class for measuring applaunch time.
+     * startLaunch(): Marks the beginning of the application launch, starts Timer
+     * endLaunch(): Marks the end of application, ends Timer
+     * launchMain(): Starts the application launch process and validates the finish of launch.
+    */
+    private class AppLaunch {
+
+        private String testTag;
+        private String launchCommand;
+        private ActionLogger logger;
+        Process launch_p;
+
+        public AppLaunch(String testTag, String launchCommand) {
+            this.testTag = testTag;
+            this.launchCommand = launchCommand;
+            this.logger = new ActionLogger(testTag, parameters);
+        }
+
+        // Called by launchMain() to check if app launch is successful
+        public void launchValidate(Process launch_p) throws Exception {
+            launch_p.waitFor();
+            Integer exit_val = launch_p.exitValue();
+            if (exit_val != 0) {
+                throw new Exception("Application could not be launched");
+            }
+        }
+
+        // Marks the end of application launch of the workload.
+        public void endLaunch() throws Exception{
+            waitObject(launchEndObject, launch_timeout);
+            logger.stop();
+            launch_p.destroy();
+        }
+
+        // Launches the application.
+        public void launchMain() throws Exception{
+            launch_p = Runtime.getRuntime().exec(launchCommand);
+
+            launchValidate(launch_p);
+        }
+
+        // Beginning of application launch
+        public void startLaunch() throws Exception{
+            logger.start();
+            launchMain();
+        }
+    }
+
+    // Exits the application according to application launch type.
+    public void closeApplication() throws Exception{
+        if(applaunchType.equals("launch_from_background")) {
+            pressHome();
+        }
+        else if(applaunchType.equals("launch_from_long-idle")) {
+            killApplication();
+            dropCaches();
+        }
+    }
+
+    // Kills the application process
+    public void killApplication() throws Exception{
+        Process kill_p;
+        kill_p = Runtime.getRuntime().exec(String.format("am force-stop %s", packageName));
+        kill_p.waitFor();
+        kill_p.destroy();
+    }
+
+    // Kills the background processes
+    public void killBackground() throws Exception{
+        Process kill_p;
+        kill_p = Runtime.getRuntime().exec("am kill-all");
+        kill_p.waitFor();
+        kill_p.destroy();
+    }
+
+    // Drop the caches
+    public void dropCaches() throws Exception{
+        Process drop_cache;
+        drop_cache = Runtime.getRuntime().exec("su sync; su echo 3 > /proc/sys/vm/drop_caches");
+        drop_cache.waitFor();
+        drop_cache.destroy();
+    }
+}
diff --git a/wlauto/workloads/gmail/com.arm.wlauto.uiauto.gmail.jar b/wlauto/workloads/gmail/com.arm.wlauto.uiauto.gmail.jar
index 12e12841..4511eb4c 100644
Binary files a/wlauto/workloads/gmail/com.arm.wlauto.uiauto.gmail.jar and b/wlauto/workloads/gmail/com.arm.wlauto.uiauto.gmail.jar differ
diff --git a/wlauto/workloads/gmail/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java b/wlauto/workloads/gmail/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
index d24f2757..edae608a 100755
--- a/wlauto/workloads/gmail/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
+++ b/wlauto/workloads/gmail/uiauto/src/com/arm/wlauto/uiauto/UiAutomation.java
@@ -23,28 +23,24 @@ import com.android.uiautomator.core.UiObjectNotFoundException;
 import com.android.uiautomator.core.UiSelector;
 
 import com.arm.wlauto.uiauto.UxPerfUiAutomation;
+import com.arm.wlauto.uiauto.ApplaunchInterface;
+import com.arm.wlauto.uiauto.UiAutoUtils;
 
 import java.util.concurrent.TimeUnit;
 
-public class UiAutomation extends UxPerfUiAutomation {
-
-    public Bundle parameters;
-    public String packageName;
-    public String packageID;
+public class UiAutomation extends UxPerfUiAutomation implements ApplaunchInterface{
 
     private int networkTimeoutSecs = 30;
     private long networkTimeout =  TimeUnit.SECONDS.toMillis(networkTimeoutSecs);
 
     public void runUiAutomation() throws Exception {
         parameters = getParams();
-        packageName = parameters.getString("package");
-        packageID = packageName + ":id/";
 
         String recipient = parameters.getString("recipient");
 
         setScreenOrientation(ScreenOrientation.NATURAL);
+        runApplicationInitialization();
 
-        clearFirstRunDialogues();
         clickNewMail();
         attachImage();
         setToField(recipient);
@@ -54,6 +50,31 @@ public class UiAutomation extends UxPerfUiAutomation {
 
         unsetScreenOrientation();
     }
+    
+    // Get application parameters and clear the initial run dialogues of the application launch.
+    public void runApplicationInitialization() throws Exception {
+        getPackageParameters();
+        clearFirstRunDialogues();
+    }
+    
+    // Sets the UiObject that marks the end of the application launch.
+    public UiObject getLaunchEndObject() {
+        UiObject launchEndObject = 
+                        new UiObject(new UiSelector().className("android.widget.ImageButton"));
+        return launchEndObject;
+    }
+    
+    // Returns the launch command for the application.
+    public String getLaunchCommand() {
+        String launch_command;
+        launch_command = UiAutoUtils.createLaunchCommand(parameters);
+        return launch_command;
+    }
+    
+    // Pass the workload parameters, used for applaunch
+    public void setWorkloadParameters(Bundle workload_parameters) {
+        parameters = workload_parameters;
+    }
 
     public void clearFirstRunDialogues() throws Exception {
         // The first run dialogues vary on different devices so check if they are there and dismiss