Google Earth for Tablets Should Have Desktop Features

Google Earth on the Nexus OneGoogle Earth on the mobile platform was first released for the iPhone in October 2008. It was very popular (and continues to be so today) thanks to being able to move and zoom with the touch screen, and the beauty of the imagery on high resolution smart phone screens. But, the new app would not let you see much in the way of map information – very little KML content was made available, and you couldn’t load KML files. Even so, most of us were just thrilled to see such a cool 3D app on a phone at all, so we weren’t too disappointed.

There weren’t many updates to the mobile application until Google Earth for iPhone 2.0 was released in November 2009. Before 2.0 was released Google had added some new layers you could see in Google Earth (like photos, roads, and Wikipedia placemarks). But, you couldn’t load KML files – only view the Google Earth terrain and imagery and the built-in layers. Google finally added an ability to add some KML content indirectly in the iPhone 2.0 version by allowing you to load maps you had saved in My Maps. But, only certain basic KML content was viewable. There hasn’t been a big update to the iPhone version since since 2009.

Early last year, with the introduction of the Nexus One, Google released Google Earth for Android. It had some differences from the iPhone version, including some support for GPS following. But, it also did not support KML content. A few updates to the Android came out in 2010, including version 1.1 which added the Ocean layers and undersea 3D terrain. But, you still can’t load KML content on the Android platform.

Even without more features, Google Earth is already one of the most popular apps on smart phones and tablets like the iPad (see ten must have apps for the iPad).

What about tablets?

Google Maps on the iPad

With the introduction of the new wave of tablets coming out this year (e.g. the Google/Motorola XOOM with Android 3.0/Honeycomb and Apple iPad 2), we are going to see new CPU horsepower (and 3D horsepower) made available. These computers will actually be more powerful than many desktops that run the full desktop version of Google Earth. There’s no reason I can see that tablets couldn’t run a more fully capable Google Earth application (besides the need for it to be ported to the iOS and Android operating systems). Since Google Earth already runs on Linux, Mac OS, and Windows – I’m sure Google could make a porting of the app happen!

We realize that Google is also developing the Google Maps application on the mobile platform to have more 3D capabilities. But, there’s a huge difference between adding 3D to the Maps application and the full desktop capabilities of Google Earth.

We would like to see Google Earth on tablets take full advantage of the built in features – better UI features for the touch screen; take full advantage of built-in GPS, compass, gyro, and accelerometers (imagine flying the flight simulator using those features!); better features for recording GPS tracks and showing your position during travels. Not only that, but features from the desktop version such as: measuring distances, adjusting mapping routes, historical imagery, time animations, and interfacing with Google Maps should be included. And, it’s even more critical to have the offline capabilities of Google Earth on mobile platforms like a tablet. Most importantly, you should be able to load any KML content on a tablet just like on a desktop – including network links (which enable live content such as weather and real-time position updating). I’m certain the tablet platforms can support most of the capabilities of the desktop client. Google just needs to port the app to those operating systems.

While we’re on our soapbox pleading for new features, there’s one new feature Mickey and I have been discussing that needs to come to Google Earth regardless of OS (but, especially if you have more KML capability on the tablets and/or mobile platform). Google should support the ability to put your “My Places” content (the content you want to be there when you load Google Earth) up into the cloud. Whether its stored in your Dropbox, or maybe Google Docs – you should be able to point your “My Places” to a file storage space on the net somewhere. That way when you move from one system to another, you can point Google Earth at your centrally located “My Places” content and have your favorite content (and other GE settings) always available.

So, consider this our vote for Google to port the full Google Earth capabilities to the mobile tablet platforms. I hope most of you other Google Earth lovers will agree that you’d like to see this happen for your upcoming tablet acquisition. Because, it seems like there’s going to be a lot of people with tablets in the not so distant future.

The Android 3.0 Fragments API

An important goal for Android 3.0 is to make it easier for developers to write applications that can scale across a variety of screen sizes, beyond the facilities already available in the platform:

  • Since the beginning, Android’s UI framework has been designed around the use of layout managers, allowing UIs to be described in a way that will adjust to the space available. A common example is a ListView whose height changes depending on the size of the screen, which varies a bit between QVGA, HVGA, and WVGA aspect ratios.
  • Android 1.6 introduced a new concept of screen densities, making it easy for apps to scale between different screen resolutions when the screen is about the same physical size. Developers immediately started using this facility when higher-resolution screens were introduced, first on Droid and then on other phones.
  • Android 1.6 also made screen sizes accessible to developers, classifying them into buckets: “small” for QVGA aspect ratios, “normal” for HVGA and WVGA aspect ratios, and “large” for larger screens. Developers can use the resource system to select between different layouts based on the screen size.

The combination of layout managers and resource selection based on screen size goes a long way towards helping developers build scalable UIs for the variety of Android devices we want to enable. As a result, many existing handset applications Just Work under Honeycomb on full-size tablets, without special compatibility modes, with no changes required. However, as we move up into tablet-oriented UIs with 10-inch screens, many applications also benefit from a more radical UI adjustment than resources can easily provide by themselves.

Introducing the Fragment

