All posts in category "Android"

The beta quick & dirty: because of reasons, Androblip is being rebuilt. So there’s now a beta-program. This post is about that, check out that linked post for more info about how to join etc.

Beta 3.1.7

While there is a nasty bug I have been ignoring for some time going around (hint: you probably don’t want to change orientation that much :) ), I figured that could be ignored a bit longer in favour of this piece of feature-requesting (thanks by the way)

One thing I’d love is to move the ‘subscription’ view closer to the start, I find myself having to flick through the views every time i open it to see the people that I actually care about.

– Shane

That was bugging me as well, so that will be fixed. This was harder then it looked, but this was a great starting point:

The problem is that the longclick isn’t very intuitive for many users, including some powerusers. For 100% of my alpha-tester it wasn’t very clear what was supposed to be happening (thanks Ilse), meaning that it clearly was a problem.

So I wanted to just move stuff around on the first touch, but sadly the code I have doesn’t quite translate to that very easily. Moving some of the onItemLongClickListener code to the onTouchListeners helped though, but it’s still a bit of a hack. On the other hand, it does like it works good enough, especially for beta testing, so there we are!

Talking with one of the testers (hi Osmo!) about the source, I started thinking on how to proceed with some stuff. Basically, his question was, and I somewhat agree,  why I don’t just open-source it. Now, there is always some sort of code-shyness involved with that, where you have to show the world what sort of mess you made late night, just after missing the Balmer peak, or just stuff you didn’t really fix in a good way. This is only a small I part, and not really stopping me at the moment.

The point is that I don’t know if it will be worth the effort. It will be some effort to get as much as possible in the version control, but not too much (API keys and all). Then my own compile, release, push etc cycle needs to be changed so I can easily work, but get the ‘clean’ version pushed publicly, things like that.

I’m really not sure anyone would be willing to participate, and how much it would help. Anyone at all even have thoughts on that?

As I’ve said before in other places: statistics are cool. So here are some numbers for you! These are available to us developers in the Android market.

Devices

21%8.2%7.9%7.5%47.9%
1 HTC Desire 21.0%
2 Samsung Galaxy S 8.2%
3 HTC Desire HD 7.9%
4 HTC Wildfire 7.5%
5 Motorola Droid X 4.3%
6 HTC Sensation 4G 3.3%
7 HTC Desire S 3.3%
8 SEMC Xperia X10 2.3%
9 Samsung Galaxy S 2.3%
10 Samsung Galaxy S2 2.3%

As you can see, the HTC-Desire is having a big lead! Of course people are running Android on those devices (No, really? Yeah, really :) ). More than 50% run 2.2, but there’s also a 1.5 hidden in the userbase somewhere:

OS versions

9.5%12.8%26.2%51.5%
1 Android 2.2 51.5%
2 Android 2.3.3 26.2%
3 Android 2.1 12.8%
4 Android 1.6 1.7%
5 Android 1.5 1.0%
6 Android 2.3 0.7%
7 Android 3.0 0.3%

 

New project, new problems.

Another minor fix you “just need to know”. After some server changes (I moved my SVN installation for one), I decided to just start a new Eclipse project as opposed to ‘fixing’ the old one to the new SVN location.

My basic steps are somewhat like:

  • Make a new Android project with some fake settings
  • Connect to SVN
  • Team->revert the hell out of it

Most of the time this works well.

The problem:

There seems to be a class missing, but there isn’t:
After having all the files, the application still doesn’t work. It compiles and goes to the emulator nicely, but then this happens:

ERROR/AndroidRuntime(287): java.lang.RuntimeException:
Unable to instantiate activity ComponentInfo{packageNameGoesHere}:
              java.lang.ClassNotFoundException:
packageName.ClassName in loader
              dalvik.system.PathClassLoader@44e7a8a8

And:

Caused by: java.lang.ClassNotFoundException:
                   packageName.ClassName in
                   loader dalvik.system.PathClassLoader@44e7a8a8
           at dalvik.system.PathClassLoader.findClass
                   (PathClassLoader.java:243)

No fun at all.
This error is quite obvious: it calls a certain class that cannot be found. In this case it was the class of my main activity. Not a thing that would be easily to miss. It was there in the source of course, no errors in sight, etc, but it still didn’t register as being there. This is of course a warning sign that something is wrong with your building path. But what?

The Solution

For some reason Eclipse had decided that –as opposed to every sane default–  my /src folder didn’t need to be in my build-path. Easily fixed if you this is the problem:

  • Open the build-path (right-mouse on the project -> build-path -> configure build path, or project-properties-> Java Build Path)
  • Click the Source tab.
  • Make sure your /gen and your /src paths are listed there.
  • While you’re at it, if you use google analytics, make sure that libGoogleAnalytics.jar is present in the libraries tab!

Scope

Because I was trying Ubuntu 10.10 on my laptop, I had to install a new development environment. Not too much work: I’ve used the installing instructions from Google [1].

This basically boils down to:

  1. Install Eclipse (I just used the ubuntu software center for this).
  2. Download Android SDK and unpack it.
  3. Install Android ADT plugin for Eclipse using the Eclipse install-software feature [2]
  4. Set the path to the android SDK / tools (step 2)  in the Eclipse preferences.

