Developing for Tablets - Android Is More than Phones - Android Application Development For Dummies, 3rd Edition (2015)

Android Application Development For Dummies, 3rd Edition (2015)

Part IV. Android Is More than Phones

image

webextra Supplement your Android apps with voice input using the articles online at www.dummies.com/extras/androidappdevelopment

In this part . . .

Part IV introduces you to the world beyond Android phones. Android tablets, watches, and TVs are a different sort of beast than Android phones, and this part walks you through all the changes you need to make to your app so it can run on these other Android devices.

Should you want to go beyond the realm of standard Android, you will also find everything you need to add support for Android‐based (but non‐Google) devices, such as the Amazon Fire.

Chapter 16. Developing for Tablets

In This Chapter

arrow Zeroing in on why a tablet is a different digital beast

arrow Modifying your existing app to run on tablets

arrow Downloading a tablet emulator

arrow Using responsive layouts

arrow Building product flavors

arrow Creating a tablet‐only activity

You need to master some tricks of the trade to make your apps work on tablets and on phones. In this chapter, you can get an overview of the differences betweeen phones and tablets, and then find out how to design the Tasks application to work on both types of devices.

Considering the Differences between Phones and Tablets

Android tablets and Android phones have some obvious differences, and size immediately comes to mind, but that is only one of the differences:

· Tablets are designed to be held in two hands, whereas phones are designed for only one.

· Android tablet screens tend not to extend past the 7‐to‐10‐inch range, and the largest phones max out around 6 inches.

The line between tablet and phone can blur at the 5‐inch mark. Some “tweener” devices are marketed as phones, and others with nearly the same specs are marketed as tablets.

· Tablet orientation varies depending on usage, whereas almost all Android phones have settled on portrait orientation for their screens.

Many Android tablets are designed for wide‐screen media viewing, so they favor landscape orientation. Others, such as the Nexus 7 and Kindle Fire, are designed primarily for use in portrait mode. That’s not to say that you can’t run an app in portrait mode on a landscape tablet (or vice versa), but be aware that many users may run your app in an orientation other than the one in which you completed most of your testing.

Tablets and phones also have some differences in hardware design and operation that affect app design. This list describes them from the tablet ­perspective:

· Tablets often lack always‐on 3G or 4G data connections.

· Tablets tend to be larger, use larger batteries, and benefit from much longer battery life than their phone counterparts.

· Tablets may have cheaper cameras — or no cameras — because tablet cameras typically get less use than phone cameras.

· Tablets often lack such common phone capabilities as GPS location service.

In addition, don’t be surprised if you have to design your app (or tweak an existing one) to accommodate new tablet features.

Tweaking the Tasks App for Tablets

To help accommodate the differences, you use a few techniques to upgrade the Tasks app so that it can work on both tablets and phones.

Use these strategies every time you design an Android application because it’s likely that most of your apps target users of both types of devices.

Anticipating screen size with a responsive layout

Go with the flow when you’re designing your layout to fit multiple screen sizes. A flowing, or responsive, layout skips a lot of hassle and frustration for both the designer and the user.

If you’re familiar with iOS development from a few years back, you know that back then you only had a few screen sizes to worry about: a couple of iPhone sizes, and a couple of iPad sizes. Each size required both low‐ and high‐resolution images, but that was easy enough to handle: Design for iPhone first, and then for iPad, and then plug in the low‐ and high‐resolution images in the respective versions and you were done.

Android has never been quite as simple to design for. Layouts in Android need to “flow” — that is, resize and rearrange themselves — so that they can accommodate minor (and sometimes major) differences in the width and height of users’ devices. Android developers have dozens or hundreds of ­different sizes of devices to worry about.

It’s similar to designing for websites — when you’re building a website, you can’t assume that all users will view it in browser windows that are exactly the same size (800 x 600 pixels). Users may view the site from bigger (or sometimes smaller) browser windows; your design must be flexible enough to give a good experience to the whole range of sizes. Designing for Android makes the same requirement. In fact, iOS is now moving in this same direction, and encouraging their developers to use flowing layouts as well.

So how do you perform this bit of magic? For openers, don’t try to use fixed dimensions (such as 10px or 120dp) in your layouts. Instead, favor relative dimensions, such as "wrap_content" and "match_parent" as much as possible. The idea is to achieve a responsivelayout that can resize to fit the device.

