<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Alan Cooke on Medium]]></title>
        <description><![CDATA[Stories by Alan Cooke on Medium]]></description>
        <link>https://medium.com/@a1cooke?source=rss-fac39e7c570b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*AGNJDo5tIT0ifHbx.jpeg</url>
            <title>Stories by Alan Cooke on Medium</title>
            <link>https://medium.com/@a1cooke?source=rss-fac39e7c570b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 30 Apr 2026 11:10:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@a1cooke/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Collecting Build Metrics from Buddybuild]]></title>
            <link>https://zendesk.engineering/collecting-build-metrics-from-buddybuild-8645ea82818b?source=rss-fac39e7c570b------2</link>
            <guid isPermaLink="false">https://medium.com/p/8645ea82818b</guid>
            <category><![CDATA[metrics]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[observability]]></category>
            <category><![CDATA[buddybuild]]></category>
            <dc:creator><![CDATA[Alan Cooke]]></dc:creator>
            <pubDate>Tue, 16 Oct 2018 06:43:17 GMT</pubDate>
            <atom:updated>2018-10-16T06:43:17.503Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o8_ICjpD-v_-8xdKWruniw.png" /><figcaption>Example Datadog dashboard of build metrics</figcaption></figure><p>So after a long hiatus from writing, I’ve decided to try and be a bit more disciplined and write more frequently. This is the first in a series around how we have introduced build time tracking across our CI environments, and how we track it in our development tools.</p><p>We at Zendesk use <a href="https://www.buddybuild.com/">Buddybuild</a>, a CI &amp; CD service for building iOS (and prior to their <a href="https://www.buddybuild.com/blog/buddybuild-is-now-part-of-apple">acquisition</a> by Apple, Android) applications and libraries. Buddybuild is great as it hides a lot of the complexity when it comes to getting setup with CI, and at the time of our initial comparison was a lot faster than our previous CI provider.</p><p>The great convenience of hiding the complexity means doing anything out of the ordinary is less than obvious. Custom scripting is a prime example of this. Consider an example of what I wanted to do with two tasks we want to track:</p><blockquote>Task 1: Measure the time it takes for a build to complete its execution</blockquote><blockquote>Task 2: Measure number of successful and failed builds</blockquote><p>Unlike other CI platforms, Buddybuild doesn’t offer a YAML file that a developer/integrator can modify. Instead, one can implement a set of scripts that are executed at different stages of the build process.</p><p>Documentation on customising build steps is listed <a href="https://docs.buddybuild.com/builds/custom_build_steps.html">here</a>, but here is a brief description:</p><p><em>buddybuild_postclone.sh — </em>Script called once your repo has been cloned</p><p><em>buddybuild_prebuild.sh</em> — Script called just before your build begins</p><p><em>buddybuild_postbuild.sh</em> — Script called at the end of a successful build</p><p><em>buddybuild_finally.sh</em> — Called at the end of the CI’s build loop regardless</p><h3>Task 1: Measure time for a build to complete</h3><p>To do this we need to capture the start and end time, then calculate the difference, and send it to our reporting service.</p><p>In `<em>buddybuild_prebuild.sh</em>`, we do the following:</p><pre>#Get the start time of the build<br>BUILD_START_TIME=$(date +%s)</pre><pre>#Export the value via .bashrc to be able to read it in other scripts<br>echo &quot;export BUILD_START_TIME=$BUILD_START_TIME&quot; &gt;&gt; $HOME/.bashrc</pre><p>In `<em>buddybuild_finally.sh</em>` we do the following:</p><pre>#Get the end time of the build<br>BUILD_END_TIME=$(date +%s)</pre><pre>#Calculate the difference between start and end<br>let &quot;BUILD_TIME = $BUILD_END_TIME - $BUILD_START_TIME&quot;</pre><pre>#Post the result to our metrics service<br>./metric.sh -m &quot;mobile.build.total.time&quot; -v $BUILD_TIME</pre><p>We do the time calculation in the final step in order to capture the time for failed and successful builds.</p><h3>Task 2: Measure successful and failed builds</h3><p>Buddybuild doesn’t have an environment variable, or state that yields the status of the build within these scripts.</p><p>In order to achieve this, we track it in an environment variable in <em>buddybuild_postbuild.sh,</em> which is only called on a successful build. To do this we include the following in our script:</p><pre>echo “export BUILD_RESULT=\”SUCCESS\”” &gt;&gt; $HOME/.bashrc</pre><p>Then in <em>buddybuild_finally.sh </em>, we check for the presence of the <strong><em>SUCCESS</em></strong> value or not, which implies the outcome of the build:</p><pre>if [ “$BUILD_RESULT” -eq “SUCCESS” ]; then <br>    ./metric.sh -m “mobile.build.success.count” -v 1<br>else <br>    ./metric.sh -m “mobile.build.failure.count” -v 1<br>fi</pre><p>This is all good stuff but how do the metrics actually get from Buddybuild to a reporting platform. In our case we are using <a href="https://www.datadoghq.com/">Datadog</a> to store and report on these metrics. We do this by leveraging the <a href="https://docs.datadoghq.com/api/?lang=python#post-timeseries-points">Datadog REST API</a>.</p><p>metric.sh is a bash wrapper around this API but the core of the script can be seen below.</p><pre>curl -X POST -H &quot;Content-type: application/json&quot; <br>\-d &quot;{ \&quot;series\&quot; : [{\&quot;metric\&quot;:\&quot;$metric\&quot;,          <br>\&quot;points\&quot;:[[$currenttime, $value]],          <br>\&quot;type\&quot;:\&quot;$type\&quot;,          <br>\&quot;tags\&quot;:$transformedtags}]}&quot; \&quot;https://api.datadoghq.com/api/v1/series?api_key=$apikey&quot;</pre><p>We chose bash not for ease of development, but because it doesn’t have any additional dependencies when it comes to running in a variety of CI environments.</p><p>Now you too can start to track the outcomes of your builds, and gain more insight into your historical builds, the time spent waiting on a build, and also measure changes as you make them to your overall build performance.</p><p>Hopefully someone finds this useful.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8645ea82818b" width="1" height="1" alt=""><hr><p><a href="https://zendesk.engineering/collecting-build-metrics-from-buddybuild-8645ea82818b">Collecting Build Metrics from Buddybuild</a> was originally published in <a href="https://zendesk.engineering">Zendesk Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift, Collections and Generics]]></title>
            <link>https://medium.com/@a1cooke/swift-collections-and-generics-e901ec56946?source=rss-fac39e7c570b------2</link>
            <guid isPermaLink="false">https://medium.com/p/e901ec56946</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Alan Cooke]]></dc:creator>
            <pubDate>Tue, 16 Feb 2016 10:35:39 GMT</pubDate>
            <atom:updated>2016-02-16T10:35:39.847Z</atom:updated>
            <content:encoded><![CDATA[<p>As you can tell from my last post, my focus of late has been on iOS development with a mixture of Objective-C and Swift.</p><p>Something that might go by a lot of people is that the support for generics includes all types, structs, primitive types, objects, everything. Why bring this up I hear you wonder, well my background is primarily from working in Java. Where I first learned to put generics to work in a meaningful way. The subtle gotcha that tripped me up, I will try and explain.</p><p>So what I wanted to build is a LIFO (Last In First Out) data structure which would be loosely based on a <a href="https://en.wikipedia.org/wiki/Stack_(abstract_data_type)">Stack</a> but without the naming conventions of <em>push</em> and <em>pop</em>. Instead we have add, clear and list. I’m sure you can grasp what they will do.</p><p>So lets look at what that might look like in Swift land, keeping in mind my comments from my other post: <a href="https://medium.com/@a1cooke/extending-objective-c-objects-using-swift-3ac33fb3ada1#.jm10ahdrm">Extending Objective-C objects usingSwift</a>. We require a level of inter-operability until we hit full Swift so for now we will lean on objects from Foundation module.</p><p>Lets take a look at a first pass approach to the development of this stack.</p><pre>class Stack&lt;T&gt;: NSObject {</pre><pre> private var stack: [T]!</pre><pre> private var stackCapacity: Int!</pre><pre> private var storageKey: String!</pre><pre> var hasItems: Bool { return stack.count &gt; 0 }</pre><pre> convenience init(storageKey: String!) {</pre><pre>   self.init(storageKey: storageKey, stackCapacity: 5)</pre><pre> }</pre><pre> init(storageKey: String!, stackCapacity: Int!) {</pre><pre>   super.init()</pre><pre>   self.storageKey = storageKey</pre><pre>   self.stackCapacity = stackCapacity</pre><pre> }</pre><pre> func items() -&gt; [T] {</pre><pre>   return stack</pre><pre> }</pre><pre> func add(item: T!) {</pre><pre>   if stack.count == stackCapacity {<br>       stack.removeLast()</pre><pre>   }</pre><pre>   if !stack.contains(item) {</pre><pre>       stack.insert(item, atIndex: 0)</pre><pre>   }</pre><pre> }</pre><pre> func clear() {</pre><pre>   stack.removeAll()</pre><pre> }</pre><pre>}<br></pre><p>This appears from the outset to be a legit looking LIFO stack as described, it should just compile and work, WRONG!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bnAZKEt0jdbb65TU4OJeNQ.png" /><figcaption>Error given by XCode — Cannot convert value of type ‘T!’ to expected argument type ‘<a href="http://twitter.com/noescape">@noescape</a> _ throws -&gt; Bool’</figcaption></figure><p>So what the above error means is that <em>T</em> in this case doesn’t conform to a protocol that contains depends on in order to check if it is in fact contained within the Array.</p><p>Solution, enter <em>Equatable</em> , this is a protocol which defines how in this case objects are compared to each other. The following change fixes the above code.</p><pre>class Stack&lt;T: Equatable&gt;: NSObject {</pre><pre>}</pre><p>For completeness sake, let me explain what the above notation is saying, a I should point out what is the actual definition is that T can only be of things that conform to the Equatable protocol.</p><p>Why is this important is that, as I mentioned my background is primarily in Java so I naively thought that <em>T</em> could only ever be an object, in fact in Swift, <em>T</em> could be a primitive type, struct, enum or an Object.</p><p>For more information on Equatable in Swift NSHipster explains it better than I can: <a href="http://nshipster.com/swift-comparison-protocols/">http://nshipster.com/swift-comparison-protocols/</a></p><p>I hope someone finds this useful</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e901ec56946" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Extending Objective-C objects using Swift]]></title>
            <link>https://medium.com/@a1cooke/extending-objective-c-objects-using-swift-3ac33fb3ada1?source=rss-fac39e7c570b------2</link>
            <guid isPermaLink="false">https://medium.com/p/3ac33fb3ada1</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Alan Cooke]]></dc:creator>
            <pubDate>Tue, 26 Jan 2016 23:42:00 GMT</pubDate>
            <atom:updated>2016-01-26T23:42:00.407Z</atom:updated>
            <content:encoded><![CDATA[<p>This is a short post to share something neat I thought about this week and wrote. We are working in a codebase which contains a mixture of Obj-C and <a href="https://developer.apple.com/swift/">Swift</a>. We faced a code smell in a new View Controller we are building, which was facing down the barrel of a giant <em>if/else</em> combination.</p><p>In Zendesk our API is provided by a Rails application and as such enums are represented as strings when they are serialised in JSON. Looking at our <a href="https://developer.zendesk.com/">Developer Portal</a> where you can find about all things <a href="https://developer.zendesk.com/rest_api/docs/core/introduction">Zendesk Rest API</a>. We see this example, ticket fields</p><pre>{<br>  &quot;id&quot;<strong>:</strong>                    34,<br>  &quot;url&quot;<strong>:</strong>                   &quot;https://company.zendesk.com/api/v2/ticket_fields/34.json&quot;,<br>  &quot;type&quot;<strong>:</strong>                  &quot;subject&quot;,<br>  &quot;title&quot;<strong>:</strong>                 &quot;Subject&quot;,<br>  &quot;raw_title&quot;<strong>:</strong>             &quot;{{dc.my_title}}&quot;,<br>  &quot;description&quot;<strong>:</strong>           &quot;This is the subject field of a ticket&quot;,<br>  &quot;raw_description&quot;<strong>:</strong>       &quot;This is the subject field of a ticket&quot;,<br>  &quot;position&quot;<strong>:</strong>              21,<br>  &quot;active&quot;<strong>:</strong>                <strong>true</strong>,<br>  &quot;required&quot;<strong>:</strong>              <strong>true</strong>,<br>  &quot;collapsed_for_agents&quot;<strong>:</strong>  <strong>false</strong>,<br>  &quot;regexp_for_validation&quot;<strong>:</strong> <strong>null</strong>,<br>  &quot;title_in_portal&quot;<strong>:</strong>       &quot;Subject&quot;,<br>  &quot;raw_title_in_portal&quot;<strong>:</strong>   &quot;{{dc.my_title_in_portal}}&quot;,<br>  &quot;visible_in_portal&quot;<strong>:</strong>     <strong>true</strong>,<br>  &quot;editable_in_portal&quot;<strong>:</strong>    <strong>true</strong>,<br>  &quot;required_in_portal&quot;<strong>:</strong>    <strong>true</strong>,<br>  &quot;tag&quot;<strong>:</strong>                   <strong>null</strong>,<br>  &quot;created_at&quot;<strong>:</strong>            &quot;2009-07-20T22:55:29Z&quot;,<br>  &quot;updated_at&quot;<strong>:</strong>            &quot;2011-05-05T10:38:52Z&quot;,<br>  &quot;removable&quot;<strong>:</strong>             <strong>false</strong><br>}</pre><p>The issue with this is that in Objective-C enums are essential typedef’ed as NSUInteger. What does that really mean in simple terms is that enums are Unsigned Integers and only Unsigned integers, converting to and from a JSON representation isn’t clean or trivial.</p><p>A naive representation of this in Objective-C would look something like this code block below, using an NSString to represent type.</p><pre>@interface ZDPTicketField : NSObject</pre><pre>@property (nonatomic, readonly) NSString *title;</pre><pre>@property (nonatomic, readonly) NSString *type;</pre><pre>@property (nonatomic, readonly) NSString *fieldDescription;</pre><pre>@property (nonatomic, readonly) NSNumber *position;</pre><pre>@property (nonatomic, readonly) NSString *tag;</pre><pre>@property (nonatomic, readonly) NSString *regExpForValidation;</pre><pre>@property (nonatomic, readonly) NSArray&lt;ZDPSystemFieldOption *&gt; *systemFieldOptions;</pre><pre>@property (nonatomic, readonly) NSArray&lt;ZDPCustomFieldOption *&gt; *customFieldOptions;</pre><pre>@property (nonatomic, readonly) BOOL active;</pre><pre>@property (nonatomic, readonly) BOOL required;</pre><pre>@end</pre><p>As you can see comparing strings is not going to be fun and it never is, it’s an enum in the backend and we should be able to offer something similar in our API client.</p><p>Enter Swift!</p><p>We are always looking to use Swift on a regular basis where and when it makes sense, this is typically brand new code and as we refactor out Obj-C. Before I hear a lot of people talking about performance and the cost of enums, they make consuming model responses from an API easier then I am in favour of it with that trade off.</p><p>We created the following which works well in Swift classes however currently the converted Swift back into Objective-C doesn’t support the this notation. It means this connivence is reserved to our Swift classes but as we migrate more and more code to Swift I think it’s an acceptable compromise.</p><pre>extension ZDPTicketField {<br> <br>    enum TicketFieldType: String {</pre><pre>    case TicketForm = “ticket_form”,<br>             TicketProblem = “ticket_problem”,<br>             TicketIncidents = “ticket_incidents”,<br>             Tag = “tag”,<br>             Requester = “requester”,<br>             CC = “cc”,<br>             DueDate = “due_date”,<br>             Subject = “subject”,<br>             Description = “description”,<br>             Comment = “comment”,<br>             Status = “status”,<br>             Type = “tickettype”,<br>             BasicPriority = “basic_priority”,<br>             Priority = “priority”,<br>             Group = “group”,<br>             Assignee = “assignee”,<br>             Tagger = “tagger”,<br>             Checkbox = “checkbox”,<br>             Integer = “integer”,<br>             Regex = “regexp”,<br>             TextArea = “textarea”,<br>             Decimal = “decimal”,<br>             Text = “text”,<br>             Date = “date”,<br>             Brand = “brand”<br>    }<br> <br>    var typeEnum: TicketFieldType! { <br>        return TicketFieldType(rawValue: self.type!)<br>    }<br> <br>}</pre><p>What this results is that in Swift we can now access this extended computed property in our code and it will look and feel like an original part of our model definition.</p><pre>var currentTicketField = getSelectedTicketField()</pre><pre>if let type = currentTicketField.typeEnum {</pre><pre>    switch type {</pre><pre>        case .Subject:</pre><pre>        //Do something...<br>        break</pre><pre>    }<br>}</pre><p>I hope someone else finds it useful, I certainly had a little grin when it worked for me.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3ac33fb3ada1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using v4 Support Library FileProvider and Camera Intent]]></title>
            <link>https://medium.com/@a1cooke/using-v4-support-library-fileprovider-and-camera-intent-a45f76879d61?source=rss-fac39e7c570b------2</link>
            <guid isPermaLink="false">https://medium.com/p/a45f76879d61</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[android-app-development]]></category>
            <dc:creator><![CDATA[Alan Cooke]]></dc:creator>
            <pubDate>Wed, 09 Sep 2015 19:51:03 GMT</pubDate>
            <atom:updated>2016-10-12T09:42:42.933Z</atom:updated>
            <content:encoded><![CDATA[<p>As part of our goal to constantly improve our app, we decided to review out permissions and look to reduce the number of items we request our users to approve.</p><p>Android hasn’t helped the cause with it’s old permission model, what has been introduced in M aka Marshmallow is a vast improvement for users and developers. It offers developers the opportunity to explain to users why and what we are asking from them in terms of access to their device and or data.</p><p>But enough of a discussion on Android and it’s Permission model. Lets look at the problem at hand. We have added the <a href="https://developer.android.com/reference/android/support/v4/content/FileProvider.html">FileProvider</a> to our app in order to control access to files to and from our application.</p><p>The issue faced was when completing the action of taking a picture, the Camera/Gallery app would crash and the onActivityResult would be called.</p><pre>java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{423c0ad0 13416:com.google.android.gallery3d/u0a10020} (pid=13416, uid=10020) that is not exported from uid 10079</pre><p>An example of how to define the Support v4 FileProvider looks as follows:</p><pre>&lt;manifest&gt;<br>    ...<br>    &lt;application&gt;<br>        ...<br>        &lt;provider<br>            android:name=&quot;android.support.v4.content.FileProvider&quot;<br>            android:authorities=&quot;com.mydomain.fileprovider&quot;<br>            android:exported=&quot;false&quot;<br>            android:grantUriPermissions=&quot;true&quot;&gt;<br>            ...<br>        &lt;/provider&gt;<br>        ...<br>    &lt;/application&gt;<br>&lt;/manifest&gt;</pre><p>A naive approach would be to simply update the FileProvider definition and set the XML attribute <strong><em>export</em></strong> to <strong><em>true</em></strong>. Doing that would resulted in another <em>SecurityException</em>.</p><p>Ultimately after a lot of head scratching and soul searching I decided to try the following method that is provided within the <a href="http://developer.android.com/reference/android/content/Context.html"><em>Context</em></a> object <a href="http://developer.android.com/reference/android/content/Context.html#grantUriPermission(java.lang.String, android.net.Uri, int)"><em>grantUriPermission</em></a><em> </em>and<em> </em><a href="http://developer.android.com/reference/android/content/Context.html#revokeUriPermission(android.net.Uri, int)"><em>revokeUriPermission</em></a>.</p><p>Solution, give possible apps permission to the URI in order to complete the action. The following code snippet shows using the <em>PackageManager</em> to lookup for Activities that will respond to the <em>ACTION_IMAGE_CAPTURE</em></p><pre>Intent intent = new Intent(MediaStore.<em>ACTION_IMAGE_CAPTURE</em>);</pre><pre>List&lt;ResolveInfo&gt; resolvedIntentActivities = context.getPackageManager().queryIntentActivities(intent, PackageManager.<em>MATCH_DEFAULT_ONLY</em>);</pre><pre>for (ResolveInfo resolvedIntentInfo : resolvedIntentActivities) {<br>    String packageName = resolvedIntentInfo.activityInfo.packageName;<br><br>    context.grantUriPermission(packageName, fileUri, Intent.<em>FLAG_GRANT_WRITE_URI_PERMISSION </em>| Intent.<em>FLAG_GRANT_READ_URI_PERMISSION</em>);<br>}</pre><p>Similarly one needs to revoke access once you are done relying on the URI.</p><pre>context.revokeUriPermissionfileUri, Intent.<em>FLAG_GRANT_WRITE_URI_PERMISSION </em>| Intent.<em>FLAG_GRANT_READ_URI_PERMISSION</em>);</pre><p>I hope the following will help others who find themselves scratching their head and wondering what on earth is going on.</p><p>I welcome feedback on format and my communication of the issue, I am always keen to refine the craft of sharing knowledge.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a45f76879d61" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Problems with launch Intent searching via Package manager]]></title>
            <link>https://medium.com/@a1cooke/launch-intent-searching-via-package-manager-7c7397d45f5a?source=rss-fac39e7c570b------2</link>
            <guid isPermaLink="false">https://medium.com/p/7c7397d45f5a</guid>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[development-journal]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Alan Cooke]]></dc:creator>
            <pubDate>Sun, 19 Jul 2015 17:23:39 GMT</pubDate>
            <atom:updated>2015-07-19T17:25:45.172Z</atom:updated>
            <content:encoded><![CDATA[<p>So it took me the best part of a day of hunting and hair pulling to catch this issue.</p><p>As part of some day to day development work and trying to make my colleagues subsequent work easier I wanted to create a Utility class which would provide him with a simplified way of interacting from one app to another. In order todo this we landed on <a href="http://developer.android.com/reference/android/content/Intent.html">Intent</a> juggling and relying <a href="http://developer.android.com/reference/android/app/Activity.html#onActivityResult(int, int, android.content.Intent)">onActivityResult</a></p><p>Here is the code, before the fix:</p><pre>PackageManager manager = context.getPackageManager();</pre><pre>...<br>intent = manager.getLaunchIntentForPackage(<em>APP_PACKAGE_NAME</em>);<br>...</pre><pre>return intent;</pre><p>The problem, onActivityResult was returning before the called Activity had even rendered. Something was up, so I started to hunt in the usual places. Make sure <em>singleTop</em> or <em>singleTask</em> wasn’t set on the calling Activity, no joy…</p><p>I eventually decided to dig into some source code and found that the method <a href="http://developer.android.com/reference/android/content/pm/PackageManager.html#getLaunchIntentForPackage(java.lang.String)"><em>PackageManager#getLaunchIntentForPackage</em></a><em> </em>adds a flag to the Intent it returns, flag in question is<em>: </em><a href="http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK"><em>FLAG_ACTIVITY_NEW_TASK</em></a></p><p>For those of you who are interested can find the Source to the concrete implementation of PackageManager aka <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/app/ApplicationPackageManager.java#104">ApplicationPackageManager</a></p><p>Fix for the problem, clear the set flags, in our case we didn’t need any set</p><pre>PackageManager manager = context.getPackageManager();<br>...<br>intent = manager.getLaunchIntentForPackage(<em>APP_PACKAGE_NAME</em>);</pre><pre>if (intent != null) {<br>    intent.setFlags(0);<br>}</pre><pre>...<br>return intent;</pre><p>I am writing this up so that it hopefully helps someone else and saves some time and also for my own sanity if ever happens again, I can recall my notes.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7c7397d45f5a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Google Analytics for Android & Custom Dimensions]]></title>
            <link>https://medium.com/@a1cooke/google-analytics-for-android-custom-dimensions-1419e3245286?source=rss-fac39e7c570b------2</link>
            <guid isPermaLink="false">https://medium.com/p/1419e3245286</guid>
            <dc:creator><![CDATA[Alan Cooke]]></dc:creator>
            <pubDate>Sat, 24 May 2014 20:36:04 GMT</pubDate>
            <atom:updated>2014-05-25T13:17:57.229Z</atom:updated>
            <content:encoded><![CDATA[<h4>The little bit the documentation left out</h4><p>This being my first blog post I am going to try and make the post small and concise and hopefully as I practise my writing I will be able to refine the process further and further and hopefully deliver content people will want to read.</p><p>This first blog post is hoping to save people the time and effort it took me to figure this stuff out, while straight forward once you know how, there is a distinct disconnect in the documentation I was using.</p><p><a href="https://developers.google.com/analytics/devguides/collection/android/v3/">Google Analytics SDK Documentation</a> (v3, because thats the version I’m currently working with)</p><p>Google Analytics offers a wealth of information and power in terms of tracking user behaviour while using your app. Recently I was asked to see if we could enhance the data collected to extract what screen orientation user actions were taking place.</p><p>My first thought was that the EasyTracker in Google Analytics should have had this by default but it appears not.</p><p>The best approach to achieve this is to use a custom dimension. I have broken it down into three succinct steps:</p><h4>Step 1: Configure you Analytics Account with the new Custom Dimension</h4><p>Launch your Google Analytics Account and Access the Admin tab</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9mP1s0c3xI5e4BmBp-5Jbg.png" /><figcaption>The Admin Tab for your Google Analytics Account</figcaption></figure><p>Once selected you should see the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/243/1*4dZys4hFh2hiQV13eku5WQ.png" /></figure><p>Here you can select the “Custom Definitions” section which will expanded a list of a available options; here select “Custom Dimensions”</p><p>Once selected it will present you with a table view of all the already defined custom dimensions if any.</p><p>As table views aren’t that exciting I decided you didn’t need a picture of it.</p><p>The next to step is to create a new custom dimension definition.</p><p>This can be done by click on the button titled “+ New Custom Dimension”</p><p>Next you will be presented with a couple of options when defining the custom dimension.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/449/1*jzWZna8mXMvB83XCwJq2aQ.png" /></figure><p>Here you have three options.</p><p>Name — An arbitray string, you wish to use to describe the data collection</p><p>Scope — Three available options are here Hit, Session, User (I’ll explain these in a moment)</p><p>Active — A boolean of if the data should be gathered</p><p>Hit — is a value that is tracked per event</p><p>Session — is a value that is tracked per user session</p><p>User — is a value that is tracker per user</p><p>More information can be found here: <a href="https://developers.google.com/analytics/devguides/platform/customdimsmets#scope">Scope value explained</a></p><p>As I mentioned at the start of the blog this was the piece of the puzzle I had been missing from the documentation of the SDK, either I missed it but I am pretty sure it makes no reference to needing to complete this step.</p><p>Without the definition, your code can send custom data to it’s heart’s content but Google Analytics will rightly just ignore it.</p><p>Last step is to click “Create”. This will then show up in the table of available of Custom Dimensions defined for the Application you wish to track.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8Xq5ohf-mKd-X0sDrI99_A.png" /></figure><p>The piece for you as the developer is to make note of the <em>Index</em>, this Integer is now valuable to you when adding the custom event to your tracking code.</p><h4>Step 2: Add the appropriate code to include the new Custom Dimension</h4><p>Hopefully this should be a pretty short step, the Tracker APIs that I am currently using are pretty straight forward to use and provides an Event Builder which makes the majority of the Event Map creation very straight forward.</p><p>Here is an example of some code that tracks events and send them to Google</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*85fw6Y2VBgX96sOi3wkVKA.png" /></figure><p>Now to add in the Custom Dimension code</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eWtkd60OabHdVVrkYDy9gw.png" /></figure><p>Thats all you have todo to track the now custom event, for brevity sake, assume that <em>getScreenOrientation</em> returns a string of the device’s current orientation. Additionally I know referencing the <em>1</em> in is very bad practise but for purpose of spelling out the relationship between the index presented in the admin panel and your code.</p><h4>Step3: Test on a developer account</h4><p>Great success you have achieved custom dimension tracking as part of your standard Google Analytics Event tracking. The difficulty here is that testing has a 24 hour lead time, once you have your event tracking code in place, test out your app using a test app profile.</p><p>Once you have data in place you can view this in the Google Analytics <em>Reporting -&gt; Behaviour -&gt; Top Events</em></p><p>Here you can should see a list of events that have occurred in your app, next step is to include the custom dimension. Pressing the “Secondary Dimension” button should present a popover with all the available options.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/712/1*_sBoApHXiKUIJ9LZ5WDvwQ.png" /></figure><p>Selecting Screen Orientation, will include the newly collected data as part of your report and should provide you with better insight to how people are using your app and in what orientation.</p><p>As a first blog post I hope someone else finds it somewhat useful.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1419e3245286" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>