I didn’t install the JDK, because it was on my machine by default. I assume the package manager has that, but I’m not sure. Now I’m all happy with my new toys, installing Subclipse for SVN, getting my source, and coding away. Then the trouble started :)

Symptoms

It seems that I couldn’t  start any Android Virtual Device (AVD). I made a new run configuration, but it didn’t start. Instead I got an error, stating:

‘Launching android’ has encountered a problem.

An internal error occurred during : “Launching android”.

Clicking “details >>” produces an extra line:

Path for project must have only one segment

And, for full disclosure, the complete log-entry included trailing this post.

Cause & Solution

It seems that this rather cryptic message means nothing more in my case than “please enter a name and project for your run configuration”. I did have a “name”, but left the “Project” field empty. Entering a value in the ‘project’ (the “AndroBlip” you see next to ‘browse’) fixed it. Sources seem to indicate that the same error is produced if you don’t enter a value in the ‘name’-field.

run configurations screenshot

Screenshot

References

  1. http://developer.android.com/sdk/installing.html
  2. https://dl-ssl.google.com/android/eclipse/
  3. http://stackoverflow.com/questions/4961151/android-path-for-project-must-have-only-one-segment

Complete error log

!ENTRY org.eclipse.core.jobs 4 2 2011-02-20 12:12:00.397
!MESSAGE An internal error occurred during: “Launching android”.
!STACK 0
java.lang.IllegalArgumentException: Path for project must have only one segment.
at org.eclipse.core.runtime.Assert.isLegal(Assert.java:63)
at org.eclipse.core.internal.resources.WorkspaceRoot
.getProject(WorkspaceRoot.java:181)
at com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate
.getProject(Unknown Source)
at com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate
.launch(Unknown Source)
at org.eclipse.debug.internal.core.LaunchConfiguration
.launch(LaunchConfiguration.java:853)
at org.eclipse.debug.internal.core.LaunchConfiguration
.launch(LaunchConfiguration.java:703)
at org.eclipse.debug.internal.ui.DebugUIPlugin
.buildAndLaunch(DebugUIPlugin.java:866)
at org.eclipse.debug.internal.ui.DebugUIPlugin$8
.run(DebugUIPlugin.java:1069)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

Google launched their Android Market on the web two days ago. What I personally like is being able to browse through my installed Android apps on my computer and find new ones to install. You can buy apps on the web and they wil automatically be installed on your phone. There is also the option of leaving a user review for an app.

Of course we immediately looked to see how AndroBlip was featured there! :-)

AndroBlip on the Android Market on the web

Hopefully, this new way of finding apps for Android will make it easier to leave comments or suggestions for our app. We hope to see some user reviews soon!

There is also an option for us to add video’s to the app description, like for example Winamp did on their Market page. Suggestions for making a (fun?) video are welcome!

Indeed, quite simple, but still.

Limiting character amount

The first goal was to limit the amount of characters someone can type in an EditText. Well, this sounds easy and it is. You can set a filter, like so:

editText.setFilters(new InputFilter[]{
         new InputFilter.LengthFilter(MAX_SIZE)
});

Limiting to a certain value

Now to implement this for the setting that stops you from asking for a million pictures to be downloaded.

To be clearer: I have a preference that lets you set the amount of pictures you can download. You should be able to write only numbers* here.. I’ve done this, more or less inelegantly, with the “android:digit” attribute in the xml:

<EditTextPreference
       android:title="Max Amount"
       android:summary="The more, the heavier. Default = 12"
       android:key="viewMax"
       android:defaultValue="12"
       android:digits="0123456789"/>

* no, we’re not entering the amount in HEX.

This works OK, but you can type in a lot of 9’s if you want. That’s no good.

Now to add another LengthFilter is only applicable for numbers  up to (10^y)-1, e.g. up to 999: a LengthFilter(3) will of course limit you to 3 characters, not to an int of max 3.

I have not found a filter for the maximum value, as the standard InputFilter gives us “ALLCAPS” and the previously used LengthFilter. I think the cleanest method might be to write an InputFilter, but it’s rather easy to fix without one, using an OnSharedPreferenceChangeListener.

Simple summary of how to limit an edittext to a certain value

We can add a lot of Listeners, that trigger on a lot of different moments, this is just an example. The moment of warning might be a bit late (after having set the value), but as a proof-of-concept:

Implement OnSharedPreferenceChangeListener

Whenever you’ve changed the preference, trigger a function to check if everything is sane. The activity implements OnSharedPreferenceChangeListener, so you can do this:

getPreferenceScreen().getSharedPreferences()
              .registerOnSharedPreferenceChangeListener(this);

The Listener