The following code shows a layout that makes too many assumptions about the device it’s on:

<?xml version="1.0" encoding="utf-8”?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300px"
android:layout_height="match_parent"
android:lines="1"
android:text="Occurrences of the word 'Internet' in the Gettysburg
Address: 0 (unverified)"/>

The code has multiple problems:

· It uses a fixed‐sized TextView rather than flexible dimensions, like wrap_content and match_parent.

· It uses pixels (px) to measure size, which doesn’t scale automatically across different devices, as dp (device‐independent pixels) would.

· It hard‐codes the number of lines in TextView to 1 and doesn’t tell Android what to do with any overflow.

· It doesn’t use ScrollView, so if your layout is taller than the device screen, there’s no way to see the offscreen views.

· Generally speaking, many of your layouts should be wrapped in a single ScrollView to handle unanticipated overflow off the bottom of the screen. Exceptions include layouts that already handle scrolling, such as ListView, which shouldn’t be wrapped in aScrollView. The example above uses only a single TextView, so it’s unlikely to need a ScrollView, but more complicated layouts should consider them.

Figure 16-1 shows the TextView from the above code. It abruptly cuts off text midsentence because of the fixed size. If the developer had used a responsive layout, the text wouldn’t have been cut off.

image

Figure 161: A non‐responsive layout that abruptly truncates after “Occurr­ences of . . .”

Fixing this particular example is easy by changing the width of the TextView and replacing android:lines="1" with android:maxLines="3":

<?xml version="1.0" encoding="utf-8”?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="3"
android:text="Occurrences of the word 'Internet' in the Gettysburg Address:
0 (unverified)"/>

When you’re designing your layouts, always consider the maximum size of each item in your layout. The app content can take up more space than you expect, and it’s important to anticipate these situations and plan for them rather than end up with an app that looks ugly.

Adding more fragments

Android uses fragments to help you deal with the additional real estate on tablets. The basic idea is that a typical phone activity centers on one, two, or three distinct groups of reusable onscreen items. Put each of these groups into its own fragment and it becomes easy to reuse across multiple activities.

You’re going to do exactly this — you’ll add the TaskEditFragment and the TaskListFragment from your two phone activities into a single new activity that tablet users will enjoy.

Figure 16-2 shows how Tasks fragments lay out on a phone and on a tablet.

image

Figure 162: Fragments can handle a single activity on a phone (left) or two activities on a tablet (right).

Without fragments, you’d have to reinvent the wheel every time you wanted to make an activity that shows a list of tasks. Using fragments, just write the code once and you can reuse it as many times as you want.

Creating different layouts for different devices

The fragment is a handy feature for the designer, but how do you slice and dice fragments to show the right experience for the right device? The tablet’s relatively vast screen real estate (compared to a phone) can show one or two more fragments on a single activity.

You can use one layout containing a single activity for your phone and another layout containing multiple fragments for your tablet. For example, here’s the TaskListActivity layout for the phone size in the Tasks app:

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

And Listing 16-1 shows how you might modify the code using two ­fragments to create a two‐column layout on a tablet:

Listing 161: Two‐Column Table Layout Example

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

<fragment
android:id="@+id/list_fragment"
android:name="com.dummies.tasks.fragment.TaskListFragment"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
/>

<fragment
android:id="@+id/edit_fragment"
android:name="com.dummies.tasks.fragment.TaskEditFragment"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
/>

</LinearLayout>

This is very similar to what you’ll do later in the chapter to put two ­fragments next to each other.

Three strategies for adding tablet support

There are three main strategies that you can use to make your phone app work on tablets. Each is perfectly reasonable and has its own set of advantages and disadvantages.

The first strategy is to make two different apps: one for phones and one for tablets. This sounds wasteful, but in fact it’s quite easy to use build variants to create two different apps from nearly the same codebase.

The advantage of this strategy is that you can keep all your shared code in one place but keep any phone‐specific or tablet‐specific code in separate directories. That way, the tablet code won’t need to be installed on phones where it won’t be used, and vice versa. The disadvantage of this strategy is that you need to manage two APKs, one for phones and one for tablets, every time you make a new release of your app.

