Multiple symbol definitions

I found a way to allow multiple symbol definitions in a static library assembled from a bunch of object (.o) files. The secret sauce is adding “-z muldefs” to the g++ command line. I’m not sure what it tickles in the linker but it made my pains go away. One of these days I’ll spend a weekend playing with “ld” to see what other magic I can come up with.

Android device automation with ADB

Today’s post is something that could be a time saver or a reference for those are are vaguely familiar with Android automation. I’m posting because its something I keep coming across and something I hate having to lookup. Let’s call it…

“How to automate your Android device”

The “adb shell input” command can be used to automate any attached Android device by sending simple commands and input over USB. The syntax is:

input [<source>] <command> [<arg>...]

The sources are:

The commands and default sources are:
text <string> (Default: touchscreen) [delay]
keyevent [--longpress] <key code number or name> … (Default: keyboard)
tap <x> <y> (Default: touchscreen)
swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
press (Default: trackball)
roll <dx> <dy> (Default: trackball)

You can send key codes as input events using “adb shell input key event <keycode>” using the following list of key codes:

1 -->  "KEYCODE_MENU" 
3 -->  "KEYCODE_HOME" 
4 -->  "KEYCODE_BACK" 
5 -->  "KEYCODE_CALL" 
7 -->  "KEYCODE_0" 
8 -->  "KEYCODE_1" 
9 -->  "KEYCODE_2" 
10 -->  "KEYCODE_3" 
11 -->  "KEYCODE_4" 
12 -->  "KEYCODE_5" 
13 -->  "KEYCODE_6" 
14 -->  "KEYCODE_7" 
15 -->  "KEYCODE_8" 
16 -->  "KEYCODE_9" 
17 -->  "KEYCODE_STAR" 
18 -->  "KEYCODE_POUND" 
19 -->  "KEYCODE_DPAD_UP" 
26 -->  "KEYCODE_POWER" 
28 -->  "KEYCODE_CLEAR" 
29 -->  "KEYCODE_A" 
30 -->  "KEYCODE_B" 
31 -->  "KEYCODE_C" 
32 -->  "KEYCODE_D" 
33 -->  "KEYCODE_E" 
34 -->  "KEYCODE_F" 
35 -->  "KEYCODE_G" 
36 -->  "KEYCODE_H" 
37 -->  "KEYCODE_I" 
38 -->  "KEYCODE_J" 
39 -->  "KEYCODE_K" 
40 -->  "KEYCODE_L" 
41 -->  "KEYCODE_M" 
42 -->  "KEYCODE_N" 
43 -->  "KEYCODE_O" 
44 -->  "KEYCODE_P" 
45 -->  "KEYCODE_Q" 
46 -->  "KEYCODE_R" 
47 -->  "KEYCODE_S" 
48 -->  "KEYCODE_T" 
49 -->  "KEYCODE_U" 
50 -->  "KEYCODE_V" 
51 -->  "KEYCODE_W" 
52 -->  "KEYCODE_X" 
53 -->  "KEYCODE_Y" 
54 -->  "KEYCODE_Z" 
55 -->  "KEYCODE_COMMA" 
61 -->  "KEYCODE_TAB" 
62 -->  "KEYCODE_SPACE" 
63 -->  "KEYCODE_SYM" 
66 -->  "KEYCODE_ENTER" 
67 -->  "KEYCODE_DEL" 
68 -->  "KEYCODE_GRAVE" 
69 -->  "KEYCODE_MINUS" 
76 -->  "KEYCODE_SLASH" 
77 -->  "KEYCODE_AT" 
78 -->  "KEYCODE_NUM" 
80 -->  "KEYCODE_FOCUS" 
81 -->  "KEYCODE_PLUS" 
82 -->  "KEYCODE_MENU" 

Here are some common use cases.

Send an upward swipe gesture to the screen:
adb shell input swipe 200 900 200 300

Simulate pressing the back key
adb shell input keyevent 4

And for something more involved, log into Skype on an Android Motorola G smartphone using your Microsoft credentials

#tap the Microsoft log in button
adb shell input tap 80 622
#tap username
adb shell input tap 200 622
adb shell input text
#swipe to dismiss keypad
adb shell input tap 200 472
#tap password
adb shell input tap 200 900
adb shell input text password
#send enter key
adb shell input keyevent 66

Yak Shaving with the IntelliJ 13 SQL Query Plugin

