Matt Compton - Big Nerd Ranch Tue, 19 Oct 2021 17:46:17 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 Optimize Battery Life with Android’s GCM Network Manager https://bignerdranch.com/blog/optimize-battery-life-with-androids-gcm-network-manager/ https://bignerdranch.com/blog/optimize-battery-life-with-androids-gcm-network-manager/#respond Tue, 05 Apr 2016 09:53:37 +0000 https://nerdranchighq.wpengine.com/blog/optimize-battery-life-with-androids-gcm-network-manager/ The [GCM Network Manager](https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager) simplifies common networking patterns like waiting for network connectivity, network retries and backoff. Essentially, the GCM Network Manager allows developers to focus a little less on networking issues and more on the actual app, by providing a straightforward API for scheduling network requests.

The post Optimize Battery Life with Android’s GCM Network Manager appeared first on Big Nerd Ranch.

]]>

The GCM Network Manager enables apps to register services that perform network-oriented tasks, where a task is an individual piece of work to be done. The API helps with scheduling these tasks, allowing Google Play services to batch network operations across the system.

The API also helps simplify common networking patterns, such as waiting for network connectivity, network retries and backoff. Essentially, the GCM Network Manager allows developers to focus a little less on networking issues and more on the actual app, by providing a straightforward API for scheduling network requests.

Battery Concerns and Networking

Before diving into the GCM Network Manager and what it offers, let’s take a detour and talk about battery concerns in relation to network requests, so that we understand why batching together network calls is important.

Here’s a diagram of the Android radio state machine:

Radio State Machine

It’s pretty straightforward. I include the diagram to reinforce the idea that waking up the radio is the most costly process when dealing with network connectivity. As such, network calls are one of the largest consumers of battery.

No single network transaction kills the battery, though, but rather the sheer number of individual requests that wake up the radio. If network requests are launched separately from one another, then the device is constantly awoken and the radio turned on. A device being constantly woken and unable to sleep causes a significant drain on the battery (just like with people who can’t sleep).

The diagram below shows an individual network request from an image fetching app called PhotoGallery, one of the sample apps from our best-selling Android programming book:

Single Network Request

Well, a single request doesn’t look so bad. The radio is awoken for it, but hey—it’s only one request, right?

Now here’s a diagram with multiple network calls:

Multiple Network Request

Suddenly we have multiple requests, and notice how the radio has woken up for each one, which will quickly drain the battery and annoy the end user.

We can easily improve battery life by making network calls in batches, as this optimizes the cost of starting up the radio. If the most expensive part of the radio lifecycle is the initial waking-up stage, then we’ll simply wake it up only once across these multiple requests. This method works well if the data being requested isn’t needed immediately, but instead will be used at some point in the future.

Here’s a diagram of the batched network calls:

Batched Network Request

Now the radio is only awoken once, saving battery life.

Sometimes you do need network calls immediately, like when you’re playing a game or sending a message. For those occasions, you should continue as normal with the individual network requests, but keep in mind that this type of network call does not optimize for battery life, network conditions or reboots.

GcmTaskService

Now that we’ve seen the usefulness of batching multiple network requests in order to optimize for battery efficiency, let’s dive into how to implement GCM Network Manager in an app.

First, add the appropriate dependency for the GCM Network Manager to the build.gradle file:

dependencies {
    ...
    compile 'com.google.android.gms:play-services-gcm:8.1.0'
    ...
}

Make sure to depend only on the GCM subset of Google Play Services, or you will import all of Google Play Services, adding many methods and unnecessary bulk to your app.

Next, we must declare a new Service in the Android Manifest:

<service android:name=".CustomService"
        android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE"
        android:exported="true">
   <intent-filter>
       <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
   </intent-filter>
</service>

The name of the service (CustomService) is the name of the class that will extend GcmTaskService, which is the core class for dealing with GCM Network Manager. This service will handle the running of a task, where a task is any piece of individual work that we want to accomplish. The intent-filter of action SERVICE_ACTION_EXECUTE_TASK is to receive the notification from the scheduler of the GCM Network Manager that a task is ready to be executed.

Next, we’ll actually define the GcmTaskService, making a CustomService.java class that extends GcmTaskService:

public class CustomService extends GcmTaskService {
        ...
}

This is the class that will handle a task anytime it’s being run. Due to extending GcmTaskService, we must implement the onRunTask method in CustomService:

@Override
public int onRunTask(TaskParams taskParams) {
        Log.i(TAG, "onRunTask");
        switch (taskParams.getTag()) {
                case TAG_TASK_ONEOFF_LOG:
                        Log.i(TAG, TAG_TASK_ONEOFF_LOG);
                        // This is where useful work would go
                        return GcmNetworkManager.RESULT_SUCCESS;
                case TAG_TASK_PERIODIC_LOG:
                        Log.i(TAG, TAG_TASK_PERIODIC_LOG);
                        // This is where useful work would go
                        return GcmNetworkManager.RESULT_SUCCESS;
                default:
                        return GcmNetworkManager.RESULT_FAILURE;
        }
}

This is what’s called when it’s time for a task to be run. We check the tag of the TaskParams that’s been given as a parameter, as each tag will uniquely identify a different task that’s been scheduled. Normally some important networking task or logic would occur inside the case blocks, but this example just prints a log statement.

GcmNetworkManager

Now that we’ve set up our GcmTaskService, we must grab a reference to the GcmNetworkManager object, which will be our hook into scheduling new tasks to be run for our previously defined service.

private GcmNetworkManager mGcmNetworkManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        mGcmNetworkManager = GcmNetworkManager.getInstance(this);
}

The GcmNetworkManager object will be used to schedule tasks, so one way to do this is to hold a reference as a member variable in onCreate. Alternatively, you can just get an instance of the GcmNetworkManager when you need it for scheduling.

Scheduling Tasks

A single task is one individual piece of work to be performed, and there are two types: one-off and periodic.

We provide the task with a window of execution, and the scheduler will determine the actual execution time. Since tasks are non-immediate, the scheduler can batch together several network calls to preserve battery life.

The scheduler will consider network availability, network activity and network load. If none of these matter, the scheduler will always wait until the end of the specified window.

Now, here’s how we would schedule a one-off task:

Task task = new OneoffTask.Builder()
              .setService(CustomService.class)
              .setExecutionWindow(0, 30)
              .setTag(LogService.TAG_TASK_ONEOFF_LOG)
              .setUpdateCurrent(false)
              .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
              .setRequiresCharging(false)
              .build();

mGcmNetworkManager.schedule(task);

Using the builder pattern, we define all the aspects of our Task:

  • Service: The specific GcmTaskService that will control the task. This will allow us to cancel it later.
  • Execution window: The time period in which the task will execute. First param is the lower bound and the second is the upper bound (both are in seconds). This one is mandatory.
  • Tag: We’ll use the tag to identify in the onRunTask method which task is currently being run. Each tag should be unique, and the max length is 100.
  • Update Current: This determines whether this task should override any pre-existing tasks with the same tag. By default, this is false, so new tasks don’t override existing ones.
  • Required Network: Sets a specific network state to run on. If that network state is unavailable, then the task won’t be executed until it becomes available.
  • Requires Charging: Whether the task requires the device to be connected to power in order to execute.

All together, the task is built, scheduled on the GcmNetworkManager instance, and then eventually runs when the time is right.

Here’s what a periodic task looks like:

Task task = new PeriodicTask.Builder()
                        .setService(CustomService.class)
                        .setPeriod(30)
                        .setFlex(10)
                        .setTag(LogService.TAG_TASK_PERIODIC_LOG)
                        .setPersisted(true)
                        .build();

mGcmNetworkManager.schedule(task);

It seems pretty similar, but there are a few key differences:

  • Period: Specifies that the task should recur once every interval at most, where the interval is the input param in seconds. By default, you have no control over where in that period the task will execute. This setter is mandatory.
  • Flex: Specifies how close to the end of the period (set above) the task may execute. With a period of 30 seconds and a flex of 10, the scheduler will execute the task between the 20-30 second range.
  • Persisted: Determines whether the task should be persisted across reboots. Defaults to true for periodic tasks, and is not supported for one-off tasks. Requires “Receive Boot Completed” permission, or the setter will be ignored.

We’ve now seen the real strength of using the GCM Network Manager API, as the creation and scheduling of tasks is both simple and flexible.

Canceling Tasks

We saw how to schedule tasks, so now we should also take a look at how to cancel them. There’s no way to cancel a task that is currently being executed, but we can cancel any task that hasn’t yet run.

You can cancel all tasks for a given GcmTaskService:

mGcmNetworkManager.cancelAllTasks(CustomService.class);

And you can also cancel a specific task by providing its tag and GcmTaskService:

mGcmNetworkManager.cancelTask(
        CustomService.TAG_TASK_PERIODIC_LOG,
        CustomService.class
);

In either case, remember that an in-flight task cannot be canceled.

Google Play Services

The entry point to scheduling a task with the network manager is the schedule method that we used earlier, which requires Google Play Services. In order to safely use Google Play Services, we should always check for its existence, like so:

int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode == ConnectionResult.SUCCESS) {
        mGcmNetworkManager.schedule(task);
} else {
        // Deal with this networking task some other way
}

If Google Play Services is unavailable, the GcmNetworkManager will just silently fail—so you should always check.

In a similar vein, when Google Play Services or the client app is updated, all scheduled tasks will be removed. To avoid losing all your currently scheduled tasks, GcmNetworkManager will invoke our GcmTaskService’s (so CustomService’s) onInitializeTasks() method. This method should be used to reschedule any tasks, which is most common when dealing with periodic tasks. Here’s an example:

@Override
public void onInitializeTasks() {
    super.onInitializeTasks();
    // Reschedule removed tasks here
}

Simply override this function and reschedule the necessary tasks within it.

Wrapping Up

Phew! We took a deep look at the GCM Network Manager and how to use it to conserve battery life, optimize network performance, and peform bits of batched work using Tasks. The next time you need to perform a bit of networking logic on a particular schedule, consider using the GCM Network Manager for a streamlined yet robust approach.

If you found this blog post interesting and would like to learn more about the exciting features of Android Marshmallow or the various new community tools, then check out our Android bootcamps:

The post Optimize Battery Life with Android’s GCM Network Manager appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/optimize-battery-life-with-androids-gcm-network-manager/feed/ 0
Building Custom Lint Checks in Android https://bignerdranch.com/blog/building-custom-lint-checks-in-android/ https://bignerdranch.com/blog/building-custom-lint-checks-in-android/#respond Wed, 10 Feb 2016 09:53:37 +0000 https://nerdranchighq.wpengine.com/blog/building-custom-lint-checks-in-android/ Lint is a static analysis tool that can help identify bugs and problems in a software project. While it's been around for many years, Lint has remained a timeless tool that's been ported to a multitude of different platforms. There is great power in the Android Lint API, as you can create your own custom Lint rules. This post will go through an example of building a custom Lint check that identifies when an Enum is being used.

The post Building Custom Lint Checks in Android appeared first on Big Nerd Ranch.

]]>

Lint is a static analysis tool that can help identify bugs and problems in a software project. While it’s been around for many years, Lint has remained a timeless tool that’s been ported to a multitude of different platforms. Out of the box, Android Lint has more than 200 different checks, ranging from obscure performance improvements to security issues and even internationalization concerns.

With a bit of searching, you can find the source code for all of the existing Android Lint checks. Peruse at your own risk—it’s a sparsely documented non-final fluctuating API hellscape.

Despite that, there is great power in the Android Lint API, as you can create your own custom Lint rules. You can easily write a rule, then have it be statically checked across some or all of your projects. You can distribute it locally so only you can use it, or you could throw it into continuous integration so your team could use it. This can be useful if you’re in an environment where certain coding standards must be enforced, such as targeting a certain API level or higher. If you’re writing a library and want to check that it’s being accessed correctly, then you could write a custom Lint rule and distribute it with the library.

In this post, we will go through an example of building a custom Lint check that identifies when an Enum is being used (because some folks dislike Enums). We’ll also cover how to unit test your new Lint check, so that we have some level of trust in its veracity. But as a disclaimer before we begin, the Lint API is not public or final—it can and will change, rendering our custom Lint check example code obsolete. However, the principles and topics herein should remain useful to anyone attempting to build custom Lint checks.

Four Parts to Every Lint Check

There are four main parts to every Lint check: Implementations, Issues, Detectors, and the Registry. We’ll cover each in more depth later on, but here are the basics:

  • Issues – An Issue is a possible problem or bug in an Android application. These are what Lint is checking for, such as redundant XML layouts or forgetting to have a launcher Activity. Each time Lint is run and returns a list of possible problems; those are Issues.
  • Detectors – A Detector scours your code searching for Issues. A single Detector can search for multiple independent but related Issues, such as finding multiple Android Manifest Issues using a single Detector.
  • Implementations – An Implementation connects an Issue to a particular Detector class and also states where to look for a given Issue. For example, an Implementation could tell a Detector meant to check for layout problems to only look in certain XML files.
  • Registries – A Registry is a listing of all of the Issues that Lint will care about when run. The default Issues being checked by Lint are all listed in the BuiltinIssueRegistry class. Since we’ll be writing our custom Issues, we’ll also have to provide our own custom Registry that will be included in our final packaged JAR output.

Together, these parts will combine to form a full Lint check. Here’s a nice diagram displaying the relationships between all of these individual pieces:

Lint Check Architecture

The Registry is just a listing of all of its Issues, but the other pieces can all be interplayed and reused. So harkening back to our example Lint check that searches for Enum usage, we’ll have to create a few parts:

  • an Issue that encapsulates the idea of an Enum being used
  • a Detector that can search Java files for an Enum declaration
  • an Implementation that points to our new Detector and provides a Scope to be searched (all Java files)
  • a Registry that contains a list of all of our new Issues (a list with just one item)

With all of those pieces, we will then unit test that they interact correctly. As a final output, we’ll build a JAR file that can be installed and used alongside all the other default Lint checks, whether locally or in a continuous integration environment.

You should build the custom Lint Detector in its own Android Studio module or even its own project, so the Lint check will be reusable and not tied to a specific project. To start, let’s add a few lines to our build.gradle dependencies:

dependencies {
    compile 'com.android.tools.lint:lint:24.3.1'
    compile 'com.android.tools.lint:lint-api:24.3.1'
    compile 'com.android.tools.lint:lint-checks:24.3.1'
}

Now we can dive into the details.

The Implementation

The Implementation of our Lint check is part of an Issue, pointing to the Detector class and Scope set. Without the Implementation, the Issue wouldn’t know how to be identified or where to look for the problem.

Here’s an example, from EnumDetector.java:

private static final Class<? extends Detector> DETECTOR_CLASS = EnumDetector.class;
private static final EnumSet<Scope> DETECTOR_SCOPE = Scope.JAVA_FILE_SCOPE;

private static final Implementation IMPLEMENTATION = new Implementation(
        DETECTOR_CLASS,
        DETECTOR_SCOPE
);

There are two parameters to take care of:

  • Detector Class – This points to the Detector that our Implementation will use. In this example, we’ll point to our custom EnumDetector.java class, which scours our code for Enums (we’ll look at it more closely later). The type of the Detector parameter is Class<? extends Detector>, so we can use any custom class that descends from the provided Detector superclass.
  • Scope Set – The Scope is an EnumSet<Scope>, which describes the set of file scopes that an Issue can be found in. Possibilities include (but are not limited to) resource files, Java source files, Java class files, Proguard configuration files, Android Manifest files and all files in the project. It’s important to limit the Scope to be as narrow as possible. For instance, if the Issue only appears in the Android Manifest, then don’t use Scope.ALL but instead Scope.MANIFEST_SCOPE. If Lint is being used on a per-file basis automatically (such as in an IDE), then limiting the Scope will improve performance by allowing Lint to check for Issues only within that file’s Scope. In our Enum-searching case, we set the Scope to be Scope.JAVA_FILE_SCOPE, since Enums will only be defined in a Java source file.

As a side note, we define the Implementation itself inside of the Detector used in the Implementation, and later we’ll even define the Issue in that same Detector. Defining these three parts of a Lint check in one file is useful if our Detector is searching for one Issue with a single Implementation. In other cases, we will want to break out the various pieces into their own distinct classes.

The Issue

An Issue represents a problem that Lint should check—it’s what we’re looking for. In our case, our Issue is that an Enum is being used. Issues are nothing but data representations of different situations that occur.

The following code snippet is an example of an Issue, defined inside EnumDetector.java:

private static final String ISSUE_ID = "Enum";
private static final String ISSUE_DESCRIPTION = "Avoid Using Enums";
private static final String ISSUE_EXPLANATION = "No real Android programmer should ever use enums. EVER.";
private static final Category ISSUE_CATEGORY = Category.PERFORMANCE;
private static final int ISSUE_PRIORITY = 5;
private static final Severity ISSUE_SEVERITY = Severity.WARNING;

public static final Issue ISSUE = Issue.create(
        ISSUE_ID,
        ISSUE_DESCRIPTION,
        ISSUE_EXPLANATION,
        ISSUE_CATEGORY,
        ISSUE_PRIORITY,
        ISSUE_SEVERITY,
        IMPLEMENTATION  // This was defined in the "Implementations" section
);

As shown above, we create a custom Issue by using the static create() method with these parameters:

  • ID – Each Issue has a constant ID value that should be short, descriptive and unique among all Issues. The ID should never be null. The general convention is to just use a single camel-cased word.
  • Description – The description is a brief single-line summary of the Issue, used to give a high-level idea of what this Issue concerns.
  • Explanation – The explanation is a longer summary of the Issue, explaining in depth to the user what it means. The description parameter is usually too brief to convey the details of a Lint Issue, so the explanation is where you explain fully and provide context. The explanation is always shown in the HTML output for a Lint check, though it also can be integrated into an IDE’s Lint tooling.
  • Category – The category is a bucket that an Issue falls into. There are several categories predefined, and categories can also be nested for really specific Issues. Categories are useful because a user can filter and sort Issues, which allows for including or excluding Issues in a given Lint run on a per-category basis.
  • Priority – The priority is a numerical ranking of how important an Issue is. The ranking is used to compare, rank and sort Issues. The ranking runs from 1 to 10, with 10 being the most important.
  • Severity – The severity determines how bad the Issue is in a build and compilation sense, with the possibilities being fatal, error, warning or ignore. Fatal and error severities are both considered build errors. Fatal Issues are considered slightly more severe, as they will be checked automatically during APK assembling. If a fatal Issue is detected, then the build is canceled. Warning is the most common severity, and it still allows the build to succeed. Any Issues with a severity of ignore aren’t checked.
  • Implementation – This is the same as you saw earlier: the Implementation points to an Issue’s Detector class and also gives a Scope set of where the Issue is applicable.

The ID, description and explanation are all describable values related to Enums, while the category, priority and severity have predefined values chosen from their respective classes. We chose the Performance Category because Enum usage can have negative effects on an app’s performance, and we gave it a priority of 5 out of 10 because it’s not that important. The Severity of Warning means the build will still pass, but will be flagged as a potential problem. Filling out the builder method is all it takes to create our own Issue!

However, the heart of a Lint check lies elsewhere: in the Detector.

The Detector

The Detector is responsible for scanning through code, finding individual Issue instances and reporting them. Detectors can find and report multiple Issue types, which can be useful if two distinct Issues might appear in similar circumstances (think about all the different Android Manifest checks).

A Detector implements one of the Scanner interfaces, which give it the ability to scan through code. The three possibilities are XmlScanner, JavaScanner and ClassScanner, used for XML files, Java files and class files, respectively. If we want to detect an Issue in the Android Manifest, then we’d be using the XmlScanner interface. To find Enums, we’ll be using JavaScanner.

The various Scanners search through code via the lombok.ast API, which represents code as an Abstract Syntax Tree, or AST. Instead of lines of code, you get a searchable tree. Lombok provides utilities and hooks for parsing through these trees, allowing you to find specific pieces of code that you care about for your Issues.

Without further ado, here’s the rest of the EnumDetector.java file, which includes all of the heavy lifting for the Lint check:

public class EnumDetector extends Detector implements Detector.JavaScanner {

    ... // Implementation and Issue code from above

    /**
     * Constructs a new {@link EnumDetector} check
     */
    public EnumDetector() {
    }

    @Override
    public boolean appliesTo(@NonNull Context context, @NonNull File file) {
        return true;
    }

