Pages

Conversion to Dalvik format failed with error 1

Usually I close/restart Eclipse to clear this error.
 
On this occasion I tried "Clean / Rebuild" and that also worked - and more quickly than an Eclipse restart.

Minimum required to get started with Google Maps

1) Obtain key for debug version of app.
The default location where the MD5 certificate is stored for the Debug version of the app:
C:\Users\<your windows user>\.android\debug.keystore


The keytool.exe is here:
C:\Program Files\Java\jdk1.6.0_14\bin


The command to get the debug certificate is:
keytool -list -alias androiddebugkey -keystore C:\Users\<your windows user>\.android\debug.keystore -storepass android -keypass android


Enter the MD5 cetificate output by the keytool command into the Google Maps signup page: http://code.google.com/android/maps-api-signup.html

2) Add the highlighted lines to AndroidManifest.xml

<application android:icon="@drawable/icon" android:label="@string/app_name">
...
<uses-library android:name="com.google.android.maps" />
...
</application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />


3) Create an Activity that extends MapActivity otherwise LogCat reports this error:

09-06 07:44:23.269: ERROR/AndroidRuntime(868): Caused by: java.lang.IllegalArgumentException: MapViews can only be created inside instances of MapActivity.


package xxx.yyy;
import android.os.Bundle;
import com.google.android.maps.MapActivity;
public class MyMapView extends MapActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mapview);
}

@Override
protected boolean isRouteDisplayed() {
return false;
}
}


4) Create a layout (mapview.xml) in this example

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<com.google.android.maps.MapView
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:apiKey="the key received from Google" />
</LinearLayout>


5) Remember to add the MyMapView activity to the project's AndroidManifest.xml

6) Using the project's Properties dialog, select Android and choose the target as Google APIs

7) Using the AVD Manager create a new AVD that targets Google APIs

Make a TextView look like an EditText

<TextView

style="@android:style/Widget.EditText"

android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>

List the InputMethods

InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.

INPUT_METHOD_SERVICE);

List<InputMethodInfo> inputMethodInfoList = inputManager.getEnabledInputMethodList();

for (InputMethodInfo i : inputMethodInfoList) {

Log.d(

"INPUT-DEBUG", i.getServiceName());

Log.d(

"INPUT-DEBUG", i.getPackageName());

Log.d(

"INPUT-DEBUG", i.getSettingsActivity());

}

Defining and Using Menus in XML

Create an .xml file in the res/menu folder, for example:

res/menu/editpreferences_menu.xml

and populate it with some menu definitions, something like this:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_done" android:title="@string/menu_done"
android:icon="@android:drawable/ic_menu_save" />
<item android:id="@+id/menu_revert" android:title="@string/menu_revert"
android:icon="@android:drawable/ic_menu_revert" />
<item android:id="@+id/menu_help" android:title="@string/menu_help"
android:icon="@android:drawable/ic_menu_help" />
</menu>

Then inflate the XML menu using the onCreateOptionsMenu in the Activity:
public class EditPreferences extends Activity {
...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.editpreferences_menu, menu);
return true;
}
}

Attaching the debugger

I've spent months tediously closing my app, setting my breakpoints and then relaunching with the debugger.
 
There is an easier way.
 
From the Devices view (in the Debug perspective) highlight your process and click the "debug" button (it looks like a green bug on the Devices titlebar).
 
Much better.

Service Permissions

This didn't work:

<service android:name=".MyInputService" android:permission="android.permission.BIND_INPUT_METHOD>
</service>

and gave this runtime error:
Permission Denial: Accessing service ComponentInfo{com.powerplain/com.powerplain.MyInputService} requires android.permission.BIND_INPUT_METHOD

whereas this technique did work:
<service android:name=".MyInputService">
</service>
<uses-permission android:name="android.permission.BIND_INPUT_METHOD" />

Android Source Code

