Tor Norbye's Blog
Wednesday, July 18, 2012
Why I've Been So Silent
The reason is simple: I'm posting somewhere else. For Android related posts, such as recent features, I'm posting to the http://tools.android.com site, including its Recent Updates blog.
And for everything personal, as well as shorter work related posts, I'm using Google+:
https://plus.google.com/u/0/116539451797396019960/posts
I'm pretty active there, so if you've been following my blog you may want to redirect your feed reader.
Thursday, November 18, 2010
Building the Android IDE Tools
Andy Rubin recently tweeted how to build Android - and as you can see, it's easy and the instructions fit within the 140 twitter character limit. However, if you want to work on the IDE tooling itself, there are many other tips and tricks to know about. The purpose of this blog entry is to document how you can set up an environment to build the Android SDK, including the IDE support, and have everything configured such that you can run and debug the Android support directly from within the IDE.
My hope is that some of you, once you have the Android tooling up and running, will decide to look under the covers, tinker with the bits, and hopefully find and fix bugs, or even contribute features! I'll talk more about contributions in a later blog post; today the focus is on building and running the bits even if you have no intention of contributing. Even bug reports from you on newly developed features would be useful.
Setup
First, you'll need to install the prerequisites for your platform. This means you'll have git, a C compiler, etc. There are quite a few steps here, and it's all platform dependent, so I'll just point you to the official build instructions where we have detailed instructions: http://source.android.com/source/download.html . If you're on a Mac, pay particular attention to the instructions on creating a case sensitive filesystem image. When I started I glossed over that part and hurried down to the git checkout command, only to discover later that I had to start over.
One other Mac specific tip, which isn't in the main Android page yet, is that Apple's recent JDK update "broke" the Android build on Snow Leopard since the build uses JNI. The location of the JNI header file changed or disappeared with the JDK update, so you now need to go to Apple and get the developer SDK, JavaDeveloper.pkg from http://connect.apple.com.
NOTE NOTE NOTE: Xavier tells me that building on Windows is more difficult because the SDK itself doesn't build on Windows, so you may have to download a system image and then build the tools components themselves manually. Hopefully I'll be able to provide more details on this soon.
Once you have everything configured, check out the source code using the first half of Andy Rubin's tweet:
$ mkdir android
$ cd android
$ repo init -u git://android.git.kernel.org/platform/manifest.git
$ repo sync
During the repo init command, it will ask you for your name and e-mail address; these will be used later if you decide to check in changesets and upload them for review.
Build
Now you are ready to build. While you could just type "make", this is where our SDK build instructions diverge a bit.
In a bash shell, run these commands
$ . build/envsetup.sh
$ lunch sdk-eng
$ make sdk
That will run for quite a while and build everything. It will also create a lot of symlinks to help you edit and compile files within Eclipse.
Next, configure Eclipse. We support Eclipse 3.4 and up, but we're currently using Eclipse 3.5.2 for development. Make sure you get a version with RCP support, such as the "Eclipse for RCP and RAP Developers" distribution. I'm using eclipse-rcp-galileo-SR2-macosx-cocoa. (You can use Eclipse 3.6.1 - I just tried it. However, the test project won't compile. You won't need that project to run the Eclipse support. If you're going to be making changes you'll want to have it, but for now, if you're just wanting to try the new support and don't want to install an older Eclipse, go right ahead, and skip the "tests" project in the projects-to-import list below.)
To configure Eclipse, right click in the Workspace and choose "Import...", then select "Existing Projects into Workspace". You want to import precisely these projects:
- sdk/eclipse/plugins/com.android.ide.eclipse.adt
- sdk/eclipse/plugins/com.android.ide.eclipse.tests
- sdk/eclipse/plugins/com.android.ide.eclipse.ddms
- sdk/ddms (import all 3 projects - ddmlib, ddms-plugin, ddmuilib)
- sdk/ide_common
- sdk/androidprefs
- sdk/sdkstats
- sdk/layoutlib_api
Things won't compile yet, until we finish the configuration.
Go to the Preferences panel, search for Classpath Variables, and define ANDROID_SRC pointing to the top of your source tree (e.g. the "android" dir in the tweet instructions).
Then right click on the ddmuilib project and open its properties. Go to Java > Build Path, and open the User Libraries tab. You should see ANDROID_JFREECHART and ANDROID_SWT as libraries there. These will need to be configured. For ANDROID_JFREECHART, select the library and click on Add Jars, then point to prebuilt/common/jfreechart and add all 3 jars. For ANDROID_SWT, add the 3 jars under prebuilt/common/eclipse, as well as the architecture specific version - for my Mac it's prebuilt/darwin-x86/swt/swt.jar but this will depend on your OS and architecture. (When I used Eclipse 3.6 I couldn't just add the jars from this dialog, I had to go and open the User Libraries panel and there I could define libraries named ANDROID_JFREECHART and ANDROID_SWT.)
Voila -- now all the errors in the Problems view should disappear! (There are still quite a few warnings.)
Run and Debug
The next step is to add a run configuration so you can run and debug the ADT. Hit the Run button. When it asks you what to run it as, choose "Eclipse Application".
Important: Open the Configurations panel and edit the new configuration. In particular, go to the "Plug-ins" panel, and uncheck the third or so item, "com.android.ide.eclipse.tests". If you enable it you can run into some very subtle bugs where jars from the test module's classpath are accidentally conflicting with different versions of jars in the tools plugin. I wasted nearly a day on that issue...
If you're on Mac and you get "java.lang.UnsatisfiedLinkError: Cannot load 32-bit SWT libraries on 64-bit JVM", you need to add "-d32" as an argument to the VM.
You should now be able to run the ADT - it will invoke a second instance of Eclipse, where all the Android tooling is baked in. The first thing you need to do is point the tool to a version of the SDK. Open the Preferences panel, and in the Android panel go to the text field where you can point to an SDK root. If you have downloaded versions of Android in the past, you can point to the root containing all of the different platforms here. However, you don't have to -- when you ran "make sdk" earlier you built a trunk version of the Android SDK (from here on referred to as "AOSP", which I think stands for Android Open Source Project). Therefore, you can point to your build output here -- and as you continue pulling down new changes and rebuilding the SDK, your Eclipse target will also use the latest and greatest.
To point to it, use <your tree>/out/host/darwin-x86/sdk/android-sdk_eng.tnorbye_mac-x86/
That exact path will not work for you, since it has various architecture and user names in it. So open the file chooser and drill down, first to out, then host, then your os and architecture, then sdk, and then some directory which contains "android-sdk_eng", your username and your platform. Hit OK.
After a brief pause you should now see a platform listed in the listbox in the Android panel, and it will identify itself as version "AOSP". If you instead point to officially released versions of Android, you'll see versions like "5", "6" and "7". The reason we don't use a number for the trunk version is to prevent you from accidentally building an app compiled against this trunk version, and then releasing it on the market.
Now that you have your Android versions configured, you can create a new Android project. Do New > Android Project, and in the New project dialog, you need to go and choose the AOSP platform in the platform listbox. Fill out the dialog. The only trick is that it asks you for a "Min SDK Version", and here you should again type "AOSP". You can now go and try for example the Layout Editor, by opening res > layout > main.xml.
We're working actively on the layout editor, but as you can see we could use help in lots of areas, from feature development, to icon work, to bug fixing, to bug reporting! (Again, I'll talk more about contributions in a follow-up post.)
To stay up to date, just go to the command line, type "repo sync", wait for a while, and then redo the make steps (source build/envsetup.sh, lunch sdk-eng, make sdk, create_symlinks), and reopen Eclipse and rebuild all. If you get a build error, you can wipe out the entire out folder to build from scratch, but I rarely have to do that.
You can add additional Android platforms, such that you can choose which platform to use for WYSIWYG rendering (just like you can already switch theme, orientation, etc):
This is a new feature added just in the last couple of days. It lets you target older platforms but visually work with newer platforms, and quickly switch between them to see how your layout looks on different platforms. Of course, to use this you need to point your root Android tree to an install containing multiple platforms. If you do add additional platforms, make sure you copy older platforms (android-6, android-7, etc) into the platforms/ folder of the newly built SDK, rather than the other way around. This is necessary because the directory structure changed recently.
Edit
Now that you can build and run, let's take a look at the source code. The main Eclipse project to look at is the "adt" project, which is the Eclipse plugin.
First, you can configure your editor to use our custom dictionary to help the spell checker recognize words that are in our comments but are not in the default Eclipse English dictionary. Search for Spelling in the options dialog, and add sdk/eclipse/dictionary.txt as the "User Defined Dictionary" path.
Second, if you will be doing any editing of the source code, make sure you configure your editor to use our formatting preferences and our import order. Open the Java Code Style dialog, and for the formatter, import development/ide/eclipse/android-formatting.xml . For Organize Import, import development/ide/eclipse/android.importorder . The code style for the Android source code base is document in http://source.android.com/source/code-style.html.
***
That's it! You should now be able to get the source code, build, edit, run and debug the Android IDE tools!
Friday, October 15, 2010
Android
In particular, I'm working on tooling for Android. That means I get to work fully in open source again which I enjoyed in the NetBeans days. We use the public Android git repository and I submit my fixes into the Gerrit code review tool which is a really nice workflow tool for git; I highly recommend it.
As you may or may not know, the Android tooling is Eclipse based, so I'm learning both to use Eclipse as well as writing plugins for it. There are some things I'm missing from NetBeans, but there are also some new features I'm welcoming. I just need to rewire my motor reflexes for it all to feel natural!
In the past when I've posted NetBeans tips, many of you have helpfully listed the corresponding Eclipse (and IntelliJ) shortcuts. While I have found replacements for many of the features I'm used to, I'm still stumped with the following, so if any of you could enlighten me - either with existing keybindings or optional plugins, I would appreciate it:
- Most important: How can I, via the keyboard, navigate through my matches in the Find Usages search? This was my favorite keystroke in NetBeans (and I had meant to do a code tip about it) - if you press Cmd-period, you can navigate through find usages searches, build errors, diff view differences, etc. In Eclipse there is also Cmd-period, but it only works if the Search window has focus - and it doesn't work in the Diff view. (In fact, Cmd-period doesn't work in the Search window on the Mac; I don't know why, because it's listed as the shortcut, and Cmd-period does work in the editor view to navigate parsing errors. Luckily I've found the workaround of Cmd+Shift+period which navigates backwards, so I'm using that one, but I still have to give the Search window focus.)
- When I select a symbol in the editor, all the occurrences (of the same variable, class, method, etc) are highlighted. In NetBeans I could navigate through these via a shortcut. Is there a way to do that in Eclipse? (Somebody told me that I could select the text and then use Cmd-k to navigate, but that's text-search based and will jump to unrelated symbols that happen to be the same string, e.g. the same parameter name in a different function).
- How can I, via the keyboard, see the light bulb text? Sometimes I get a light bulb in the editor margin trying to tell me something. I have not found a way to see what it's saying other than hovering over it with the mouse. In NetBeans, Alt+Enter would show the light bulb text above the current line as well as the quickfix suggestions below the current line. In Eclipse I know I can press Cmd-1 to see the suggestions, but it doesn't show what the warning is and sometimes it isn't obvious from the suggestions what the problem is. (For example, for an unused variable the suggestion is "Remove x").
- I'm really missing the NetBeans version control view (the one which lists the "status"; all your changed, added, and removed files and made it trivial to walk through and diff them). Maybe this is just because I'm working with git and there isn't a plugin which offers that view yet?
- This is minor, but when I initiate instant-renaming, it doesn't select the text, which NetBeans did, and I prefer that (so I can hit rename and type the new name). Is there a way to configure it to do that?
These are the answers I've asked some Eclipse users about and still haven't learned the answers to. One question I did ask, and eventually found the answer to is how to navigate files similar to NetBeans' Ctrl-Tab feature. The reason I'm bringing it up is that only one person finally showed me the right feature but most people didn't know about it - so if you're an Eclipse user, maybe you'll find this useful: "Next Editor". It's bound to something I can't remember in Eclipse, but I rebound the action called "Next Editor" to Ctrl-Tab (since Cmd-Tab is the equivalent application-switch shortcut on the Mac). You can press it to jump between two files - but the key thing is that when you're jumping between more than two files you can keep holding the Ctrl key after typing Tab to see a dialog of your recently edited files in most-recently-edited order. I find this more intuitive than the jump-between-editing-locations since sometimes I jump to a file, look for something (without editing) and then I want to go back.
Anyway, I'm having a great time. I love working on tools, and perhaps even more, Android!
(By the way, if there are any SWT mavens out there, I would love an answer to this question which I posed on StackOverflow. If you know the answer but don't have or want to have a Stackoverflow account, feel free to post it here and I'll link back to it.)
Monday, September 27, 2010
Next Chapter
Google seems to be open to employee blogging, so hopefully I can continue writing about work related topics. And I realize I've forgotten to finish my IDE tips "series" - I have a few more tips that I planned to cover so I'll try to get around to that soon!
Friday, September 24, 2010
System.exit(0)
I joined Sun in 1996 and I've been here ever since -- including the Oracle acquisition six months ago. It's been a wonderful time. I've met many of the world's most talented engineers, I've had the chance to work on some interesting projects and I've learned a lot! I looked at my badge that I'm about to turn in (picture on left) and it has the original photo taken when I joined -- and I look like a kid!!
However, it's time to move on. I've chosen to take a new opportunity where I'll get to have even more fun. For now, I'd like to thank all my former Sun and Oracle coworkers for the great experiences you've given me and wish you luck with the future!
System.exit(0);
Friday, September 17, 2010
New blog home
- I exported from Roller into a MovableType format.
- I used the http://code.google.com/p/google-blog-converters-appengine/ project to convert the movable type file into a file suitable for Blogger import.
- However, all the dates were broken; they all showed up with today's date. I tracked this down to the fact that the converter filter assumes the times in the archive are in 12 hour format (with am/pm at the end, and for me they were not.) So I fixed this by replacing the following line in google-blog-converters-r89/src/movabletype2blogger/mt2b.py :
return time.strptime(mt_time, "%m/%d/%Y %I:%M:%S %p")
with
return time.strptime(mt_time, "%m/%d/%Y %H:%M:%S") - The biggest challenge was dealing with the images; the blog converted okay but still referenced all my image resources on blogs.sun.com. To fix this, I first uploaded all my images to picasaweb and made them world writable. Then I looked at the page in picasaweb which shows thumbnails for all the images in the album, and I saved it. This file contains image links. Unfortunately, the images all end up with many different url prefixes, so it's not as simple as just replacing the old image prefix with the new one. I wrote a short Java program to extract all the image links, and create a map from file base name to the full url.
- I then wrote a simple Java program to rewrite the Blogger import file such that it replaces all urls of the form http://blogs.sun.com/... with the corresponding new Picasaweb url using the above map. I also took the image urls from the thumbnails and removed the /s128/ portion of the url, which gets you the original image rather than the thumbnail. (Also, it turns out picasaweb insists on converting all .png images and .gif images to .jpg, so the URLs have to adjusted for those cases.)
- I also did a little bit of post processing on the results; for example, I collapsed some repeated br tags that are no longer necessary, and I inserted a "This blog entry was imported and urls might be wrong"-warning at the top of each imported post.
- One final tip: I discovered that a number of my images were missing. It turns out that Picasa by defaults hides small images (of which I had many) - so these were not uploaded! There are places to both go and enable these as well as adding .gif to the list of included file extensions, so handling this is easy once you're aware of the problem.
Tuesday, June 29, 2010
Don't Use Implicit Return Types
WARNING: This blog entry was imported from my old blog on blogs.sun.com (which used different blogging software), so formatting and links may not be correct.
JavaFX, like Scala, is a fully statically typed language. However, unlike Java, it allows you to omit type declarations in many places, since it can infer it. Coupled with the fact that you can use expressions as statements, and that the last expression in a function will be the return value, this lets you write really simple and clear code.
def s = "Hello";
def len = s.length();
function product(a: Number, b: Number) {
a * b
}
The function above shows an "Implicit Return Type": The compiler figures out the return type, which in this case will be a Number, and that is the signature computed for the function.
Unfortunately, this can sometimes lead to trouble! Here's a real-world example:
public function clearSelection() {
selected = null;
}
This function clears the selection in a node. The intention of the developer was probably for this function to have a "void" return type. But that is not the return type! The last statement is an expression, an assignment, which has the type of the left hand side, which is actually a node.
So the return type here is a Node! And it could easily have leaked an implementation class too.
This may not seem like a big deal here, but what if a subclass wanted to override this function? It would try this:
override function clearSelection() {
super.clearSelection();
moreStuff();
}
And this would fail compilation, with a surprising error message:
File.fx:1: incompatible types
found : void
required: Node
override function clearSelection() {
1 error
That's right, your subclasses will now need to deal with this return type too! If it's an implementation class, they're in trouble!
There are other reasons implicit return types are bad too. Here's a function specifying a desired padding for a node:
public function padding() {
5
}
The user may have intended for this to be a Number, but since the default is "5" instead of "5.0", the implied type here is Integer, which means that subclasses will need to round their desired padding to an integer. And this is not always a good thing - see the pixel considerations article.
For all of the above reasons, our Coding Conventions Document states that you should not use implicit types, at least not for any non-private API. That includes package, protected and public functions. However, it's a simple mistake to make. We've all made it! For that reason, to help track these down, I've created a quickfix for NetBeans which identifies and fixes these problems. Here's what happens if you look at a function like the one described above:
The light bulb and underline warns you that there is a problem here. Clicking on the light bulb, or pressing Alt+Enter when the caret is on that line, shows this info:
It's telling you that you have an implicit return for a public function, and it's offering to insert the actual, current return type of the function. It's also offering to make the function Void.
Pressing return will fix the function:
There are certain return types you cannot express in JavaFX script - such as returns including generics signatures. The quickfix won't warn about those since there is nothing you can do.
You can find the module on the Plugin Center here. Hopefully it will be as useful to you as it has been to me!
P.S. We discussed this topic (implicit return types in JavaFX and Scala) for a while on the latest
Java Posse Podcast episode.