    @Override
    public EnumSet<Scope> getApplicableFiles() {
        return Scope.JAVA_FILE_SCOPE;
    }

    @Override
    public List<Class<? extends Node>> getApplicableNodeTypes() {
        return Arrays.<Class<? extends Node>>asList(
                EnumDeclaration.class
        );
    }

    @Override
    public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
        return new EnumChecker(context);
    }

    private static class EnumChecker extends ForwardingAstVisitor {

        private final JavaContext mContext;

        public EnumChecker(JavaContext context) {
            mContext = context;
        }

        @Override
        public boolean visitEnumDeclaration(EnumDeclaration node) {
            mContext.report(ISSUE, Location.create(mContext.file), ISSUE.getBriefDescription(TextFormat.TEXT));
            return super.visitEnumDeclaration(node);
        }

    }

}

Let’s break it down. The Detector is instantiated by Lint each time we run a Lint check, similar to how JUnit will tear down and rebuild everything between runs. To allow Lint to automatically instantiate your Detector, we provide a public default constructor. Technically, the Java compiler will provide one for you automatically if you leave it out, but we’re going to define ours explicitly as a reminder that the system is using it.

Here are the methods again:

@Override
public boolean appliesTo(@NonNull Context context, @NonNull File file) {
    return true;
}

The appliesTo(...) method is a hook to determine if a given file is valid and should be scanned, and we return true to check everything in our given Scope.

@Override
public EnumSet<Scope> getApplicableFiles() {
    return Scope.JAVA_FILE_SCOPE;
}

The getApplicableFiles() method defines the Scope of our Detector, which for this example is all Java files.

@Override
public List<Class<? extends Node>> getApplicableNodeTypes() {
    return Arrays.<Class<? extends Node>>asList(
            EnumDeclaration.class
    );
}

The getApplicableNodeTypes() method is where things get interesting. A “node” in this sense is a particular segment or piece of code. A node could be a class declaration or a method invocation or even a comment. We care only about the specific case of an Enum being declared, so we return a list of one valid node type: EnumDeclaration.class.

@Override
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
    return new EnumChecker(context);
}

Now that our Detector knows to apply only to Java files and hook into only Enum declaration nodes, the next step is to traverse our tree and hit the nodes, one by one. The createJavaVisitor(...) method is our Lombok hook into traversing our Java tree. We create an inner class called EnumChecker to represent the process of checking this tree for the nodes we care about:

private static class EnumChecker extends ForwardingAstVisitor {

    private final JavaContext mContext;

    public EnumChecker(JavaContext context) {
        mContext = context;
    }

    @Override
    public boolean visitEnumDeclaration(EnumDeclaration node) {
        mContext.report(ISSUE, Location.create(mContext.file), ISSUE.getBriefDescription(TextFormat.TEXT));
        return super.visitEnumDeclaration(node);
    }

}

Since we have only one applicable node type being checked, our inner class just has the one overridden method of visitEnumDeclaration(...). For each Enum declaration that is detected while traversing the AST, this method will be called exactly once. All it’s going to do when called is report the Issue being found.

When an Issue is found, we use the report(...) method. The method parameters are an Issue being reported, a location where the Issue was found, and a brief description of the Issue. There are other versions of the report(...) method where you can specify exact line numbers and give more detailed information. For our purposes, the simplest report works fine.

Our Detector can now search through Java files, identify Enum declaration nodes and then yell at us by reporting on each of the instances.

The Registry

An individual Registry is a list of all of the Issues that Lint should care about from a given JAR of Lint rules. By default, Lint pulls from one Registry, the aptly-named BuiltinIssueRegistry class, which lists more than 200 different Issues. We can include our own custom EnumIssue in the overall list of Lint Issues by providing our own Registry. The Registry is packaged inside of the final JAR output and will point to all of the fun new Issues that we’ve provided.

The code for a custom Registry extends the abstract IssueRegistry class and overrides a single method:

public class CustomIssueRegistry extends IssueRegistry {

    private List<Issue> mIssues = Arrays.asList(
            EnumDetector.ISSUE   // Could totally add more here
    );

    public CustomIssueRegistry() {
    }

    @Override
    public List<Issue> getIssues() {
        return mIssues;
    }

}

Since the Registry is just a hook for Lint to grab all of the provided Issues, there’s not much excitement here. We override the getIssues() method so Lint gets our list, and we also provide a default empty constructor (which is required) so that the system can easily instantiate our new Registry.

There’s an additional step for our Registry to be found, however. We have to make some changes to our build.gradle file, where we’ll add some information about the output JAR that will be built:

jar {
    baseName 'com.bignerdranch.linette'
    version '1.0'

    manifest {
        attributes 'Manifest-Version': 1.0
        attributes('Lint-Registry': 'com.bignerdranch.linette.registry.CustomIssueRegistry')
    }
}

For the basename, version and Manifest Version, use the package name and whatever version you’re on. The important piece is the Lint-Registry attribute, which needs to be the fully qualified path of our custom Issue Registry. Now, the manifest (i.e., the metadata) of our output JAR will contain the path to our Registry. Lint will use this path to identify all of the new Issues that we introduce.

As far as implementing the custom Lint check itself goes, we’re done! That’s all of the parts: Implementation, Issue, Detector and Registry. However, for ease of use and veracity purposes, we’re going to add some tests before covering how to build the JAR.

Testing

While testing on Android is notoriously annoying, testing Lint checks is surprisingly easy. The first thing we need to do is add a few dependencies to our build.gradle:

dependencies {
    testCompile 'junit:junit:4.11'
    testCompile 'org.assertj:assertj-core:3.0.0'
    testCompile 'org.mockito:mockito-core:1.9.5'
    testCompile 'com.android.tools.lint:lint:24.3.1'
    testCompile 'com.android.tools.lint:lint-tests:24.3.1'
    testCompile 'com.android.tools:testutils:24.3.1'
}

The next step is to specify our source sets explicitly, so that our project will better understand its own structure. We need to do this so our tests will know where to find the test-resources directory.

sourceSets {
    main {
        java {
            srcDirs = ["lint/src/main/java"]
        }
    }
    test {
        java {
            srcDirs = ["lint/src/test/java"]
        }
    }
}

With those new build.gradle additions, we can begin testing.

Testing the Registry

Let’s start with something simple, like testing our new Registry:

public class CustomIssueRegistryTest {

    private CustomIssueRegistry mCustomIssueRegistry;

    /**
     * Setup for the other test methods
     */
    @Before
    public void setUp() throws Exception {
        mCustomIssueRegistry = new CustomIssueRegistry();
    }

    /**
     * Test that the Issue Registry contains the correct number of Issues
     */
    @Test
    public void testNumberOfIssues() throws Exception {
        int size = mCustomIssueRegistry.getIssues().size();
        assertThat(size).isEqualTo(1);
    }

    /**
     * Test that the Issue Registry contains the correct Issues
     */
    @Test
    public void testGetIssues() throws Exception {
        List<Issue> actual = mCustomIssueRegistry.getIssues();
        assertThat(actual).contains(EnumDetector.ISSUE);
    }

}

We’re just instantiating our custom Registry and checking its size and list of Issues for correctness. There’s not much else to test here.

Testing the Detector

The more interesting (and useful) tests are for the custom Detector. These tests will pull from external sample files in your test-resources directory and run a Lint check on each of them. In my example code on Github, I abstracted away some of this logic into a superclass for reusability. Here’s a condensed version:

public class EnumDetectorTest extends LintDetectorTest {

    private static final String PATH_TEST_RESOURCES = "/lint/src/test/resources/enum/";
    private static final String NO_WARNINGS = "No warnings.";

    @Override
    protected Detector getDetector() {
        return new EnumDetector();
    }

    @Override
    protected List<Issue> getIssues() {
        return Arrays.asList(EnumDetector.ISSUE);
    }

    /**
     * Test that an empty java file has no warnings.
     */
    public void testEmptyCase() throws Exception {
        String file = "EmptyTestCase.java";
        assertEquals(
                NO_WARNINGS,
                lintFiles(file)
        );
    }

    /**
     * Test that a java file with an enum has a warning.
     */
    public void testEnumCase() throws Exception {
        String file = "EnumTestCase.java";
        String warningMessage = file
                + ": Warning: "
                + EnumDetector.ISSUE.getBriefDescription(TextFormat.TEXT)
                + " ["
                + EnumDetector.ISSUE.getId()
                + "]n"
                + "0 errors, 1 warningsn";
        assertEquals(
                warningMessage,
                lintFiles(file)
        );
    }

    @Override
    protected InputStream getTestResource(String relativePath, boolean expectExists) {
        String path = (PATH_TEST_RESOURCES + relativePath).replace('/', File.separatorChar);
        File file = new File(getTestDataRootDir(), path);
        if (file.exists()) {
            try {
                return new BufferedInputStream(new FileInputStream(file));
            } catch (FileNotFoundException e) {
                if (expectExists) {
                    fail("Could not find file " + relativePath);
                }
            }
        }
        return null;
    }

    private File getTestDataRootDir() {
        CodeSource source = getClass().getProtectionDomain().getCodeSource();
        if (source != null) {
            URL location = source.getLocation();
            try {
                File classesDir = SdkUtils.urlToFile(location);
                return classesDir.getParentFile().getAbsoluteFile().getParentFile().getParentFile();
            } catch (MalformedURLException e) {
                fail(e.getLocalizedMessage());
            }
        }
        return null;
    }

}

Phew! That’s a lot of code, so let’s break down the test file piece by piece, starting with two setup methods:

@Override
protected Detector getDetector() {
    return new EnumDetector();
}

@Override
protected List<Issue> getIssues() {
    return Arrays.asList(EnumDetector.ISSUE);
}

The getDetector() method provides the Detector that we want to test, while getIssues() provides the Issues. For these, return EnumDetector and EnumIssue, respectively.

Here are the constants from the top of the file:

private static final String PATH_TEST_RESOURCES = "/lint/src/test/resources/enum/";
private static final String NO_WARNINGS = "No warnings.";

The first constant of PATH_TEST_RESOURCES is our relative path to the test-resources directory, which is used in the getTestResource() and getTestDataRootDir() methods. Their purpose is to identify the test resource file to be used in a given test case. The second constant of NO_WARNINGS is the default Lint message when nothing is wrong, which we’ll need for test comparisons.

Here are the individual test cases again:

public void testEmptyCase() throws Exception {
    String file = "EmptyTestCase.java";
    assertEquals(
            NO_WARNINGS,
            lintFiles(file)
    );
}

public void testEnumCase() throws Exception {
    String file = "EnumTestCase.java";
    String warningMessage = file
            + ": Warning: "
            + EnumDetector.ISSUE.getBriefDescription(TextFormat.TEXT)
            + " ["
            + EnumDetector.ISSUE.getId()
            + "]n"
            + "0 errors, 1 warningsn";
    assertEquals(
            warningMessage,
            lintFiles(file)
    );
}

We have only two test cases, the empty example and a small Enum example. For each case, we point to the file that we want to test, and then we call lintFiles(String path) on the path String. If the test-resources directory setup above is correctly found, then the lintFiles() call will load the test file into memory as an on-the-fly Android project and then run a Lint check on it, returning its output as a String value.

Once we have the String of the finished Lint check, we compare against what we expected. For the empty test case, we expect a value equal to the NO_WARNINGS constant. For the Enum case, we expect a warning message that is composed of a bunch of different variables we’ve defined throughout this process. Figuring out what the actual warning message will be takes some trial and error, but the simplest of Lint checks (like what we’ve done here) will follow the String concatenation pattern used in the testEnumCase() method.

When you’re all done, here’s what you have: each test case has a test file, we run a Lint check on it, and then we examine the output to determine if it’s what we expect.

Running the Tests

My favorite way to do anything is via terminal. Navigate to the root of our custom Lint check project and run the following command:

./gradlew clean build test

Your output should look something like this:

:clean
:compileJava
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build

BUILD SUCCESSFUL

Total time: 6.373 secs

Hopefully, all is well. I highly recommend a test-driven development approach if you start building custom Lint checks. It’s a perfect use-case—provide a sample file and then write a Detector or Issue to fit the case.

Linty Fresh

If you’ve made it this far, congratulations. Your hard work is about to pay off. If you recall, the final output of our custom Lint checker is a JAR file. Anytime we want to add Lint checks to our system, we simply add a JAR file to our ~/.android/lint/ directory. The Lint tool will always check there for anything new on each run. By running the assemble Gradle task, we will generate and assemble the JAR during each build. Now, we could move the output JAR from our build directory to the Lint directory manually, but I prefer to incorporate it into the build process by adding this handy Gradle task to our build.gradle file:

defaultTasks 'assemble'

task install(type: Copy) {
    from configurations.lintChecks
    into System.getProperty('user.home') + '/.android/lint/'
}

Let’s build and install our new Lint check by running the following from a terminal at the root of our custom Lint check project:

./gradlew clean build test install

Assuming everything builds and passes, let’s check to see if our new Lint rule is now available:

lint --show Enum

If everything went smoothly, you should see the following:

Enum
----
Summary: Avoid Using Enums

Priority: 5 / 10
Severity: Warning
Category: Performance

No real Android programmer should ever use enums. EVER.

While having the Lint check available on a system level is great, the final trial is actually running our shiny new Lint check on a real project, so navigate to an actual Android application project of your choice and run the following:

./gradlew lint

You could also use Android Studio’s Analyze->Inspect Code... menu option, but that’s no fun.

Assuming all is well, the results should be found in build/outputs/lint-results.html and look something like this:

Lint Report

Ta-da! Finally, our custom Lint check is registered in the system. Now we can use it on any project. It was quite a journey: we built up an Implementation, an Issue, a Detector, a Registry and some test cases, in addition to making some Gradle magic. Lint is an under-utilized tool by many Android developers, but I hope now you can start pushing the boundaries and making the most of static code analysis.

In case you missed it earlier, here is the full source code, which actually includes a few different examples. Enjoy!

Special thanks to my coworker Jason Atwood for all of his research help, and to André Diermann, Jerzy Chalupski, and Cheng Yang for getting me started on the right path.

The post Building Custom Lint Checks in Android appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/building-custom-lint-checks-in-android/feed/ 0
Implementing Android Marshmallow Direct Share https://bignerdranch.com/blog/implementing-android-marshmallow-direct-share/ https://bignerdranch.com/blog/implementing-android-marshmallow-direct-share/#respond Wed, 09 Dec 2015 10:00:00 +0000 https://nerdranchighq.wpengine.com/blog/implementing-android-marshmallow-direct-share/ Direct Share can save the user a bit of time and make sharing content more streamlined. But how do we actually add Direct Share to an existing Android app?

The post Implementing Android Marshmallow Direct Share appeared first on Big Nerd Ranch.

]]>

Direct Share is a new feature in Android Marshmallow that allows users to share content to targets, such as contacts, within other apps. The core idea is that the user can directly share the relevant content without having to first open a second app, so Direct Share allows the user to skip a step in the usual sharing flow.

I came across Direct Share while working on our upcoming 1-day Android Platform Features and Community Tools classes, and now it’s become one of my favorite new additions in Android Marshmallow.

Direct Share Overview

One great example of Direct Share is sharing content to a contact in a messaging app. Here’s what that would end up looking like:

Direct Share Example

The usual share options appear, with Hangouts, Messages and Inbox listed at the bottom. However, the Direct Share targets are the various people listed at the top of this share dialog. Instead of clicking to share and then clicking into the desired messaging app like Hangouts, the most important contacts appear in the chooser dialog itself. In this flow, the user doesn’t have to click into the Hangouts app and then choose a contact, instead being able to choose a contact immediately.

For a compare and contrast example, we’re going to use a sample app that just shares a bit of text to a selected contact. Here’s what the share dialog looks like on Lollipop:

Example of Share Dialog on Lollipop

And here’s the Marshmallow version with Direct Share enabled:

Example of Share Dialog on Marshmallow

Now, this is the same app on both versions, so the important takeaway here is that the feature gracefully falls back on older versions of Android to the standard chooser dialog. In this way, the Direct Share options can be added to newer versions, with the sharing functionality working just the same on older versions.

Building a ChooserTargetService

So Direct Share can save the user a bit of time and make sharing content more streamlined. But how do we actually add Direct Share to an existing app?

The first step is to create a service that extends the platform’s ChooserTargetService, which is demonstrated by the following SampleChooserTargetService.java snippet:

public class SampleChooserTargetService extends ChooserTargetService {
  @Override
  public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) {
    final List<ChooserTarget> targets = new ArrayList<>();
    for (int i = 0; i < length; i++) {
      final String targetName = ...
      final Icon targetIcon = ...
      final float targetRanking = ...
      final ComponentName targetComponentName = ...
      final Bundle targetExtras = ...
      targets.add(new ChooserTarget(
          targetName, targetIcon, targetRanking, targetComponentName, targetExtras
      ));
    }
    return targets;
  }
}

Override the onGetChooserTargets() method, which will return a List of ChooserTargets that are the Direct Share options that appear in the sharing dialog.

Each ChooserTarget has a few parameters:

  • The name of the target
  • The icon to represent the target
  • The ranking score for this target (between 0.0f and 1.0f), which is used if there’s too many direct share items, then items with low ranking scores will be omitted.
  • The name of the component to start if the target is chosen
  • A Bundle of Extras that will be merged into the original Intent before launching the next component with that intent

The order of the targets in the chooser dialog is the same as the ordering of the list of targets that we provide. Any sorting of the targets should be done here, during list construction.

How you create those targets is entirely up to you, though typically the ChooserTarget information is constructed from the model layer of your specific app.

Update the Android Manifest

While we have built our ChooserTargetService, we now need to hook it up in our app, so that the system knows about the service and can use it.

First, you’ll need to declare your custom ChooserTargetService in your AndroidManifest.xml, like so:

<service
    android:name=".SampleChooserTargetService"
    android:label="@string/app_name"
    android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
    <intent-filter>
        <action android:name="android.service.chooser.ChooserTargetService" />
    </intent-filter>
</service>

This accomplishes two things:

  • Binds the Service using the android.permission.BIND_CHOOSER_TARGET_SERVICE permission
  • Includes an IntentFilter with the android.service.chooser.ChooserTargetService action

Next, you’ll need to update your AndroidManifest.xml with some meta-data tags:

<activity
    android:name=".SendMessageActivity"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <meta-data
        android:name="android.service.chooser.chooser_target_service"
        android:value=".SampleChooserTargetService" />
</activity>

For each activity that you want to expose to ChooserTargetService, add a meta-data element to it. Specify the name as android.service.chooser.chooser_target_service, and point the value to the Service defined earlier. When an implicit intent is sent out that matches with one of these activities, then the intent chooser dialog will show both the normal app icon for that activity and also the list of ChooserTarget icons. The normal app icon just opens the activity like a standard share intent would, while the ChooserTarget icons will open the activity with some initial data on the intent (specified in the ChooserTargetService).

Direct Share Flow

Let’s take a quick look at the flow between screens from a user’s perspective of Google’s Direct Share sample app. The user is starting on a normal-looking app screen, with a nice big share button that sends out an implicit intent.

Direct Share Flow (1/3)

Next, the user hits the share button, causing the share dialog to pop up.

Direct Share Flow (2/3)

When the Activity that we attached our Chooser Service to via metadata is able to respond to an implicit intent, that’s when the Chooser Service will generate its list of choices using the onGetChooserTargets() from our custom ChooserTargetService. The list of Chooser Targets will then be used to populate the dialog asking how you want to answer the intent.

In addition, the actual Activity that the meta-data was attached to will be listed alongside the generated Chooser Targets, allowing a user to just pick the Activity normally and opt away from using Direct Share. Normally, this Activity would be some kind of list of contacts or list of users to pick from.

Direct Share Flow (3/3)

If the user taps on one of the Chooser Targets, then the ‘choose a contact from a list’ step that is normally part of the flow can be skipped, and the user goes right to sending the content, wherever that may lead.

Avoid Clutter

We must always remember to be a good citizen—while Direct Share is neat feature, you shouldn’t use it in a way that clutters up the chooser dialog with unnecessary options. Otherwise, you might drown out the sharing options your users actually want.

Cluttered Sharing

In the above example, the app lists eight different users as Chooser Targets, but perhaps only the most frequently messaged contacts should be shown instead.

Learning More

Direct Share is an excellent way to streamline the user experience of sharing content, allowing users to share more easily to their most common targets.