This is a link to a ZIP of just the Android bit of the source code tree.
 
 
and is only 3mb

Landscape Values

I haven't tried this myself yet but....
 
In one of the sample projects they have a values-land folder in which there is a dimens.xml file. So I'm assuming that I can move the specific dimensions out into that folder where they'll be picked up automagically in landscape mode.
 
At the moment I use things like "amount_width_portrait" and "amount_width_landscape" then modify the layout-land to suit.
I wonder if the same applies to drawables-land and menus-land?

Cursor Error

The consequence of not closing the SQLite Cursor once I had finished with it:
 
08-31 07:21:03.372: INFO/dalvikvm(467): Ljava/lang/IllegalStateException;: Finalizing cursor android.database.sqlite.SQLiteCursor@43150358 on null that has not been deactivated or closed
08-31 07:21:03.372: INFO/dalvikvm(467): at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:596)
08-31 07:21:03.372: INFO/dalvikvm(467): at dalvik.system.NativeStart.run(Native Method)

G1 Upgrade to 1.5

I found this on a blog (somewhere). It worked perfectly for me, although the 43mb download took quite a long time - 2 hours or so.

Here is how to do it if you do the same thing I did.

  1. First, have AnyCut installed if you don't already
  2. Next, Create a new shortcut on your phone's desktop. Select "AnyCut" and then select "Activity"
  3. Select "Device Info" as your activity. I can't find any other way to get to this activity on the phone
  4. Press the new shortcut icon you have created.
  5. Scroll to the bottom and find the "Check for Updates" button. Click it. You may have to a few times for it to succeed.
  6. Once the "checkin" has succeeded, exit back to your home screen and you will be prompted to install the update.

Simple Custom Control Template

Class
 
public class Xxxxxx extends LinearLayout {
   public Xxxxxx(Context context, AttributeSet attrs) {
      super(context, attrs);
      LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      inflater.inflate(R.layout.zzzzzzz, this);
   }
}
 
Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="
http://schemas.android.com/apk/res/android"
   android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content">
   <!-- Put your controls here -->
</LinearLayout>
 
Consumer
 
<packagename.Xxxxxx android:id="@+id/Xxxxxx01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
 
 

AsyncTask

This is what I ended up with. I've stripped the uninteresting code in the interests of clarity.
 
public void fillData() {
   new LoadDataTask().execute(this, transactionSortOrder, dateFilter);
}

private class LoadDataTask extends AsyncTask<Object, Integer, ArrayList<SeauTransaction>> {

   @Override
   protected ArrayList<SeauTransaction> doInBackground(Object... params) {
      this.activity = (Activity) params[0];
      return getData(activity, transactionSortOrder, dateFilter);
   }

   protected void onPostExecute(ArrayList<SeauTransaction> result) {
      fillAdapter(activity, result);
   }

}

private ArrayList<SeauTransaction> getData(Context activity, TransactionSortOrder transactionSortOrder,
   AbstractDateFilter dateFilter) {

   return dbAdapter.getSeauTransactionList(transactionSortOrder, dateFilter);
}

private void fillAdapter(Activity activity, ArrayList<SeauTransaction> seauTransactionList) {

   transactionAdapter = new SeauTransactionAdapter(activity, seauTransactionList);
   setListAdapter(transactionAdapter);
}


Defining Sub-Menus in XML

The XML structure for Menus and Sub-Menus is:
 
<xml ...>
<menu ....>
<item title="menu header 1" ...
<menu ...
<item title="sub menu item1" ...
<item title="sub menu item2" ...
<item title="sub menu item3" ...
</menu>
</item>
</menu>

BitmapDrawable

I sense that they stayed up late late into the night to devise something that is so tricky to use.
 
I've been drawing lines and couldn't work out why they were so "fat". Eventually I realized that they are affected by Gravity.
 
I also struggled with trying to draw more than one line on a bitmap and in different colours. The only saving grace is the canvas.drawLines method which at least allows a series of lines to be drawn on a single bitmap (but only in a single colour).
 