The second strategy is to use a single app for both types of devices, but use different activities and choose between them when you launch the app. For example, the phone app might have a TaskListActivity which shows a list of tasks, and the tablet might have a TaskListAndEditActivity which shows a list of tasks, but also shows the edit fragment next to the list (as described in the previous section). You would then add a special LaunchActivity which would be your app’s main launcher activity in the AndroidManifest. At startup, the LaunchActivity would quickly detect if you were on a tablet or on a phone, and start the appropriate activity before finishing itself. It would happen so fast that users would never even see the LaunchActivity itself.

The advantage of this strategy is that your app will still appear as a single app in the Google Play Store. The disadvantage is that all the phone code will also be installed on all your tablets, and vice versa.

The third strategy is to use the exact same activities on both phones and tablets, but to change the layouts for each type of device. This can work great for simple apps. The advantage of this strategy is that you don’t need to worry about writing additional activities to handle different device types. The disadvantage is that your phone and tablet code can start getting tangled in your activities, potentially making the activities complicated.

In this chapter, you will use the first strategy and build two separate apps for phones and tablets. However, you may want to experiment with the second strategy (or even the third) after you finish this chapter.

Configuring a Tablet Emulator

First things first — you need a tablet on which to test your application. If you already have a tablet, you’re well on your way; if you don’t, then you need an emulator to emulate an Android device on your computer. Google calls these Android Virtual Devices (AVDs). Follow these steps to get the Google Nexus 7 AVD:

1. Choose Tools⇒Android⇒AVD Manager in Android Studio.

2. Click Create Virtual Device.

3. Choose Tablet, then Nexus 7, and click Next.

4. Choose Lollipop 21 x86 and click Next.

5. Click Finish.

6. Choose the AVD you just created from the list of AVDs, and click the Start button to launch it.

See Chapter 3 for a reminder of how to configure an emulator.

Creating a New Product Flavor

As mentioned in the “Three strategies for adding tablet support” sidebar, you are going to create two product “flavors” for your app — one for phones and one for tablets. Each flavor will have its own APK file. For the most part, the flavors will share the same code, but they can have some slight differences in code and configuration.

Add the following to the android section of your Tasks build.gradle:

productFlavors {
phone {}
tablet {}
}

Both flavors will use all of the default settings, so there is no need to add any configuration to either of them. Later, you will set up each flavor to use a slightly different set of files, but for now they’re identical. When you do this, the shared code and resources will go intosrc/main (shared by all flavors), and the code for phones and tablets will go into src/phone and src/tablet, respectively, as specified by the name of the flavors you defined in the previous code.

Now choose Build⇒Rebuild Project and build your project again. If you then choose View⇒Tool Windows⇒Messages, you should see your project being built for both phones and tablets as in Figure 16-3.

image

Figure 163: Build Messages showing Tasks being built for phones and tablets.

There’s more to do, so go through the next sections before you try to install and run your two flavors.

Creating an AndroidManifest for Phones

There are going to be slight differences between your phone and tablet apps. Both require their own AndroidManifest.xml file. For the most part, the configuration will remain in your existing AndroidManifest.xml, but you’ll need to make some specific changes for each flavor that goes into a phone and tablet AndroidManifest.xml. The information in the phone and tablet AndroidManifest.xml will override the information in the main AndroidManifest.xml.

Moving the TaskListAdapter

First, go to your AndroidManifest.xml file and remove the following code:

<activity
android:name="com.dummies.tasks.activity.TaskListActivity"
... >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<intent-filter>
</activity>

The TaskListActivity will be used only on your phone. You create a ­different activity for tablets. So for that reason, you just removed it from the shared AndroidManifest.xml.

The next step is to create the phone’s AndroidManifest.xml. But before creating it, first create the phone directory by going to your src directory and creating a new directory named phone. The directory phone must match the name of the flavor you created in yourbuild.gradle in the previous section.

Next, create a new AndroidManifest.xml file in the src/phone directory with the following contents:

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

<application>
<activity android:name="com.dummies.tasks.activity.TaskListActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

</manifest>

You just moved the TaskListActivity from the shared AndroidManifest.xml to the phone‐specific AndroidManifest.xml.

Now build and run your app to make sure you haven’t broken anything. If everything worked properly, the app should run identically to how it did before you split the AndroidManifest.xml.

Informing the Google Play Store

There is one more thing you need to do: Tell the Google Play Store that the phone version of your app should only be visible and installable on phones, not tablets. If you do not do this, the Google Play Store will show the phone app to people on tablets!

Open the src/phone/AndroidManifest.xml file and add the code in bold:

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