My 9 year old daughter wanted to play a Pokemon battle with me this afternoon. I started to tell her, “I’ll be right there after I finish shaving this yak…” I’m sure folks would pay good money to see the confused look on her face if I were to have actually said that. Hi, I’m Cliff. You’re here because you shave yaks for a living. I’m here because I just finished vacuuming about 200 lbs of yak hair from my kitchen floor.

Pokemon Battle

Pokemon Battle

What in the world are you yaking about?

If you’re as late to the latest tech jargon that came out lately as I am then you probably never heard of the saying. Yak shaving is a term, which I recently heard/learned on the last few Hanselminutes podcasts. (If you haven’t heard of Scott Hanselman yet, check him out.) It was actually coined by Carlin Vieri in his time at the MIT AI Lab (1993-8) after viewing a 1991 episode of The Ren and Stimpy Show featuring “Yak Shaving Day,” a Christmas-like Holiday where participants hang diapers instead of stockings, stuff rubber boots with cole slaw, and watch for the shaven yak to float by in his enchanted canoe. It refers to the “meta-tasks” that you have to complete before you continue the real work you set out to do. An example would be if you were to write an iPhone app for a friend in an attempt to become the next Instagram. Your friend would likely come to you within a week to ask how’s the app coming along. You would likely reply, “I’ve registered for my developer account, downloaded the SDK, and I’m searching the forums while I try to resolve this provisioning profile issue I have on my iPad because it’s registered under multiple accounts.” It’s pretty common to start a mobile app this way having half a week go by without having written one line of code. So in essence you’re “shaving a yak” when you should be plotting UI components in Xcode’s StoryBoard.

About my Yak
I was busy processing some financial spreadsheets with Groovy scripts trying to load them in an instance of the Java embedded Derby Database when I ran into several issues. First, I couldn’t remember all of the SQL commands and Groovy stuff I used to use over 10 years ago when I was heavy into database number crunching. I went on a minor tangent to learn how to setup Derby, re-learn the GDK, prepared statements, etc. Next I needed to verify my data was being loaded correctly. The Derby ij command line interface was frustrating me so I decided to install a SQL plugin in IntelliJ. The most popular one, DB Navigator, wouldn’t work with my Derby db so I found the other more popular plugin… SQL Query. This plugin almost worked but it wouldn’t let me add a custom driver as there was an API change.

com.intellij.openapi.fileChooser.FileChooser.chooseFiles nosuchmethod

I Googled the error and found a hit on the Atlassian Clover plugin which had apparently fixed the same API change. While trying to find the diff in there plugin source I had to remember how I back-track bug fixes in Jira at work. I quickly realized that Clover was not open source so I investigated another hit and found the actual one-liner that fixes the error. I then needed to find the most recent copy of the SQL Query plugin source. After downloading I had to learn how to write Idea plugins, a topic which is well documented but still takes effort/practice. Along the way I ended up checking out the entire source for Idea as part of the plugin development setup instructions. (Have I ever mentioned how much I hate downloading excessive source?) I fought with dependency issues in the plugin itself as half of its dependencies were bundled as src jars and the other half was not included. Long story lengthened, I hacked the build.xml, downloaded the necessary dependencies, setup run/debug configs, uninstalled my existing SQL Query plugin to avoid potential conflicts (I don’t think it was necessary but just to be safe…) flushed the toilet several times, almost choked on a cup of coffee. In the end I managed to get both my data loaded into Derby and a working plugin that I can use to visualize the data in my IDE.

If I had just one more hour to spare I would format the above paragraph in the shape of a yak but I think you get my point. I feel awkwardly proud of myself, yet also disappointed. On the one hand I learned/compiled/debugged/built my 1st modified IntelliJ Idea plugin and I did it all in about an hour or two. I notified the original author and emailed him my updates. I will also have a pretty decent blog article documenting my experience. On the other hand half the day is gone and I only have one database table loaded and no understanding of the data I set out to mine. Still I am proud having self served my plugin error. It is a rewarding feeling to be on the development side of a fix where I’m usually begging the author, “please could you fix this error? It happens when I click here.” That sort of pleading is usually accompanied with arduous IDE log files, stripped-down or recoded pieces of whatever project I’m working on to preserve IP, frustration and an awkward smile when the author replies with, “could you send me the OTHER log files and which version of the thing are you running?”

Bash Hackery