I've ended it up with something like this:
 
BitmapDrawable baseLine = new BitmapDrawable(Bitmap.createBitmap(300, 6, Bitmap.Config.ALPHA_8));
baseLine.setGravity(Gravity.BOTTOM | Gravity.LEFT);
 
float[] points = {
/* base */0, 3, lineEnd, 3,
/* starttick */0, 1, 0, 5,
/* endtick */lineEnd, 1, lineEnd, 5 };
 
baseLineCanvas.drawLines(points, baseLinePaint);

Empty ListView

When a ListView has no items it is possible to display a default View e.g. some explanatory text about why there is nothing to be seen.
 
The simplest way to do this is with a TextView called id/android:empty like this:
 
<ListView android:id="@+id/android:list" ></ListView>
<TextView android:text="blah blah blah" android:id="@+id/android:empty" ></TextView>
 
You can also set the empty view in code which gives you some more flexibility:
 
public void onCreate(Bundle savedInstanceState) {
Log.d(getClass().getSimpleName(), "onCreate");
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.buckets_list);
getListView().setEmptyView(findViewById(R.id.EmptyBucketLayout));
 
R.id.EmptyBucketLayout can then refer to a more complex viewgroup LinearLayout / TextView / Button type of idea:
 
<ListView android:id="@+id/android:list"></ListView>
  <LinearLayout android:id="@+id/EmptyBucketLayout">
    <TextView android:text="@string/welcome_heading"></TextView>
    <TextView android:text="@string/welcome_text"></TextView>
    <Button android:text="Create Bucket"></Button>
  </LinearLayout>
 
What I could not get to work (and I found someone else with the same problem) is inflating an abitrary view and using it in the setEmptyView method:
 
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View emptyView = inflater.inflate(R.layout.buckets_list_empty, null);
getListView().setEmptyView(emptyView);
 

Handy ListView attribute

To fill a list from the bottom use this attribute:
 
android:stackFromBottom="true"
 
but you also need to set it to fill_parent
 
android:layout_height="fill_parent"
 
 

Aligning LinearLayout

I wanted to center the numeric keypad and remove the hardcoded "padding".
 
But using just

android:layout_centerHorizontal

="true"
wasn't sufficient because the width was set to "fill_parent". The width needs to be changed to "wrap_content" to give the parent enough horizontal room to do the alignment of the linearlayout.
 
 

Removing hard coded dimensions


You can specify a XML file in the res\values folder called dimensions.xml (the name is abitrary)
 
<?xml version="1.0" encoding="utf-8"?>

<

resources>

<dimen name="numkey_width">60px</dimen>

<dimen name="numkey_height">40px</dimen>

<dimen name="numkey_margin">1px</dimen>

</

resources>
 
You can then refer to the dimensions in the layout XML like this:
 
android:layout_width="@dimen/numkey_width"
android:layout_height="@dimen/numkey_height"
android:layout_marginTop="@dimen/numkey_margin"
android:layout_marginLeft="@dimen/numkey_margin"

 

 


RelativeLayout

<relativelayout width=fill_parent height=fill_parent>       <--------------------------This replaces the normal LinearLayout we use to top and tail our Activity Views
<linearlayout id=amountLayout android:layout_alignParentTop="true" >
<linearlayout id=numberLayout  android:layout_alignParentBottom="true"  >
<linearlayout 
      android:layout_below="@id/amountLayout"
      android:layout_above="@id/numberLayout"
      >
      <listview ........./>
 
 
The documentation says:
"For the sake of efficiency, the relations between views are evaluated in one pass, so if view Y is dependent on the position of view X, make sure the view X comes first in the layout."
 
 
So I layout out the top & bottom fixed elements then place the scrolling list in between them.

Soft Numeric Keyboard

I found that if you set the InputType property to:
 
Input type numberSigned|numberDecimal
 