<compatible-screens>
<!-- all small size screens -->
<screen android:screenSize="small" android:screenDensity="ldpi" />→6
<screen android:screenSize="small" android:screenDensity="mdpi" />
<screen android:screenSize="small" android:screenDensity="hdpi" />
<screen android:screenSize="small" android:screenDensity="xhdpi"/>
<screen android:screenSize="small" android:screenDensity="480" /> →10
<!-- all normal size screens --/>
<screen android:screenSize="normal" android:screenDensity="ldpi" />→12
<screen android:screenSize="normal" android:screenDensity="mdpi" />
<screen android:screenSize="normal" android:screenDensity="hdpi" />
<screen android:screenSize="normal" android:screenDensity="xhdpi"/>
<screen android:screenSize="normal" android:screenDensity="480" />→16
</compatible-screens>

<application>
<activity android:name="com.dummies.tasks.activity.TaskListActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

</manifest>

The compatible‐screens element is not used by Android or your app directly. It is used only by the Google Play Store to determine which devices this app is compatible with.

10 Declares that your app is compatible with all five resolutions of "small" screens (ldpi, mdpi, hdpi, xhdpi, and xxhdpi). You’ll notice that instead of saying xxhdpi on line 10, we say 480. This is because, at the time of this writing, the compatible‐screenselement does not yet support xxhdpi directly, so we need to use the numerical value for xxhdpi, which is 480.

12—16 Does the same, but for "normal" size devices.

These two sections declare that your app will run fine on small and normal devices, but will not run on large or extra‐large devices (generally tablets).

The compatible‐screen element is a little tricky. If you want to make changes to this section, make sure you read http://d.android.com/guide/practices/screensdistribution.html.

Creating an AndroidManifest for Tablets

Now that you have a fully functioning phone app again, it’s time to start working on the tablet app.

Create a directory named tablet inside the src directory. Inside the tablet directory, create an AndroidManifest.xml for tablets that looks like the following:

When creating new product flavors, the name of the directory under src must match the name of the flavor in the build.gradle. You can name them whatever you want, as long as they agree.

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

<application>

<!-- Declare our main activity, which will be different than the
main activity for phones.
-->
<activity android:name=
"com.dummies.tasks.tablet.activity.TaskListAndEditorActivity" > →10
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

</application>

</manifest>

Just like the phone manifest in the previous section, this manifest declares a single activity that will be the main launcher activity for the app — except the activity for tablets is different from the one for phones.

You should receive an error on line 10. That’s okay; you create the TaskListAndEditorActivity in the next section.

There is one more thing to do. You must tell the Google Play Store that this app is available only for tablets and not for phones. Add the following to your manifest:

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

<compatible-screens>
<!-- all large size screens -->
<screen android:screenSize="large" android:screenDensity="ldpi" />
<screen android:screenSize="large" android:screenDensity="mdpi" />
<screen android:screenSize="large" android:screenDensity="hdpi" />
<screen android:screenSize="large" android:screenDensity="xhdpi"/>
<screen android:screenSize="large" android:screenDensity="480" />
<!-- all xlarge size screens -->
<screen android:screenSize="xlarge" android:screenDensity="ldpi" />
<screen android:screenSize="xlarge" android:screenDensity="mdpi" />
<screen android:screenSize="xlarge" android:screenDensity="hdpi" />
<screen android:screenSize="xlarge" android:screenDensity="xhdpi"/>
<screen android:screenSize="xlarge" android:screenDensity="480" />
</compatible-screens>

<application>

<!-- Declare our main activity, which will be different than the
main activity for phones.
-->
<activity android:name=
"com.dummies.tasks.tablet.activity.TaskListAndEditorActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

</application>

</manifest>

Notice the difference between the phone manifest and the tablet manifest. In the phone manifest, you said the flavor supported small and normal screens, but in the tablet manifest you say it supports large and xlarge screens.

Making the TaskListAndEditorActivity for Tablets

You’ve created and built the phone app. You’ve declared the manifest file for the tablet app. The next step is to create the TaskListAndEditorActivity which only tablets will use.

Creating the tablet activity class

The first step is to create the directories you need. Create the following directories inside the tablet directory:

· java

· java/com

· java/com/dummies

· java/com/dummies/tasks

· java/com/dummies/tasks/tablet

· java/com/dummies/tasks/tablet/activity