If you found this blog post interesting and would like to learn more about the exciting features of Android Marshmallow or the various new community tools, then check out our new pair of one-day classes on the Android Platform and Community Tools. As a bonus, we’ll be taking these classes on the road, visiting cities around the continental United States. See you there!

The post Implementing Android Marshmallow Direct Share appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/implementing-android-marshmallow-direct-share/feed/ 0
ViewPager Without Fragments https://bignerdranch.com/blog/viewpager-without-fragments/ https://bignerdranch.com/blog/viewpager-without-fragments/#respond Thu, 30 Jul 2015 10:00:00 +0000 https://nerdranchighq.wpengine.com/blog/viewpager-without-fragments/ Every once in a while, an Android developer might want to use a ViewPager without the added complexity of also using Fragments. A good example is an image gallery, where the user can swipe between different pictures. On these types of pages, all you really want to display is a view of static content (in this case an image), so I'm going to walk you through how to utilize the ViewPager with just plain-old Views and layouts.

The post ViewPager Without Fragments appeared first on Big Nerd Ranch.

]]>

Every once in a while, an Android developer might want to use a ViewPager without the added complexity of also using Fragments. A good example is an image gallery, where the user can swipe between different pictures. On these types of pages, all you really want to display is a view of static content (in this case, an image), so I’m going to walk you through how to utilize the ViewPager with just plain-old Views and layouts.

Initial Setup

Your journey begins with laying some foundational work with an XML layout, a build.gradle file and the Activity that the ViewPager will live in.

layout/activity_main.xml

Here’s your XML layout for the Activity, which consists solely of a ViewPager.

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

build.gradle

Don’t forget to add the support library as a gradle dependency. In newer versions of Android Studio, this should be added automatically at project creation.

dependencies {
    compile 'com.android.support:support-v4:22.0.0'
}

MainActivity.java

Next you setup an Activity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        viewPager.setAdapter(new CustomPagerAdapter(this));
    }

}

Nothing too exciting here, just grabbing a reference to your ViewPager and then setting its adapter to the super-special CustomPagerAdapter that will be covered later. This initial setup could also be done in a Fragment’s onCreateView() method.

Need to know how to keep your development project on track and in budget? Download your eBook.

Model Object

Personally, I like to have a model object representing the possible pages in the ViewPager. The below enum is essentially a listing of all of your ViewPager’s pages, with tidbits of information about each one thrown in, such as the page title and the layout to be shown. In reality, this could contain any information specific to a particular screen in your ViewPager.

public enum CustomPagerEnum {

    RED(R.string.red, R.layout.view_red),
    BLUE(R.string.blue, R.layout.view_blue),
    ORANGE(R.string.orange, R.layout.view_orange);

    private int mTitleResId;
    private int mLayoutResId;

    CustomPagerEnum(int titleResId, int layoutResId) {
        mTitleResId = titleResId;
        mLayoutResId = layoutResId;
    }

    public int getTitleResId() {
        return mTitleResId;
    }

    public int getLayoutResId() {
        return mLayoutResId;
    }

}

Again, this enum isn’t strictly necessary, but it helps organize the separation of the content (the actual screen being shown) and the controller (the ViewPager).

PagerAdaper

The PagerAdapter is the core piece of this exercise. Everything that you’ve done so far is to make your life a bit easier when dealing with the PagerAdapter. So, here it is:

public class CustomPagerAdapter extends PagerAdapter {

    private Context mContext;

    public CustomPagerAdapter(Context context) {
        mContext = context;
    }

    @Override
    public Object instantiateItem(ViewGroup collection, int position) {
        CustomPagerEnum customPagerEnum = CustomPagerEnum.values()[position];
        LayoutInflater inflater = LayoutInflater.from(mContext);
        ViewGroup layout = (ViewGroup) inflater.inflate(customPagerEnum.getLayoutResId(), collection, false);
        collection.addView(layout);
        return layout;
    }

    @Override
    public void destroyItem(ViewGroup collection, int position, Object view) {
        collection.removeView((View) view);
    }

    @Override
    public int getCount() {
        return CustomPagerEnum.values().length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        CustomPagerEnum customPagerEnum = CustomPagerEnum.values()[position];
        return mContext.getString(customPagerEnum.getTitleResId());
    }

}

There’s a lot going on here, but don’t fret. Step by step, here’s each piece of the puzzle:

  • CustomPagerAdapter(Context context): The constructor needs a Context reference, since you’ll want to access some string and layout resources later on. You just save the Context as a member variable of the class.
  • instantiateItem: Using the LayoutInflater, you can inflate any desired XML layout. In this case, you use the enum and inflate the particular enum value’s associated layout. Next, you add the newly inflated layout to the collection of Views maintained by the PagerAdapter, and then you return that layout. The object being returned by this method is also used later on, as the second parameter in the isViewFromObject method. Both refer to a particular item in the PagerAdapter. In this case, it’s a View.
  • destroyItem: This method removes a particular view from the collection of Views maintained by the PagerAdapter.
  • getCount: You simply return the number of views that will be maintained by the ViewPager. For this example, the count is the number of enum values in the model object.
  • isViewFromObject: This method checks whether a particular object belongs to a given position, which is made simple in this example—just check whether the View equals the object (i.e., points to the same reference). As noted earlier, the second parameter is of type Object and is the same as the return value from the instantiateItem method.
  • getPageTitle: At a given position, you need to supply the PagerAdapter with a title. This usually manifests itself in the ActionBar as the Activity’s title, or sometimes tabs will hook into this method for labelling each tab.

While the PagerAdapter consists of many small pieces, each piece serves a unique and simple purpose.

Bon Voyage!

So now, if you need a ViewPager full of static content but don’t want the heavy-handedness of Fragments, you have a nifty guide to using a ViewPager and PagerAdapter dedicated to displaying solely Views. Enjoy life without Fragments!

The post ViewPager Without Fragments appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/viewpager-without-fragments/feed/ 0
Open-Source Licenses and Android https://bignerdranch.com/blog/open-source-licenses-and-android/ https://bignerdranch.com/blog/open-source-licenses-and-android/#respond Wed, 08 Jul 2015 10:00:00 +0000 https://nerdranchighq.wpengine.com/blog/open-source-licenses-and-android/

If you’ve ever written an Android application, then you’ve likely used a third-party library in the process. The library may even have been open-source, so that the community can view, copy and modify the code. However, the creators always retain certain rights over their project, and the form in which the authors express these rights is called a software license.

The post Open-Source Licenses and Android appeared first on Big Nerd Ranch.

]]>

If you’ve ever written an Android application, then you’ve likely used a third-party library in the process. The library may even have been open-source, so that the community can view, copy and modify the code. However, the creators always retain certain rights over their project, and the form in which the authors express these rights is called a software license.

If you’re interested in learning more about the specifics of software licensing, my fellow Nerd Jeremy Sherman has written an excellent blog post on the topic. And if you’re searching specifically for Android-related licensing information, then you should check out the official documentation about licenses on the Android Open Source Project. For this post, however, we will focus on the implementation details of an easy way to include a licenses dialog inside your Android application.

Android’s License Dialog Pattern

In most popular apps, there is a section (usually hidden deep in nested menu selections) that will have some text along the lines of “Licenses,” “Legal,” “Third-Party Notices” or any one of the infinite combinations of such phrases. Every application has its own unique spin on the wording, and the implementation of what occurs when actually clicked also differs wildly.

Opening a Browser

The simplest way to accomplish this is to list your third-party licenses on a web page, and open the license page URL with an implicit intent. Here, the Nest app has followed this pattern:

Nest license

Separate Activity or Fragment

And here’s Google Wallet starting a completely new Activity (or maybe it’s a Fragment):

Google Wallet license

Using a Dialog

My favorite implementation for displaying software licenses is through the use of a dialog. Google Drive has a solid example:

Google Drive license

Interestingly, even Google does not follow a standard: their implementation of this feature differs from app to app, leaving us without a Google-advocated “source of truth” for this particular pattern.

Together, we’re going to walk through the process of creating a license dialog similar to the one used in Google Drive. The process will include finding the license information for the libraries, building some HTML containing that information, shoving the HTML into a WebView, and then displaying the WebView through either an AlertDialog or DialogFragment (depending on personal preference). Ready?

Where to Find the License Information

Every non-trivial application utilizes third-party libraries from the open-source community, and finding the license for a particular library should be simple. The vast majority of open-source projects are hosted on GitHub, and the README.md file (shown as part of the landing page for the project) will usually have the license at the bottom. A great example is Square’s Picasso. Scroll to the bottom of the GitHub repository, and you’ll find a tidy “License” section that looks like this:

License


Copyright 2013 Square, Inc.

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.

When open-source projects include a license, whether in the README.md or just as a LICENSE.txt, the ability to easily use and credit that library is much simpler. Instead of being forced to sleuth around and figure out which license a particular project is using, the developer finds the information easily. So, to all library-creators and open-source contributors, please make the licensing information for your projects readily available.

For future reference, if a project does not include any license information, then you cannot copy or modify it for any reason except personal use, unless you expressly receive the permission of its creators. Tread lightly.

Constructing the HTML

Now that you know where to find the license information for an open-source project, the process of building a bit of HTML to display in a WebView may begin.

app/src/main/assets/open_source_licenses.html

<html>
<head>
    <style>
        body {
        font-family: sans-serif;
        }
        pre {
        background-color: #eeeeee;
        padding: 1em;
        white-space: pre-wrap;
        }
    </style>
</head>
<body>

<h3>
    Apache License
    <br/>
    Version 2.0, January 2004
</h3>
<ul>
    <li>
        <b>Gson</b>
        <br/>
        Copyright 2008 Google, Inc.
    </li>
    <li>
        <b>OkHttp</b>
        <br/>
        Copyright 2014 Square, Inc.
    </li>
    <li>
        <b>Picasso</b>
        <br/>
        Copyright 2013 Square, Inc.
    </li>
    <li>
        <b>Retrofit</b>
        <br/>
        Copyright 2013 Square, Inc.
    </li>
</ul>
<pre>
    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.
</pre>

<h3>
    The MIT License (MIT)
</h3>
<ul>
    <li>
        <b>Material Dialogs</b>
        <br/>
        Copyright (c) 2015 Aidan Michael Follestad
    </li>
    <li>
        <b>Robolectric</b>
        <br/>
        Copyright (c) 2010 Xtreme Labs
        <br/>
        Copyright (c) 2010 Pivotal Labs
    </li>
    <li>
        <b>Mockito</b>
        <br/>
        Copyright (c) 2007 Mockito contributors
    </li>