it will popup the keyboard when that field takes the focus.
 
Also, you can create a string resource of characters that can be input into the Digits property
 
in strings.xml:
<string name="acceptableNumerics">0123456789-.</string>
 
in the layout:
<EditText ....android:digits="@string/acceptableNumerics"  ... />

onLocationChanged event fires only one in the Emulator

It seems that several people are experiencing the same problem as me with the onLocationChanged event firing one time only.
 
The last post I saw on this was 1.5_r3 31st July

GPS GeoLocation Navigation Information

Traditionally positions are given using degrees, minutes, and seconds of angles in two measurements:
  1. latitude, the angle north or south of the equator
  2. longitude, the angle east or west of the Prime Meridian aka  International Date Line
  
A Minute of angle is one sixtieth of one Degree and equals about 1.86 km or 1.15 miles
A Second of angle is one sixtieth of one Minute and equals about 30 meters or 100 feet
When Selective Availability is turned off accuracy is within 150 feet
Differential GPS is accurate to within 2 metres.
Which makes me think we need to record locations to within 2/30th of a second.
The Android can report position in three different formats:
  
FORMAT_DEGREES Constant used to specify formatting of a latitude or longitude in the form "[+-]DDD.DDDDD where D indicates degrees. However the references I see are to 6dp.
  
FORMAT_MINUTES Constant used to specify formatting of a latitude or longitude in the form "[+-]DDD:MM.MMMMM" where D indicates degrees and M indicates minutes of arc (1 minute = 1/60th of a degree).
  
FORMAT_SECONDS Constant used to specify formatting of a latitude or longitude in the form "DDD:MM:SS.SSSSS" where D indicates degrees, M indicates minutes of arc, and S indicates seconds of arc (1 minute = 1/60th of a degree, 1 second = 1/3600th of a degree).
  
  
1 degree = 1.000000
1 minute  = 0.016667
1 second = 0.000278
2/30th second = 0.000019

Emulator Telnet

telnet localhost 5554
 
Android Console: type 'help' for a list of commands
OK
help
Android console command help:
    help|h|?         print a list of commands
    event            simulate hardware events
    geo              Geo-location commands
    gsm              GSM related commands
    kill             kill the emulator instance
    network          manage network settings
    power            power related commands
    quit|exit        quit control session
    redir            manage port redirections
    sms              SMS related commands
    avd              manager virtual device state
    window           manage emulator window

try 'help <command>' for command-specific help

I used window scale .6 to make the emulator window roughly the size of a real phone.

NinePatch Images

Any of the existing image files in \res\drawable that are named  xxxxx.9.png  are ninepatch images.
 
Four small things that caught me out:
1) you can't have two images with the same root name e.g. abc.png and abc.9.png
2) when you reference them in Java the .9 element is not present (related to issue 1) e.g.  R.drawable.abc would automatically reference the abc.9.png image
3) The border has to be white with the "stretchable" elements in black 
4) When you change the content of an image you have to hit F5 to refresh the \res folder - even though the filename hadn't changed - in order for the new content to appear in the application.
 
Finally, don't bother looking at the nine-patch images in the XML Editor in Layout mode - they don't stretch properly.


NinePatch Resources
NinePatch Tools

Focusable View inside ListView item won't be clickable

I found this useful snippet on a forum:
 
Romain Guy
Date: Mon, 10 Nov 2008 08:34:23 -0800
Subject: Re: [android-developers] no callback to onItemClick() on clicking my ListView
 
If you put a focusable View inside a list item, then the list item
will not be clickable. You would have to set a click listener on the
button for instance.

Leaking Services is scary easy

An interesting thread about apps that leak services:

Checkboxes on Icon Menus

Note: Menu items in the Icon Menu cannot display a checkbox or radio button. If you choose to make items in the Icon Menu checkable, then you must personally indicate the state by swapping the icon and/or text each time the state changes between on and off.