Then create a new file inside the tablet/java/com/dummies/tasks/ tablet/activity directory named TaskListAndEditorActivity.java with the following code:

public class TaskListAndEditorActivity extends Activity
implements OnEditTask, OnEditFinished →2
{

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_task_list_and_editor);
setActionBar((Toolbar) findViewById(R.id.toolbar));
}

/**
* Called when the user asks to edit or insert a task.
*/
@Override
public void editTask(long id) { →16
}

/**
* Called when the user finishes editing a task.
*/
@Override
public void finishEditingTask() { →23
}

}

The onCreate method creates a new activity, sets its content to the activity_task_list_and_editor.xml layout (which you will create), and sets its action bar to the toolbar element.

In addition, you’ll see the following happen on these lines:

2 You declare that this activity will implement the OnEditTask and OnEditFinished interfaces.

16‐23 The methods from the interfaces on line 2 are defined on these lines. Currently they are empty, but you will recall from Chapters 9 and 10 that these methods are used to figure out what the fragment will do when the user asks to edit a task and finishes editing a task. You will complete these methods in a later section.

Adding the tablet layout

Next, add the layout file. Create a new directory inside the src/tablet directory called res. Inside res, create a directory named layout, and inside the layout directory create the layout file named activity_task_list_and_editor.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"→2
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:baselineAligned="false">

<Toolbar →8
style="?android:actionBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:title="@string/app_name"
android:id="@+id/toolbar"/>

<LinearLayout →15
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">

<fragment →21
android:id="@+id/list_fragment"
android:name="com.dummies.tasks.fragment.TaskListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>

<FrameLayout →28
android:id="@+id/edit_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"/>

</LinearLayout>

</LinearLayout>

This layout consists of three main parts:

· A toolbar

· The list fragment

· A framelayout which holds your edit fragment

If you look back to Listing 16-1 at the beginning of the chapter, you’ll see that the layout is pretty similar, but instead of having two fragments in the layout, it has one fragment and one placeholder. The reason the second fragment needs to be a placeholder is because the edit fragment cannot be instantiated without knowing the ID of the task that needs to be edited. Because the ID isn’t known at the time the layout is created, you must inflate the fragment manually so that you can specify the ID. Look back at Chapter 10 and you’ll see you needed to do the same thing there for the TaskEditFragment.

Discussion of the previous code in more detail:

2 A vertical LinearLayout that holds the two fragments for your tablet layout. Set baselineAligned to false as recommended by Android lint to get a tiny bump in performance. See Chapter 17 for more information about Android lint.

8 The toolbar for the activity. It won’t be styled automatically, so set its style to the theme’s actionBarStyle. Also set its title to the app’s name.

15 A second LinearLayout, this one arranged horizontally. This LinearLayout is used to hold the two side‐by‐side fragments.

21 The list view fragment, which occupies the leftmost third of the screen. It is using one‐third of the screen because its layout_weight is set to 1, whereas the layout_weight of the other fragment on line 28 is set to 2, and 1 out of 3 is one‐third. Remember, when using layout_weight, you must set your layout_width to 0.

28 The edit view fragment, which occupies the remaining two of three parts of the screen.

Building the Tablet App

The tablet app isn’t quite done yet, but it’s time to run it and see what happens. How do you choose whether to build the phone app or the tablet app? Android Studio gives you a simple way to choose.

Choose View⇒Tool Windows⇒Build Variants. You should see a tool window, listing the build types for each of your apps. Click the build variant for Tasks and change it to say tabletDebug (see Figure 16-4):

image

Figure 164: The Build Variants tool window with the tablet Debug flavor selected.

There are four build variants listed for the Tasks app. These correspond to the two buildTypes and the two productFlavors in your build.gradle as shown in Table 16-1.

Table 161 The Four Build Configurations for the Tasks App

buildTypes / productFlavors

Debug

Release

Phone

phoneDebug

phoneRelease

Tablet

tabletDebug

tabletRelease

Your build.gradle may not explicitly list a debug buildType, but it is always there by default.

You can add additional buildTypes or productFlavors if you want, but be careful! The number of build configurations can explode very quickly if you add a bunch of new productFlavors or buildTypes.

Now choose Build⇒Make Project and build the tablet app. Then choose Run⇒Run ‘Tasks’ to run your app, and choose the tablet emulator you created earlier in this chapter. You should see a list view but no editor view, as in Figure 16-5.