This morning I found myself playing with bash commands trying to move a bunch of dirtied files to a Subversion change list. Most people find themselves after searching for years in college, others find themselves after volunteering for a mission or going on a trip to another country. Not me, I find myself in the middle of an iTerm session trying to make sense of a bunch of text files that have been dirtied (modified) by an improperly factored project structure after running a build which doesn’t restrict its output to one path. Hi, I’m Cliff. You’re here because you’d like to make sense of a bunch of files on your hard drive. Maybe you’re in a situation similar to mine. Maybe you just like hacking with shell commands, piping the output of one command into the input of another. I’m here to explain what I learned this morning.

I was frustrated because “svn st” kept spewing out a bunch of modified files for my project and I hadn’t made source changes. I modified some setting in Eclipse to get things to compile but that was the extent. I use change lists in IntelliJ all the time and I know you can do the equivalent from the command line using Subversion. So I get to hacking with awk and grep and paste to try and make sense of “svn st” output. Here’s what I came up with.

svn st
(Lists all modified files, but you probably already knew that.)
? .idea/scopes
? .idea/workspace.xml
? atlassian-ide-plugin.xml
? out
? awesome-android-ad-api/bin
M awesome-android-app/.classpath
? awesome-android-app/build/retrieve-ivy.xml
? awesome-android-app/libs/awesome-android-ad-api.jar
? awesome-android-app/libs/awesome-android-ad-impl.jar
? awesome-android-app/lint-report-formatted.xml
? awesome-android-app/lint-report.html
? awesome-android-app/lint-report.xml
M awesome-android-app/.classpath
M thirdparty/XPartyManagedView/lib/.classpath
M thirdparty/HockeySDK-Android/.classpath

svn st | grep -e ‘.classpath’
(list only ‘.classpath’ project files modified, this filters my output for the changes I made in my Eclipse settings.)
M awesome-android-app/.classpath
M thirdparty/XPartyManagedView/lib/.classpath
M thirdparty/HockeySDK-Android/.classpath

svn st | grep -e ‘.classpath’ | awk ‘{print($2);}’
(Print only the 2nd column from the earlier svn output which we filtered with grep. It’s pretty cool because now we’re getting to the actual files we want to operate on.)

paste -d ‘ ‘ -s <(svn st | grep -e '.classpath' | awk '{print($2);}')
(Flatten the one column output above listing only the file names into a single line delimited with a single space ‘ ‘ character. This is even better because now all of the files can be passed as a parameter to a shell command but how do we do that?)
awesome-android-app/.classpath thirdparty/XPartyManagedView/lib/.classpath thirdparty/HockeySDK-Android/.classpath