</ul>
<pre>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</pre>

</body>
</html>

The header contains a bit of styling information, so that the HTML looks pretty. Customize this however you want, most likely by using brand colors and theming. What follows is the actual license information, which is broken up into multiple sections, one for each license type. This example just lists all the software and copyright information for a given license, then repeats the license text itself. Again, this can be uniquely tuned to whatever style you’d like; just make sure to reproduce the copyright information (year and company) and also the physical text of the license (Apache 2.0, MIT or whatever). The end result is a nice snippet of HTML that has all of the required license information for properly crediting open-source contributors.

Constructing the WebView

The following XML layout for our dialog is succinct; it’s only a WebView that takes up the entire screen.

app/src/res/layout/dialog_licenses.xml

<?xml version="1.0" encoding="utf-8"?>
<WebView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

The HTML will be loaded into the WebView right before the dialog is created.

AlertDialog Implementation

You now have the HTML containing the licensing information and the layout file for the WebView. The next step is to display them both in a dialog, so let’s first look at implementing an AlertDialog.

MainActivity.java -> displayLicensesAlertDialog()

private void displayLicensesAlertDialog() {
    WebView view = (WebView) LayoutInflater.from(this).inflate(R.layout.dialog_licenses, null);
    view.loadUrl("file:///android_asset/open_source_licenses.html");
    mAlertDialog = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Light_Dialog_Alert)
        .setTitle(getString(R.string.action_licenses))
        .setView(view)
        .setPositiveButton(android.R.string.ok, null)
        .show();
}

This method builds an AlertDialog and then shows it on the screen. The first step is to inflate the WebView from the layout that was defined in the previous section, and then the HTML from earlier is loaded into the newly inflated WebView. After that, it’s just a matter of building up the AlertDialog using the Builder pattern, making sure to set the AlertDialog’s View to be the WebView.

The final result will look like this:

AlertDialog Implementation

While it may not be a work of art, at least credit is now being given for your usage of third-party open-source software.

DialogFragment Implementation

In case you wanted to liberally use Fragments throughout the application, let’s talk about how a DialogFragment could be used instead of an AlertDialog. One immediate benefit is that the DialogFragment will be automatically added back to the Activity on rotation, whereas the AlertDialog will be destroyed and forgotten.

LicensesDialogFragment.java

public class LicensesDialogFragment extends DialogFragment {

    public static LicensesDialogFragment newInstance() {
        return new LicensesDialogFragment();
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        WebView view = (WebView) LayoutInflater.from(getActivity()).inflate(R.layout.dialog_licenses, null);
        view.loadUrl("file:///android_asset/open_source_licenses.html");
        return new AlertDialog.Builder(getActivity(), R.style.Theme_AppCompat_Light_Dialog_Alert)
                .setTitle(getString(R.string.action_licenses))
                .setView(view)
                .setPositiveButton(android.R.string.ok, null)
                .create();
    }

}

Instead of building the AlertDialog in the Activity, a DialogFragment’s onCreateDialog method is used. Otherwise, the actual AlertDialog construction code is identical.

MainActivity.java -> displayLicensesDialogFragment()

private void displayLicensesDialogFragment() {
    LicensesDialogFragment dialog = LicensesDialogFragment.newInstance();
    dialog.show(getSupportFragmentManager(), "LicensesDialog");
}

Back in the Activity, this helper method takes care of actually showing the newly created DialogFragment, with the final result looking like this:

Licenses DialogFragment

The DialogFragment is visually identical to the AlertDialog implementation, so which one you choose is a matter of personal preference.

Examples of License Dialogs

Below is a series of screenshots from popular apps that include a third-party open-source licenses dialog. I find particularly intriguing the wide variety in design, language choice and ease of access. This is clearly an area of Android development where no established design pattern has taken hold, as you can see.

I believe that every app that uses third-party libraries should have some version of these screens. Let’s give credit where credit is due!

Amazon licenseGoogle Chrome licenseDropbox licenseFacebook licenseGmail licenseGoogle Hangouts licenseGoogle Maps licenseFacebook Messenger licenseNetflix licenseSpotify licenseTwitter licenseUber licenseYouTube license

The post Open-Source Licenses and Android appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/open-source-licenses-and-android/feed/ 0
Frame Animations in Android https://bignerdranch.com/blog/frame-animations-in-android/ https://bignerdranch.com/blog/frame-animations-in-android/#respond Tue, 12 May 2015 10:00:00 +0000 https://nerdranchighq.wpengine.com/blog/frame-animations-in-android/ Animations add vivacity and personality to your apps. Let’s take a look at how to implement a subcategory of animations called "Frame Animations."

The post Frame Animations in Android appeared first on Big Nerd Ranch.

]]>

Animations add vivacity and personality to your apps. Let’s take a look at how to implement a subcategory of animations called “Frame Animations,” meaning that they’re drawn frame by frame.

In Google’s official Material Design spec, there’s an entire page dedicated to Delightful Details, which has wonderful examples of Frame Animations in action.

Examples of Frame Animations

Examples of Frame Animations

Nifty animations! Unfortunately, nothing on the page links to resources for actually creating those delightful details, so here I am to help! Specifically, we’re going to walk through making an empty heart animate into a filled-up heart, then vice versa. It’ll look something like this:

Heart Frame Animation

…beautiful, I know.

Sequence of Images

The idea behind a frame animation is simple: We’ll be cycling through a series of images very quickly, just like an old movie reel. The “frame” refers to a single image. Thus, the first step in creating a custom frame animation is to create a sequence of images.

We have two options here: we can use XML drawables (such as shape drawables) or actual image files. For the sake of simplicity, we’re going to use the following series of PNG images:

Heart EmptyHeart 25%Heart 50%Heart 75%Heart Full

In a production application, we would also make sure to have images sized appropriately for different screen densities. For now, shove those images into the res/drawable-mdpi folder and call it a day. I would also recommend naming them in a self-descriptive way, such as ic_heart_0.png, ic_heart_1.png and so on. This way, we know the order of the images without having to view them.

I chose to name my heart images by their respective filled-up percentage, because I’m a nerd.

XML Drawables

Now that we have our images to cycle through, the next step is to define an XML Drawable for our animation. Once again, we are faced with two possibilities: the Animation-list and the Animated-selector.

Animation-List

Animation-list is the default Frame Animation of choice, as it was introduced in API 1. It works everywhere, and it’s simple. It just cycles through a sequence of provided images in a given order with given durations.

Here’s an example of an Animation-list for my heart filling up, placed in res/drawable/animation_list_filling.xml:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="true">

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_0"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_25"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_50"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_75"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_100"/>

</animation-list>

Each item in the list is just pointing to one of the images in our sequence from earlier. All we have to do is place them in the correct order and then add an appropriate duration in milliseconds.

And here’s an example of an Animation-list for my heart emptying, placed in res/drawable/animation_list_emptying.xml:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="true">

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_100"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_75"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_50"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_25"/>

    <item
        android:duration="500"
        android:drawable="@drawable/ic_heart_0"/>

</animation-list>

You might notice the android:oneshot=”true” in both of these code snippets, which is simply an attribute of the animation-list for playing the animation once and then stopping. If this is set to “false,” the animation will play on repeat.

In production, the 500ms duration is a long time, but I want to exaggerate the animations for demonstration purposes. Also note that five frames isn’t very many images for a smooth transition. The number of frames to use and how long to display them is a problem to solve on an individual-implementation basis. For a frame of reference, 15 frames at 15ms is very smooth.

Animated-Selector

Animated-selector is a bit more complex, as it’s state-based. Depending on the state of a View (such as selected or activated), the selector will animate to the correct state using provided Transitions. The Animated-selector is implemented only for Lollipop (and above), so we’re going to define our XML in the -v21 package.

Here is an example of the Animated-selector, placed in res/drawable-v21/selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/on"
        android:state_activated="true">
        <bitmap
            android:src="@drawable/ic_heart_100"/>
    </item>

    <item
        android:id="@+id/off">
        <bitmap
            android:src="@drawable/ic_heart_0"/>
    </item>

    <transition
        android:fromId="@+id/on"
        android:toId="@+id/off"
        android:drawable="@drawable/animation_list_emptying">
    </transition>

    <transition
        android:fromId="@id/off"
        android:toId="@id/on"
        android:drawable="@drawable/animation_list_filling">
    </transition>

</animated-selector>

Take note of how it’s actually referencing our Animation-lists from earlier as Transitions.

This animated-selector works well, but we need to account for the non-Lollipop devices. We’re going to define a non-animated selector, placed in res/drawable/selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:state_activated="true">
        <bitmap android:src="@drawable/ic_heart_100"/>
    </item>

    <item
        android:state_activated="false">
        <bitmap android:src="@drawable/ic_heart_0"/>
    </item>

</selector>

Now our selector will work on any device. If tried on a pre-Lollipop device, the animated-selector will just just skip the Transitions and go directly to the end state, since we’re just using a normal selector. And of course, a Lollipop device will have our Transition that we defined in the animated-selector.

In the above snippet, the animated-selector cares about the android:state_activated attribute. Just like a normal selector, I have different items defined for the possible states. However, I also have transitions defined for how to animate between these different states. In this particular animation, I just pointed the transitions to the animation-list drawables that we defined earlier.

We now have four XML files: one for emptying the heart, one for filling the heart, and two selectors for transitioning between empty and full states.

Set Up the ImageViews

It’s time to set up some ImageViews for us to play with. Specifically, we’re going to have three ImageViews, one for each XML Drawable that we defined previously. Put the following code in a Layout of your choice and throw it in an Activity:

<ImageView
    android:id="@+id/imageview_animation_list_filling"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/animation_list_filling"
    />

<ImageView
    android:id="@+id/imageview_animation_list_emptying"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/animation_list_emptying"
    />

 <ImageView
    android:id="@+id/imageview_animated_selector"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/selector"
    />

This is just a few ImageViews with unique ids and backgrounds pointing to our XML Drawables from earlier.

Starting the Animations

The behavior for starting the animations differs between the two implementations, so we’ll start with the animation-list.

Animation-List