image

Figure 165: The Tasks app with only a list view running in the Nexus 7 emulator.

The emulator has several special keys that control it. To rotate the emulator, use Ctrl‐F11 or Ctrl‐F12. Note that, if you’re on a Mac, you may also need to hold down the Fn key depending on how your keyboard is set up.

It looks great! But the problem is that there is no way add or edit tasks. You need to fill out the editTask() and finishEditingTask() methods.

Adding the App Callbacks

Recall from Chapter 10 that, on phones, the editTask() method started a new TaskEditActivity as shown in Listing 16-2 (do not add this code to your tablet app!):

Listing 162: The editTask() Method for Phones (Not Tablets)

@Override
public void editTask(long id) {
// When we are asked to edit a reminder, start the
// TaskEditActivity with the id of the task to edit.
startActivity(new Intent(this, TaskEditActivity.class)
.putExtra(TaskEditActivity.EXTRA_TASKID, id));
}

Instead of starting a new activity on tablets, it makes more sense to use some of the empty real estate on the right‐hand side of the page as a task editor. So for tablets, you’ll use a different version of editTask(), which opens the editor fragment inside the current activity.

Add the following code to TaskListAndEditorActivity.java:

@Override
public void editTask(long id) {
TaskEditFragment fragment = TaskEditFragment.newInstance(id); →3

FragmentTransaction ft = getFragmentManager() →5
.beginTransaction();
ft.replace(R.id.edit_container, fragment,
TaskEditFragment.DEFAULT_FRAGMENT_TAG);

ft.addToBackStack(null); →10

ft.commit(); →12
}

This code should look familiar. It’s very similar to the code you used in Chapter 10 to instantiate the TaskEditFragment there. As a recap:

3 Creates the fragment for the given task id.

5 Adds the fragment to the activity. If there’s one already there (for example, the user clicks on another task), then replace it. Tag the fragment with a name (DEFAULT_FRAGMENT_TAG in this case) so that you can find it again later.

10 Adds this change to the backstack, so that when the user clicks the Back button you’ll pop this editor off the stack. If you don’t do this, the whole activity closes when the user clicks the Back button, which will be disruptive and unexpected.

12 Make it so!

Now the only thing left to do is implement finishEditingTask(). All this method needs to do is remove the fragment you just created, so add the code in bold:

@Override
public void finishEditingTask() {
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();

// Find the edit fragment using the tag,
// and remove it from the activity.
Fragment fragment = fm.findFragmentByTag(
TaskEditFragment.DEFAULT_FRAGMENT_TAG);
transaction.remove(fragment);

transaction.commit();
}

Run the app again and you should be able to add and edit tasks.

One More Thing . . .

Do you remember adding that super cool code in Chapter 10 to change the colors of your window based on the color of the image being displayed? Well, that was pretty cool back then, but it looks a bit goofy now. For phones, the colors take over the entire window, but here in the tablet they only cover the right half of the page.

Let’s disable the color change for tablets but keep it there for phones.

First, define a SHOULD_USE_PALETTE field in your build configuration. Open build.gradle and add the lines in bold:

productFlavors {
phone {
buildConfigField ‘boolean’, ‘SHOULD_USE_PALETTE’, ‘true’
}
tablet {
buildConfigField ‘boolean’, ‘SHOULD_USE_PALETTE’, ‘false’
}
}

This creates a new field named SHOULD_USE_PALETTE in the BuildConfig class. The field is set to true for the APK built for phones, and to false for the APK built for tablets.

The next step is to use the field in your code. Open TaskEditFragment.java and add the code in bold:

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor task) {

. . .


// Set the thumbnail image
Picasso.with(getActivity())
.load(TaskListAdapter.getImageUrlForTask(taskId))
.into(
imageView,
new Callback() {
@Override
public void onSuccess() {
Activity activity = getActivity();

if (activity == null)
return;

// Don’t do this for tablets, only phones,
// since it doesn’t really work with a split
// screen view.
if( !BuildConfig.SHOULD_USE_PALETTE )
return;

. . .

}

Now run your app again on the tablet; the Palette behavior should be disabled. Verify that you haven’t broken anything on phones by changing your build variant to phoneDebug and running the app again on your Nexus 5 phone ­emulator. The Palette behavior should still be present on your phone app.

Congratulations! You now have a fully implemented version of your Tasks app designed for tablets!