Add the listener. It will check for the set value, and correct it if it’s not sane.

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
		String key) {
  if ("yourPrefName".equals(key)) {
    String valueString = sharedPreferences.getString(key, "");
    int value = Integer.parseInt(valueString);
    if(value > MAX_VALUE){
	EditTextPreference p = (EditTextPreference) findPreference(key);
	p.setText(""+MAX_VALUE);
	Toast t = Toast.makeText(this,"Maximum amount limited to "+MAX_VALUE, Toast.LENGTH_SHORT);
	t.show();
    }else if(value < MIN_VALUE){
	EditTextPreference p = (EditTextPreference) findPreference(key);
	p.setText(""+MIN_VALUE);
	Toast t = Toast.makeText(this,"Minimum amount limited to "+MIN_VALUE, Toast.LENGTH_SHORT);
	t.show();
    }
}

This means that you CAN enter numbers that are too high or too low, but at least you’ll get a message saying you’ve failed, and the preference will remain something sane.

Bonus: a filter on an EditTextPreference

Now for a quick bonus. I was annoyed at first why you cannot simple add a filter to your EditTextPreference like you would with an EditText

yourEditTextPreference.setFilters(yourFilters);

This is because the input you’re getting for a preference actually is an EditText, and you’ve got to find it. Short story even shorter: get the EditText from the EditTextPreference. Duh :)

yourEditTextPreference.getEditText().setFilters(yourFilters);

Now I’ll see how fun it is to write a real filter. Why not?

Time to catch up on some of the android blogposts! Lets start with a simple one: this annoying bug stops you from opening the very usefull Hierarchy-viewer.

“Failed to get the adb version: Cannot run program “adb.exe”: CreateProcess error=2, The system cannot find the file specified”

There seem to be several issues here, ranging from installing all sorts of new stuff to reinstalling the SDK, but there’s one sollution that has helpt me on 2 different (windows) machines: adding the new location of the “adb.exe” to your environment path.

Step 1: locate adb.exe. It wil probably be in the platform-tools dir (that’s new I guess)

Step 2: add the location to your PATH. In windows 7:

  • Rightclick on “my computer”
  • Advanced system settings (on the left)
  • Button “Environment Variables”
  • Select “PATH” and press “Edit…”
  • Add your path, e.g. add in the end: “;c:\android\sdk\platform-tools
  • press all OK buttons.

Win!

When you have HTML and you want to show it to your users, one of the possibilities is using a WebView. Check the WebView tutorial for more info. You can also use a TextView, but the HTML has to be changed for that. You could use linkify for this. This should be enough, but when you also want (for instance) bold and italic to work, we have to do some more trickery. The first iteration we used was this:

//description is a TextView
description.setText(Html.fromHtml(desc));
description.setMovementMethod(LinkMovementMethod.getInstance());

This works amazingly well, except for this ‘minor’ detail: full links are working perfectly, but a link like this does a force close:

<a href="/dr">Link with relative path</a>

The TextView is not a browser, so it doesn’t even know what protocol we are using, let alone what domain or path we’re supposed to be in. This will result in a force close, with a log that looks like this:

ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.View data=/dr}

The intent expects something like “http://” or “mailto:” I presume, but if it gets “/dr”, there is no activity to handle the link.

Elegance aside, a simple solution is to make an absolute link if you know the correct data. This is a quick and dirty solution, but let’s share it anyway because a lot of solutions we found were specifically for linkify, not for complete “fromhtml” purposes.

/**
 * Removes relative a hrefs
 * @param spantext (from Html.fromhtml())
 * @return spanned with fixed links
 */
public Spanned correctLinkPaths (Spanned spantext) {
  Object[] spans = spantext.getSpans(0, spantext.length(), Object.class);
  for (Object span : spans) {
    int start = spantext.getSpanStart(span);
    int end = spantext.getSpanEnd(span);
    int flags = spantext.getSpanFlags(span);
    if (span instanceof URLSpan) {
      URLSpan urlSpan = (URLSpan) span;
      if (!urlSpan.getURL().startsWith("http")) {
        if (urlSpan.getURL().startsWith("/")) {
          urlSpan = new URLSpan("http://domain+path" + urlSpan.getURL());
        } else {
          urlSpan = new URLSpan("http://domain+path/" + urlSpan.getURL());
        }
      }
      ((Spannable) spantext).removeSpan(span);
      ((Spannable) spantext).setSpan(urlSpan, start, end, flags);
    }
  }
  return spantext;
}

We traverse the objects in the Spanned. If we find a URLSpan we copy the span and fix that one. Then we remove the old span, and insert the new one. The copy move might not be necessary, but as it doesn’t bother us at the moment I’ll leave it like this. This has taken up quite enough time, thankyouverymuch. If you want to do something extra, and instead of opening a browser do your own onClick magic, you can take a look at this anddev forumthread.

Finally, our assign has to look like this obviously:

//description is still a TextView
description.setText(correctLinkPaths(Html.fromHtml(desc)));
description.setMovementMethod(LinkMovementMethod.getInstance());

Another interesting link is this bugreport on code.google.com. I’d say that your browser shouldn’t know where to point itself, but apparently the project members don’t agree.

It seems that a WebView element in Android reserves some space for a vertical scrollbar by default. This shows up as a small, vertical strip of white space on the right, which is not padding or margin but some space reserved for a scrollbar.

To get rid of this you have to set the scrollbar style to display the scrollbars inside the content area. This can be done with the following code:

webview.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);