In our Activity, we grab a reference to the ImageView and then start the animation, like so:

ImageView mImageViewFilling = (ImageView) findViewById(R.id.imageview_animation_list_filling);
((AnimationDrawable) mImageViewFilling.getBackground()).start();

Here’s what that looks like :

Heart Filling

Now for its partner code (identical except for the id):

ImageView mImageViewEmptying = (ImageView) findViewById(R.id.imageview_animation_list_emptying);
((AnimationDrawable) mImageViewEmptying.getBackground()).start();

And here’s what that part looks like:

Heart Emptying

Those code snippets can be put in onCreate (automatically begins when the Activity begins) or in an OnClickListener (waits for user interaction). The choice is yours!

Animated-Selector

When using the Animated-selector, the animation will trigger whenever the state-based condition is met for the selector. In our simple sample, we’re going to add a click listener to our ImageView in the onCreate method of our Activity:

mImageViewSelector.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mImageViewSelector.setActivated(!mImageViewSelector.isActivated());
    }
});

When the user clicks on our heart, the heart will fill or empty, depending on the current state. Here’s a nice GIF of my heart looping back and forth forever (presumably with a user clicking at each full and empty state):

Heart Looping

Be kind to our hearts, users!

Delightful Details

Frame Animations have the power to surprise and delight users, plus it’s fun to add little personal touches to an app. Go forth and animate!

The post Frame Animations in Android appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/frame-animations-in-android/feed/ 0
Continuous Delivery for Android https://bignerdranch.com/blog/continuous-delivery-for-android/ https://bignerdranch.com/blog/continuous-delivery-for-android/#respond Thu, 26 Feb 2015 09:00:00 +0000 https://nerdranchighq.wpengine.com/blog/continuous-delivery-for-android/

Quite a few continuous integration tools exist, but as soon as you narrow it down to options that properly support Android, it becomes much easier to pick one. Travis and TeamCity are viable options if you care primarily about the codebase compiling and passing tests, but do not need options for storing artifacts, signing them and publishing them. At Big Nerd Ranch, we have adopted Jenkins as our Android continuous delivery environment because it has enough extensibility for plugins to fully implement the entire deployment pipeline properly.

The post Continuous Delivery for Android appeared first on Big Nerd Ranch.

]]>

Quite a few continuous integration tools exist, but as soon as you narrow it down to options that properly support Android, it becomes much easier to pick one. Travis and TeamCity are viable options if you care primarily about the codebase compiling and passing tests, but do not need options for storing artifacts, signing them and publishing them. At Big Nerd Ranch, we have adopted Jenkins as our Android continuous delivery environment because it has enough extensibility for plugins to fully implement the entire deployment pipeline properly.

Jenkins can be set up to run in many different configurations ranging from a single local server in a closet running the whole pipeline to a cloud-deployed master that spins up virtual machine slaves to run individual builds. We chose to have a Jenkins master node constantly running on a cloud instance, which has the ability to spin up single-use slave instances for individual builds. This gives us a consistent and completely fresh build environment each run. The slave is created from an Amazon Machine Instance (AMI) on EC2 that can be updated when new Android SDKs and build tools are released. Overall, the cost works out to pennies per build, on top of the base cost of the master instance, which with EC2 isn’t much. The slaves are provisioned as m3.mediums from our AMI, using a bit of userdata configuration to mount the Android SDK and make sure 32-bit compatibility is available.

Our Amazon EC2 Instances

Running, running, running…

The details and specifics of how to get EC2 up and running are outside the scope of this post—we’re going to skip ahead to the Jenkins-related bits. Once all the credentials and keys are set up for the Jenkins JClouds plugin, you now have a functioning build server. At this point, the build server can compile and run your test suite and provide a link to a debug APK stored on the master node.

Time to make things interesting.

Once we turn on the Github plugins, the server will be able to mark a pull request as passed or broken and also email the team if master fails to build. We use two Jenkins jobs for this purpose.

Job Overview

A few clouds aren’t so bad, right?

One job is configured to merge a pull request (PR) into master and make sure things compile on a PR-specific basis. This job catches issues that would normally be noticed only after the PR had already been merged, and also provides quick feedback on what broke.

Passing

Passing.

Building

Building…

Failing!

Failing!

The other job is responsible for building and running the full test suite any time master is updated, typically after a PR has been merged. This job double-checks that master is staying in a happy state, but also takes significantly longer than just compiling. It runs the full Lint suite and generates a report, failing the build if the error or warning count increases from previous builds.

Lint Results

Mmm…linty fresh.

Build History

I should have paid more attention to those clouds earlier.

So to sum up, one Jenkins job ends up sanity-checking our PRs, and the other checks our master branch.

Just setting up Jenkins to continuously build like we’ve done already yields a useful tool—code quality is kept high, and we can more easily decide when a build is in a shippable state. At this point, creating a release is as simple as checking out a Jenkins-passed commit, bumping the appropriate version codes and numbers, running a release build on a local machine, signing the APK with keys that are inappropriately stored on all the developers’ machines, renaming the file appropriately, assembling release notes, tagging the commit, and then finally uploading the APK to the Google Play Store console.

Simple, right? It’s unfortunate that this amount of work is considered to be an accepted process, but since a Jenkins server has already been configured to build the codebase, we’re just going to automate the whole process of releasing a new build.

Automating Releasing a New Build

New Job

Step 1: New job.

The first step is to create a new Jenkins job. This job is distinct from the others in that it will build only when manually triggered (as opposed to being continually integrated by PRs), since this will be our actual release. Uploading APKs to the Play Store requires increasing a version number, but we don’t really want to have to change it each time. Since we have a dedicated job for this release build, we can just use the build number for the job as the version number and (part of) the version name for our application without having to do version-bump commits before each release.

Release Job Overview

Now with the Release job!

After bumping the version code and building, signing has to be dealt with. The naive approach is to use Gradle’s configuration to set up signing, but it is impossible to do this in a secure manner. Gradle can load the key and passphrase either straight from disk, or it can pull the data in from an environment variable.

Neither of these options is particularly secure. From disk, the key and passphrase would have to be in the slave image, requiring a separate image for every app and allowing anything during the build to compromise the key. Having the passphrase pulled from the environment is only slightly better. However, anyone with the ability to commit and execute a build could compromise the key by accessing their environment during the build. Using a dedicated Jenkins plugin for signing allows us to solve these issues.

Unfortunately, there is not a plugin for Android signing in the official plugin repository. However, we have written a very basic one and published it for you to compile and use. It will soon be available in the Jenkins update manager, but can also be downloaded and compiled manually. With this plugin, all signing happens only on the master node. In addition, the key and passphrase are stored in the Jenkins credential store, which limits access to be write-only from the web interface. This limits exposure to only the sysadmin of the Jenkins master. Signing happens to the artifact post-build; the key is not exposed during the build. Our plugin also has the benefit of creating both an unsigned artifact and a signed and aligned artifact.

Signing an APK

It’s not a creative Keystore name.

The final step of our release job for continuous delivery is to actually upload the generated APK to the Google Play Store. Fortunately, there is a third-party plugin available. Once the plugin is installed, it’s just a matter of granting a Google API Console credential the correct permissions from the Play Store Developer Console. The documentation for the Google Play Android Publisher Jenkins Plugin (what a mouthful!) has good instructions on how to do this.

Uploading an APK

Using different release tracks is useful!

We upload to the alpha and beta tracks for testing, then promote a build later.

At this point, we have built, signed, and uploaded our APK, but there’s still some post-upload actions that are possible. One possible action can be pushing a tag to Github with the version code, which makes creating a release marker in GitHub one quick click away via the GitHub website. A benefit of having the tagging automated is that bug triage is much easier when you get crash reports from older versions, since those versions are still readily accessible and cataloged.

Tagging Builds

A simple system for tagging all of our builds with creative names.

Long-term Payoffs

While this may seem daunting at first, once all of the work for setting up a Jenkins environment has been done for one project, it’s quick and easy to clone an existing job and just change the project-specific configurations. With a little short-term investment, the payoff in the long run is well worth it.

Thanks to Kurt Nelson for his contributions to this post.

The post Continuous Delivery for Android appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/continuous-delivery-for-android/feed/ 0
An Investigation into Flow and Mortar https://bignerdranch.com/blog/an-investigation-into-flow-and-mortar/ https://bignerdranch.com/blog/an-investigation-into-flow-and-mortar/#respond Thu, 19 Feb 2015 12:10:22 +0000 https://nerdranchighq.wpengine.com/blog/an-investigation-into-flow-and-mortar/ In our [Android bootcamp]({{ site.baseurl }}/training/courses/android/), we teach that using Fragments is the right way to go (especially for beginners), and we also use Fragments extensively in all of our [consulting projects](/work). I decided to investigate [Flow](https://github.com/square/flow) and [Mortar](https://github.com/square/mortar), two libraries that were introduced with the goal of ridding the Android world of Fragments forever. Here's what I found.

The post An Investigation into Flow and Mortar appeared first on Big Nerd Ranch.

]]>

Fragments have started to garner a negative reputation in the Android community, despite being officially supported by the Android team at Google, and there are a host of reasons why:

But perhaps most importantly, Android developers simply don’t seem to enjoy using Fragments, viewing them more as a hindrance than as a help.

Here on the Ranch, we teach in our Android bootcamps that using Fragments is the right way to go (especially for beginners), and we also use Fragments extensively on all of our consulting projects.

However, we encourage a mindset of constant exploration and continual learning, so I began investigating the most popular alternatives to Fragments.

Enter Flow and Mortar

About a year ago, Square introduced two new libraries called Flow and Mortar, with the noble goal of ridding the Android world of Fragments forever. Square has a stellar reputation in the open-source community, having built such amazing libraries as:

Suffice it to say, I trust them. I figure that any resource from Square is probably useful (or, at the very least, interesting), so it’s worth giving it a look.

I should note before diving in that Square uses these libraries only on a few internal projects, and they’re still in pre-release stages as of this writing. That said, both libraries have seen active development in recent months, which bodes well for their respective futures. While the libraries might be shifting sands that could change, break or die at any moment, the core architectural principles underlying them should remain constant.

Architecture