svn changelist “‘Eclipse project modifications.’” `paste -d ‘ ‘ -s <(svn st | grep -e '.classpath' | awk '{print($2);}')`
(We use back ticks “`” to return the value of our piped command chain as a parameter to the svn change list command and viola!)
A ['Eclipse project modifications.'] awesome-android-app/.classpath
A ['Eclipse project modifications.'] thirdparty/XPartyManagedView/lib/.classpath
A ['Eclipse project modifications.'] thirdparty/HockeySDK-Android/.classpath

All thanks to the magic of grep and awk. You can do all kinds of magic by chaining awk to grep to see and piping into past or whatever combination your mind can imagine. It just takes a little patience to familiarize with the command line flags and things like regex. Once you get the hang of it you’ll be flying…

Mac Automator tip of the day

So I was looking in TextMate for one of my most favorite tools from IntelliJ. It’s the “Compare with clipboard” action that takes whatever you have selected and runs a side-by-side diff with whatever is on your clipboard. I thought for sure it would exist in TextMate but I was disappointed so I built my own using Automator. See the pic below for the entire source. (There’s gotta be a better way to share Automator source but I’m in a hurry and lazy so there ya’ go.) This workflow depends on Xcode’s FileMerge but you can substitute whatever diff tool you’re comfortable with. To create it, start Automator and select System service from the “New…” action then copy in the actions from the image. Name it “Compare selection with clipboard” and then where ever you are in your Mac you will have access to the tool from the context menu (right clicking) of any selection.

Automator workflow

Compare selection with clipboard

When I first posted this there was a small bug. I changed the get clipboard step to an Applescript command “get the clipboard” since the built-in Automator task returns styled text instead of raw text.

Build a better mousetrap (Chat apps)

I’ve been quietly working on a chat app. I built one a long time ago which has been sitting on Github forever without any updates, but I’ve also recently pushed my Android “how to” to Github, you can find it here. I love working in both the Android and iOS space as I get a unique insight that I try to share with others. I also like to compare both the development process and tooling across both platforms. Hi, I’m Cliff. You’re here because you want to build a better chat app. I’m here for much the same reason. With apps like Skype, Line, whatsapp, and others crowding the space you might wonder “what’s the point?” I’m embarking on this experience partly to familiarize myself with what’s changed in iOS 7 but mainly just because. Maybe it will turn into something or maybe it won’t.

I’m my latest effort I’ve actually tried updating Jinx to support iOS7. My first stage has begun with introducing Storyboards and playing with Autolayout. I will later ARC-ify it and rip out the dumb artificial intelligence in favor of what I have in the Android example. Finally I want to incorporate P2P networking, voice recognition and TTS in both apps but that will have to wait until I hit the lottery and can afford to quit my job. (I’m just brimming with ideas!) If you have ideas or insights, feel free to jump in!

My First C++0x!

I’d been talking up a storm about c++11 ever since this year’s ./build conference. I saw some folks talk about it and was immediately intrigued. While I love Obj-C I’ve never been much of a C/C++ coder and it always bothered me. Now with the new additions to C++ I feel I have no excuse but to take a deep dive. Hi, I’m Cliff. You’re here because you write some flavor of C code. I’m here solely because I got an adrenaline rush from completing my 1st unit test exercise using “Bandit” with the CMake build system. It’s a rush because I only learned CMake last week, literally between apk compiles. (a few months ago I was barely able to code hello world in regular make.)

What is C++0x?
If you haven’t heard, C++ is not legacy. There have been some enhancements! Back when I was in computer school the big deal was c99, which was a new standard or recommendation. Basically it was what most C++ programmers agreed to as the proper things to include in the language. Ever since then, most people I’ve known have maved on to things like Java, C#, Obj-C, Ruby, Python, etc. C++ was considered “what we used to do before we knew better”. I’ll admit, I let what little knowledge I had about C stagnate. In recent years, however, a bunch of smart people got together and decided to update the ol’ c99 standard and add some new flavor. They call this new flavor C++ 11 but you may see it referred to as c++0x or cx11 or any number of geek shorthand forms.

Why C++0x?
Why would you want to learn C++ or even any new variation of C these days when there are so many other things to do with your life like writing Ruby or Scala, or Clojure? Why would anyone care? Let’s take it back in the mid 2000′s when people used to rave about garbage collection, DSLs, and meta object programming and the like. Back then it was common to hear things like “RAM is cheap”, “CPUs can handle whatever we throw at them”, “Early optimization is evil!” We used to just allocate as needed and throw libraries in without caution. Then something happened. Apple released the iPhone. Mobile computing became important. Suddenly we were right back where we were in the late 90′s when counting bytes was critical. Also people started to realize that extra CPU cycles, and excessively used memory would translate into real $$ in the data centers where racks of servers would run non-stop. Something as simple as unwinding a tail recursive call into a loop could save hundreds if not thousands of dollars. Speed became important again.

As much as I dreaded learning Obj-C and reference counting back then I grew a fond appreciation for what it meant in terms of performance. If you’ve ever tried writing a game on a memory constrained device with garbage collection then you’re probably familiar with with the Flyweight pattern or why it helps to avoid garbage collection. After a while you may have also noticed your program started to resemble a C like program where you obsess over releasing objects to some sort of pool and count memory like a tax collector counts… err.. uh… tax stuff. Bad analogies aside, the closer you get to C the better your software runs on both embedded and on servers.

So that’s why I’m sort of excited. I want to get closer to C and C++11 allows me to do that while providing many of the high level constructs I’ve grown familiar with over the years like literal collection initializers and the new “auto” keyword, and a decent Thread model. I’m getting ahead of myself, however. I’ve barely completed “Hello Bandit world!” I still have a lot to learn but it’s all looking gravy already.

CMake, C++, and TDD

I’m in the middle of an experimental C++ fibonacci program in an attempt to familiarize myself with CMake. I barely know “Make” and now I’m ankle-deep in CMake. How did I get here? It began as part of my exploration into C++ TDD. I’ve been periodically playing with C++ testing tools trying to find a comfortable way to develop some decent cross platform logic. My exploring took me to mnmlstc/unittest. Hi, I’m Cliff. You’re here because you write unit tests. I’m here trying to find the appropriate way to do so in C++.

there’s not much to blab about tonight. I’m only passing #define macros from a config header template through to my c++ logic and scratching the surface of integrating tests with CMake. So far I’ve learned that configuring the install target of your make file uses a default prefix of “/usr/local” when you use relative paths but you can override this by using absolute paths. I’ve also learned how to “add_definition”s.

I’m a long way from mnmlstc but I’m having fun. Hopefully I’ll have some decent object models emerging from my experiments… and hopefully these models will be properly coded in C++11. Have you ever tried to understand a new technology from the eye of a test framework you’ve never used before? Me neither…

Git sparse checkout

I just wanted to share something in git I learned rather recently. Don’t laugh either because I I know a whole lot of you are probably like, “git experts” and thinking… “c’mon son? You just now figuring that out?” If that is you keep your mouth shut. This post is not intended for you. It is instead intended for those of you who are still parked in the Subversion mindset. It is for Old timers like myself who are delighted when they finally figure out what the rest of the tech community has been raving about for years. Hi, I’m Cliff. you’re here because you’re getting long in the tooth and trying to keep up with technology. I’m here because my teeth are just as long. I’m also here to tell you that you really don’t need to clone the whole git repo.

Here’s the story (because a lot of my posts have some sort of backstory): I was trying to figure out how to get gdb working in a Gradle-managed Android Studio project. Y’see, I’ve already managed to get an Android Studio project with a native component to build and run on both the device and the emulator. Now I’m trying my hand at C++/gdb debugging. Something I’d never done even on a regular ant managed project. (What’s that? You didn’t know that you can use Android Studio and Gradle to build/run an Android project with native libraries? Stay tuned for the updated post that I thought I’d already told you about!) That venture got me looking for the source to the Android plugin for Gradle. There are a couple of android plugins but I wanted the one that was running as part of my Android Studio project. I found the source and was intimidated by the layout of the source on Google’s site. Intimidated, I immediately told myself I wasn’t trying to checkout the entire thing onto my tiny 256GB HD. I have a strong distaste for checking out projects with huge a source base. (I later learned that the part that I needed to check out wasn’t really all that big and negated the need for both my exploration into git sparse checkouts and this rather long blog update but it was a fun exercise none the less.) So here’s the short instructions on how to do it. I found out from this S/O post.

Assuming you want to checkout the new Gradle build system but only want the gradle subfolder from the 4.3_r0.9 tag as I did you would do something like this:

$ mkdir android-tools
$ cd android-tools/
$ git init
Initialized empty Git repository in /Users/clifton/dev/android-tools/.git/
$ git remote add -f origin origin
remote: Counting objects: 15, done
remote: Finding sources: 100% (15/15)
remote: Total 11593 (delta 2852), reused 11593 (delta 2852)
Receiving objects: 100% (11593/11593), 6.09 MiB | 2.49 MiB/s, done.
Resolving deltas: 100% (2853/2853), done.
* [new branch] jb-mr1-dev -> origin/jb-mr1-dev
* [new branch] jb-mr1-dev-plus-aosp -> origin/jb-mr1-dev-plus-aosp
* [new branch] jb-mr1-release -> origin/jb-mr1-release
* [new branch] jb-mr1.1-dev -> origin/jb-mr1.1-dev
* [new branch] jb-mr1.1-dev-plus-aosp -> origin/jb-mr1.1-dev-plus-aosp
* [new branch] jb-mr1.1-release -> origin/jb-mr1.1-release
* [new branch] jb-mr2-dev -> origin/jb-mr2-dev
* [new branch] jb-mr2-release -> origin/jb-mr2-release
* [new branch] jb-mr2.0-release -> origin/jb-mr2.0-release
* [new branch] master -> origin/master
* [new branch] tools_r21 -> origin/tools_r21
* [new branch] tools_r22 -> origin/tools_r22
* [new branch] tools_r22.2 -> origin/tools_r22.2
* [new branch] version_0.5 -> origin/version_0.5
* [new tag] android-4.2.1_r1 -> android-4.2.1_r1
* [new tag] android-4.2.1_r1.1 -> android-4.2.1_r1.1
* [new tag] android-4.2.1_r1.2 -> android-4.2.1_r1.2
* [new tag] android-4.2.2_r1 -> android-4.2.2_r1
* [new tag] android-4.2.2_r1.1 -> android-4.2.2_r1.1
* [new tag] android-4.2.2_r1.2 -> android-4.2.2_r1.2
* [new tag] android-4.2_r1 -> android-4.2_r1
* [new tag] android-4.3_r0.9 -> android-4.3_r0.9
* [new tag] android-4.3_r0.9.1 -> android-4.3_r0.9.1
* [new tag] android-4.3_r1 -> android-4.3_r1
* [new tag] android-4.3_r2 -> android-4.3_r2
* [new tag] android-4.3_r2.1 -> android-4.3_r2.1
* [new tag] android-cts-4.2_r1 -> android-cts-4.2_r1
* [new tag] android-cts-4.2_r2 -> android-cts-4.2_r2
* [new tag] android-sdk-support_r11 -> android-sdk-support_r11
remote: Counting objects: 4, done
remote: Finding sources: 100% (4/4)
remote: Total 4 (delta 0), reused 4 (delta 0)
Unpacking objects: 100% (4/4), done.
* [new tag] version_0.5.0 -> version_0.5.0
* [new tag] version_0.5.1 -> version_0.5.1
* [new tag] version_0.5.2 -> version_0.5.2
* [new tag] version_0.5.3 -> version_0.5.3
$ git config core.sparseCheckout true
$ echo 'gradle/*' >.git/info/sparse-checkout
$ git checkout android-4.3_r0.9
Note: checking out 'android-4.3_r0.9'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

HEAD is now at 70d8da9... Merge "Move version to 22."

As you can see above there are quite a few tags associated with this project but so far the sparse checkout seems to have worked as advertised. I’m not sure how much space savings I’m seeing over cloning the entire project but hopefully this tip will serve to help others, or myself as I sometimes look over old posts to remember how I did something.

Can your IDE do this?

So I’m tapping out a test method in my favorite tool for developing mobile software and it looks like this:

View errorMessage = errorDialog.findViewById(findIdForStringIdentifier(ERROR_MESSAGE_TEXT));
assertTrue("Expecting a TextView field", errorMessage instanceof TextView);

Then I notice… no, scratch that I don’t even notice that auto-complete has sprung into action and is offering me the proper completion at the top of the list, “getText()”. It happens in the most subtle way as my subconscious mind already knows what it wanted to do and it directs my fingers to accept the completion. What I end up with is:

View errorMessage = errorDialog.findViewById(findIdForStringIdentifier(ERROR_MESSAGE_TEXT));
assertTrue("Expecting a TextView field", errorMessage instanceof TextView);
((TextView) errorMessage).getText()

Hi, I’m Cliff. You’re here because your IDE doesn’t do what my IDE does. I’m here because I’m ecstatic over what I’ve learned in the last 10 minutes. Look again at the above code snippets, both before and after and follow what happened in between. The important part is where the 1st line establishes a local variable of type “View”. To my amazement auto complete picked up and inferred it was a type of TextView when I started keying the 3rd line and it offered me not just any random or alphabetized list of suggestions but a preferred suggestion that matched exactly what was being conjured up in my grey matter. (For those unfamiliar with Android programming, a view does NOT include a “getText()” method.) And while I didn’t have to futz with the usual, “oh… I have to either declare my local type as a TextView or add a cast” my IDE does this inference then later performs the cast on my behalf keeping my cursor within the proper context so I can continue adding logic. It happened so “matter of fact” like and so quickly that I didn’t catch on until I had completed typing the line at which point I had to do a double take.

How does it know I need a TextView? Is it because of the preceding assert with the “instanceof” comparison? Does it just naturally assume most views will need to be eventually cast to a “TextView” type because that’s all most Android devs know how to use anyway? Is it reading through the xml layout and determining the type based on the integer id returned from my custom “findIdForStringIdentifier” that is taking a String constant id? Has Jetbrains quietly figured out how to read brainwaves over my Mac’s wifi antenna? I don’t know and I don’t really care!

I had done similar programming in other IDEs (Eclipse, Netbeans, X-Code, Visual Studio) but never have I ever had such an experience where an IDE literally read my mind, did the excessive back-spacing, parenthesis wrapping, casting, and continuation of thought for me. It’s these little nuggets that I keep finding in IntelliJ Idea that keep me addicted. I could go on for days on how wonderful this one… read it… ONE experience, out of hundreds of similar experiences, made my life today but I won’t. I’ve argued the merits of Idea to plenty of developers over the years but until you actually experience how do they put it…? “Development with pleasure” Until you actually live out a few of these scenarios you will continue to grind out code the usual way, hitting refresh/rebuild project to clear the red squiggles that really shouldn’t be there, dealing with arbitrary auto-complete suggestions, not truly being able to refactor code effectively as you could otherwise.


Get every new post delivered to your Inbox.

Join 251 other followers