Android 3.0 further helps applications adjust their interfaces with a new class called Fragment. A Fragment is a self-contained component with its own UI and lifecycle; it can be-reused in different parts of an application’s user interface depending on the desired UI flow for a particular device or screen.

In some ways you can think of a Fragment as a mini-Activity, though it can’t run independently but must be hosted within an actual Activity. In fact the introduction of the Fragment API gave us the opportunity to address many of the pain points we have seen developers hit with Activities, so in Android 3.0 the utility of Fragment extends far beyond just adjusting for different screens:

  • Embedded Activities via ActivityGroup were a nice idea, but have always been difficult to deal with since Activity is designed to be an independent self-contained component instead of closely interacting with other activities. The Fragment API is a much better solution for this, and should be considered as a replacement for embedded activities.
  • Retaining data across Activity instances could be accomplished through Activity.onRetainNonConfigurationInstance(), but this is fairly klunky and non-obvious. Fragment replaces that mechanism by allowing you to retain an entire Fragment instance just by setting a flag.
  • A specialization of Fragment called DialogFragment makes it easy to show a Dialog that is managed as part of the Activity lifecycle. This replaces Activity’s “managed dialog” APIs.
  • Another specialization of Fragment called ListFragment makes it easy to show a list of data. This is similar to the existing ListActivity (with a few more features), but should reduce the common question about how to show a list with some other data.
  • The information about all fragments currently attached to an activity is saved for you by the framework in the activity’s saved instance state and restored for you when it restarts. This can greatly reduce the amount of state save and restore code you need to write yourself.
  • The framework has built-in support for managing a back-stack of Fragment objects, making it easy to provide intra-activity Back button behavior that integrates the existing activity back stack. This state is also saved and restored for you automatically.

Getting started

To whet your appetite, here is a simple but complete example of implementing multiple UI flows using fragments. We first are going to design a landscape layout, containing a list of items on the left and details of the selected item on the right. This is the layout we want to achieve:

The code for this activity is not interesting; it just calls setContentView() with the given layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <fragment class="com.example.android.apis.app.TitlesFragment"
            android:id="@+id/titles" android:layout_weight="1"
            android:layout_width="0px"
            android:layout_height="match_parent" />

    <FrameLayout android:id="@+id/details" android:layout_weight="1"
            android:layout_width="0px"
            android:layout_height="match_parent" />

</LinearLayout>

You can see here our first new feature: the <fragment> tag allows you to automatically instantiate and install a Fragment subclass into your view hierarchy. The fragment being implemented here derives from ListFragment, displaying and managing a list of items the user can select. The implementation below takes care of displaying the details of an item either in-place or as a separate activity, depending on the UI layout. Note how changes to fragment state (the currently shown details fragment) are retained across configuration changes for you by the framework.

public static class TitlesFragment extends ListFragment {
    boolean mDualPane;
    int mCurCheckPosition = 0;

    @Override
    public void onActivityCreated(Bundle savedState) {
        super.onActivityCreated(savedState);

        // Populate list with our static array of titles.
        setListAdapter(new ArrayAdapter<String>(getActivity(),
                R.layout.simple_list_item_checkable_1,
                Shakespeare.TITLES));

        // Check to see if we have a frame in which to embed the details
        // fragment directly in the containing UI.
        View detailsFrame = getActivity().findViewById(R.id.details);
        mDualPane = detailsFrame != null
                && detailsFrame.getVisibility() == View.VISIBLE;

        if (savedState != null) {
            // Restore last state for checked position.
            mCurCheckPosition = savedState.getInt("curChoice", 0);
        }

        if (mDualPane) {
            // In dual-pane mode, list view highlights selected item.
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
            // Make sure our UI is in the correct state.
            showDetails(mCurCheckPosition);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("curChoice", mCurCheckPosition);
    }

    @Override
    public void onListItemClick(ListView l, View v, int pos, long id) {
        showDetails(pos);
    }

    /**
     * Helper function to show the details of a selected item, either by
     * displaying a fragment in-place in the current UI, or starting a
     * whole new activity in which it is displayed.
     */
    void showDetails(int index) {
        mCurCheckPosition = index;

        if (mDualPane) {
            // We can display everything in-place with fragments.
            // Have the list highlight this item and show the data.
            getListView().setItemChecked(index, true);

            // Check what fragment is shown, replace if needed.
            DetailsFragment details = (DetailsFragment)
                    getFragmentManager().findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index) {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index);

                // Execute a transaction, replacing any existing
                // fragment with this one inside the frame.
                FragmentTransaction ft
                        = getFragmentManager().beginTransaction();
                ft.replace(R.id.details, details);
                ft.setTransition(
                        FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }

        } else {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), DetailsActivity.class);
            intent.putExtra("index", index);
            startActivity(intent);
        }
    }
}

For this first screen we need an implementation of DetailsFragment, which simply shows a TextView containing the text of the currently selected item.