First, let’s go over architecture in Android applications. In the days before Android Honeycomb, before Fragments even existed, the standard pattern for creating Android apps was to create a bunch of Activities. Typically, most developers loosely followed a Model-View-Controller paradigm, which made a lot of sense. The model was the underlying data, typically some database or maybe a web request stored as JSON, or any various enumerations of Java objects. The View would happily be the XML layouts that the developer would craft for each Activity, and the Controller was the Activity associated with each screen of the application.

This is a simplistic overview, but you can see how Android fits into MVC by default.

Pre-Honeycomb Model View Controller

With the advent of Fragments in Honeycomb, the Android team made it easier to deal with different form factors. Now, the standard architecture became a few Activities and a bunch of composed Fragments, so that all of our apps would be cross-platform between phones, tablets, watches or spaceships.

Post-Honeycomb Model View Controller

At the time, this seemed like a boon. Fragments were all the rage, and decomposing an Activity into multiple fragments was great. Plus, the architecture still adheres to MVC, though Activities were often reduced to merely being Fragment holders and the interface between Fragments and the OS.

But what if Activities weren’t properly given a chance? Maybe, if used in conjunction with custom Views, Activities don’t actually need the support of Fragments to create cross-platform modular apps. The core idea behind using Flow and Mortar is to explore this question. Flow and Mortar work by replacing our Fragments with custom Views paired with dedicated and injected controller objects, so we can work solely with Views instead of Fragments.

Fragment-less Architecture

We’ll be constructing the middle portion of this diagram over the course of our discussion, figuring out where to put different pieces of the puzzle in a world without Fragments. We’ll watch as the architecture evolves from standard MVC into something altogether different, which (spoiler alert) will heavily involve Flow and Mortar.

So, what, exactly are Flow and Mortar, and how can they help?

Flow

Flow divides an application into a logical collection of “Screens.” Screens are not any sort of special library object, but rather a plain old Java object (POJO) that we create to represent sections of our application. Each Screen is a self-contained segment of the app, with its own function and purpose. A Screen’s usage isn’t so different from the typical Activity’s usage. Each Screen corresponds to a particular location in the app, sort of like a URL to a webpage or a really specific Implicit Intent in Android. Thus, the Screen class serves as a self-contained readable definition of a section of the application.

Each Activity in our application will own a “Flow” object. The Flow object holds the history of Screens in a backstack, similar to the Activity backstack or the FragmentManager’s backstack of Fragments, allowing us to navigate between Screens by simply instantiating where we want to go. Instead of an application having a bunch of Activities, there exists a small number (ideally one) Activity that hosts multiple Screens. It looks something like this:

Screens

If we want to go to a new Screen, we simply instantiate it and tell our Flow object to take us there. In addition, Flow comes with goBack() and goUp() methods, which behave as expected. While the introduction of goto statements in Java might scare some folk, it’s not so terribly evil.

Flow Example

In essence, Flow tells us where to go in our app. The advantage of using Flow is that it gives us a simple way to navigate around various custom Views that we’ve defined (i.e., Screens), freeing us to not worry about Activities or Fragments—we deal solely with Views. It creates a simpler, cleaner, View-centric world.

Mortar

Mortar is a library focused around Dagger and its associated dependency injection. Mortar divides an application into composable modules using a few distinct parts: Blueprints, Presenters and a boatload of custom Views.

Each section of a Mortar app (that is, each Screen, since we’re also using Flow) is defined by a Blueprint, which is given its own personal Dagger module. It ends up looking a bit like this:

Blueprints

Flow and Mortar play well together. All we have to do is adjust our Screen class to also implement the Blueprint interface (provided by Mortar), and it gives us the Dagger scoping for free.

Presenters

The Presenter is a singleton object that functions as a view-controller with a simple lifecycle and persistence bundle. Each View has an associated Presenter, which lives inside the associated Screen (with a Blueprint). Since the Presenter is scoped to just the Screen that it lives in, the Presenter (our heavy-duty controller object) will be garbage collected if we go to a new Screen using Flow. The Dagger scoping of Mortar combined with automatic garbage collection allow our app to be more memory efficient, since any of our controller objects that aren’t currently being used are GC-ed away. In Activity-land, there are fewer guarantees of garbage collection when switching between Fragments and Activities.

Custom Views are used liberally so that we can simply inject all of the important model data through Dagger, and then use the associated Presenter to control the View itself. Presenters survive configuration changes, but have enough Activity lifecycle knowledge to be restored after process death. The Presenter actually hooks into the Activity’s onSavedInstanceState() bundle, using the same mechanism for saving and loading data on configuration change as an Activity would.
The Presenter life cycle is a simple one with only four callbacks:

  • onEnterScope(MortarScope scope)
  • onLoad(Bundle savedInstanceState)
  • onSave(Bundle outState)
  • onExitScope()

Not nearly as confusing a lifecycle as Fragments, if I do say so myself!

There are a lot of moving parts and new terms and classes and all sorts of room for confusion. So in sum, we have the following pieces of the puzzle:

  • Screen: A particular location in the application’s navigation hierarchy
  • Blueprint: A section of an application with its own Dagger module
  • Presenter: A View-controller object
  • Custom Views: Views defined by Java and usually some XML

Here’s what our final Mortar and Flow architecture looks like:

Mortar and Flow Architecture

Instead of sticking with Model View Controller, the architecture has morphed into more of a Model View Presenter style. The big difference concerns the handling of runtime configuration changes like rotation. In MVC, our Controller (Activities and Fragments) will be destroyed alongside our Views, whereas in MVP, only our View will be destroyed and recreated. Nifty.

Model View Presenter

Positives

With all of this work and redesign, there needs to be some payoff, so let’s talk about the good things.

  • Using Mortar and Flow forces us to create a modular architecture with a Model View Presenter design, which is useful for maintaining a clean codebase.
  • Testing becomes easier through the dependency injection of our custom views and Presenters.
  • Animation can be dealt with on a View level, as opposed to worrying about Fragment and Activities as much.
  • Mortar scoping means the application will be more memory efficient, with garbage collection occurring on the View and Presenter level automatically.

And, of course, we no longer have to worry about Fragments and their various quirks.

Room for Improvement

Flow and Mortar do have some issues:

There is a steep learning curve. The patterns are complex and require a lot of exploration and experimentation before you can really understand them, and these libraries are certainly not for beginners. Even for an expert, there is a steep design pattern investment.

If you’re going to use Mortar and Flow, you really have to go all the way with it. It would be difficult to interplay “standard” Android with the Fragment-less Android style. If you want to convert an existing project to Mortar and Flow, the process, while certainly possible, will be long and arduous.

There’s a mountain of boilerplate and configuration to deal with. This is my biggest complaint. With all of these new classes and interfaces, I often felt like I was drowning in uninteresting code that was required solely to hook everything together, which just isn’t as much fun.

What’s next

Both Mortar and Flow are in the pre-release stages of their development, with no official release in sight. This means dealing with issues and changes and updates, with the libraries shifting from beneath us, but this also means there is plenty of time for improvement.

Working with Mortar and Flow was a fun experiment. I enjoyed trying out some new libraries and seeking alternatives to the standard Fragment-oriented architecture, but I don’t think Mortar and Flow are the solutions the Android world are seeking. That could change in a few months or years. I hope that these projects will garner more attention and love and continue to improve, and I’ll definitely be keeping an eye on them.

The post An Investigation into Flow and Mortar appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/an-investigation-into-flow-and-mortar/feed/ 0
The Future of Technology: Atlanta Science Festival https://bignerdranch.com/blog/the-future-of-technology-atlanta-science-festival/ https://bignerdranch.com/blog/the-future-of-technology-atlanta-science-festival/#respond Tue, 25 Mar 2014 22:05:52 +0000 https://nerdranchighq.wpengine.com/blog/the-future-of-technology-atlanta-science-festival/

The British author Arthur C. Clarke is renowned for his three laws of prediction involving technology, and the third and most famous law can be stated thusly:

The post The Future of Technology: Atlanta Science Festival appeared first on Big Nerd Ranch.

]]>

The British author Arthur C. Clarke is renowned for his three laws of prediction involving technology, and the third and most famous law can be stated thusly:

“Any sufficiently advanced technology is indistinguishable from magic.”

We live in an amazing time. Every day, we utilize technology that would seem like magic in any other era of history. For example, we use mechanical vehicles for transportation instead of riding horses or walking, and rely on electronic communications devices instead of writing letters or sending mail. It’s easy to forget that some of the technologies we use every day, especially electronic ones like cell phones, simply didn’t exist only a few decades ago. My job of Android developer didn’t exist even 10 years ago!

The Rapid pace of technological development

It’s staggering to consider the rapid pace of recent technological development, especially computer science and medical advances. It wasn’t until 2003 that the first draft of the Human Genome project was completed, essentially spelling out the entire DNA structure of the human body. Recent advances in prosthetic and bionic limbs allow amputees to resume their previous activities and lives. Tesla has created a car that runs entirely on electricity, potentially lessening our reliance on fossil fuels. Wearables are becoming the norm, thanks to Google Glass and the Pebble smartwatch, while at the same time the Oculus Rift is innovating virtual reality. Technology has been swiftly marching onward and shows no sign of stopping anytime soon.

LOOKING TO THE FUTURE

However, the future is even more exciting to me. There are technological advances that we still consider science fiction: the flying cars of the Jetsons aren’t quite a reality, and the androids of Blade Runner are thankfully not a dilemma (yet). But in the future, flying cars and human-like robots may become a fact of life. If you’re skeptical, simply remember that advanced technology may seem magical to the unfamiliar, but that nearly anything is possible with enough time and dedication.

Atlanta Science Festival logo

Atlanta Science festival

If we want the world to improve and for science to achieve great advances, then we must help foster growth and inspire the future that we want to live in. That’s why I’m taking part in the Atlanta Science Festival, a week-long celebration of local science and technology. I’ll be visiting 10 elementary school classes to talk about the future, advanced technology, and daring to think that anything could be possible with science. I want to foster the spirit of scientific adventure within these students. I want them to imagine the future and the crazy technologies that could be. I want them to dream about creating and building and making. Those kids have a chance at engineering the future, of making our science fiction a reality, and I want to do everything in my power to help them dream big.

Most of all, I want to impress upon them that anything is possible. After all, any sufficiently advanced technology is indistinguishable from magic, and the magic of the past is simply the science of today.

The post The Future of Technology: Atlanta Science Festival appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/the-future-of-technology-atlanta-science-festival/feed/ 0