public static class DetailsFragment extends Fragment {
    /**
     * Create a new instance of DetailsFragment, initialized to
     * show the text at 'index'.
     */
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
            ViewGroup container, Bundle savedInstanceState) {
        if (container == null) {
            // Currently in a layout without a container, so no
            // reason to create our view.
            return null;
        }

        ScrollView scroller = new ScrollView(getActivity());
        TextView text = new TextView(getActivity());
        int padding = (int)TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                4, getActivity().getResources().getDisplayMetrics());
        text.setPadding(padding, padding, padding, padding);
        scroller.addView(text);
        text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
        return scroller;
    }
}

It is now time to add another UI flow to our application. When in portrait orientation, there is not enough room to display the two fragments side-by-side, so instead we want to show only the list like this:

With the code shown so far, all we need to do here is introduce a new layout variation for portrait screens like so:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <fragment class="com.example.android.apis.app.TitlesFragment"
            android:id="@+id/titles"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</FrameLayout>

The TitlesFragment will notice that it doesn’t have a container in which to show its details, so show only its list. When you tap on an item in the list we now need to go to a separate activity in which the details are shown.

With the DetailsFragment already implemented, the implementation of the new activity is very simple because it can reuse the same DetailsFragment from above:

public static class DetailsActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_LANDSCAPE) {
            // If the screen is now in landscape mode, we can show the
            // dialog in-line so we don't need this activity.
            finish();
            return;
        }

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            DetailsFragment details = new DetailsFragment();
            details.setArguments(getIntent().getExtras());
            getSupportFragmentManager().beginTransaction().add(
                    android.R.id.content, details).commit();
        }
    }
}

Put that all together, and we have a complete working example of an application that fairly radically changes its UI flow based on the screen it is running on, and can even adjust it on demand as the screen configuration changes.

This illustrates just one way fragments can be used to adjust your UI. Depending on your application design, you may prefer other approaches. For example, you could put your entire application in one activity in which you change the fragment structure as its state changes; the fragment back stack can come in handy in this case.

More information on the Fragment and FragmentManager APIs can be found in the Android 3.0 SDK documentation. Also be sure to look at the ApiDemos app under the Resources tab, which has a variety of Fragment demos covering their use for alternative UI flow, dialogs, lists, populating menus, retaining across activity instances, the back stack, and more.

Fragmentation for all!

For developers starting work on tablet-oriented applications designed for Android 3.0, the new Fragment API is useful for many design situations that arise from the larger screen. Reasonable use of fragments should also make it easier to adjust the resulting application’s UI to new devices in the future as needed — for phones, TVs, or wherever Android appears.

However, the immediate need for many developers today is probably to design applications that they can provide for existing phones while also presenting an improved user interface on tablets. With Fragment only being available in Android 3.0, their shorter-term utility is greatly diminished.

To address this, we plan to have the same fragment APIs (and the new LoaderManager as well) described here available as a static library for use with older versions of Android; we’re trying to go right back to 1.6. In fact, if you compare the code examples here to those in the Android 3.0 SDK, they are slightly different: this code is from an application using an early version of the static library fragment classes which is running, as you can see on the screenshots, on Android 2.3. Our goal is to make these APIs nearly identical, so you can start using them now and, at whatever point in the future you switch to Android 3.0 as your minimum version, move to the platform’s native implementation with few changes in your app.

We don’t have a firm date for when this library will be available, but it should be relatively soon. In the meantime, you can start developing with fragments on Android 3.0 to see how they work, and most of that effort should be transferable.

A great guide to Turkey in Google Earth

Following in the footsteps of great sites such as 3DHawaii and 3DLasVegas, we travel to the other side of the globe to check out 3DLocationEarth, set in Turkey.

The basic idea of the site is similar the concept behind the Hawaii and Las Vegas sites; provide information about area hotels, businesses, schools, etc, and “fly” the user to each place using the 3D map on the screen.

turkey.jpg

Note: When the site first loads, all of the text is in Turkish. To convert, find the “language” drop-down near the top-right corner and select “English”.

While the amount of content on this site is quite impressive, it’s a bit clunky to use when compared to sites like 3DLasVegas. The Vegas site, if you recall, has a slick “Location Navigator” at the bottom of each item to help you easily explore it in 3D. This site has similar icons at the top of the page, but they’re very inconsistent. I suppose that’s part of the issue when dealing with such a large dataset. In addition, 3DLasVegas has thumbnails of all their locations on the left site, whereas 3DLocationEarth simply has a text-based list.

However, what is truly amazing is the 3D content that 3DLocationEarth has contributed to the 3D Warehouse, and therefore to Google Earth. As of right now, they have nearly 3400 models in Google Earth, including some notable items such as the Google headquarters in Mountain View, CA!

google.jpg

Even more impressive is their ability to view inside of various buildings. A great example of that is the Sirkeci Konak Hotel. Once you load that page, play with the silver icons at the top to go to the lobby, various rooms, the pool, etc.

We’ve shown you a few 3d interiors before, but this hotel is quite remarkable.

sirkeci.jpg

It will be interesting to see which direction Google pushes going forward. While the interior of this hotel feels similar to the Street View-based art gallery interiors that Google released earlier this week, they’re vastly different technologies. You would think that a single method for creating interiors would be ideal, but we may be a few years away from that.

In any case, check out 3DLocationEarth to see all of the great work these guys have done.