Friday, December 24, 2010

Finding Android screen orientation

There are multiple way to get Android screen orientation (landscape/portrait), however some of them are problematic:
this.getWindowManager().getDefaultDisplay().getOrientation()
Is depricated

this.getWindowManager().getDefaultDisplay().getRotation()
Works only from Android 2.2

I Found this to be the best resource until now, since it's exists since API 1 & it's not deprecated, yet:
this.getResources().getConfiguration().orientation

Compare it with:
Configuration.ORIENTATION_LANDSCAPE
Configuration.ORIENTATION_PORTRAIT
Configuration.ORIENTATION_SQUARE

Tuesday, December 14, 2010

Spinner.setSelection doesn't work correctly

Problem:
There are a lot of posts around regarding a problem with Spinner.setSelection(i) function. I encountered this issue when I've tried to replace the adapter in the Spinner and select a new item. The setSelection function seems like it's not working, but when I click the spinner the selected item was the correct one.

Solution:
Use Spinner.setSelection(i, true) instead

Wednesday, December 8, 2010

Multiple substitutions specified in non-positional format

Since Android SDK 2.3 there's a new error:
error: Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?

Description:
This error indicates you're using a string resource with %s in it. See how to use it here under 'Formatting strings'. In general, instead of:
Hello, %s! You have %d new messages.
Should be:
Hello, %1$s! You have %2$d new messages.

Tuesday, December 7, 2010

Can not find adb.exe after Android SDK update

After updating the Android SDK I got the following message when I opened Eclipse:
Can not find C:\Program Files\Google\Android SDK\tools\adb.exe
Please check the Android plugin's preferences

And when I checked the adb.exe was really missing!

Solution:
Update the Android add-ins for Eclipse, in Eclipse: "Help" -> "Check for Updates".

The reason for this error (in my case) was that since SDK 2.3 the 'adb.exe' was moved to:
C:\Program Files\Google\Android SDK\platform-tools\adb.exe

UPDATE: ddms.bat does not work as well (can not find adb.exe). The work-around I'm using until I'll find a better solution is adding the platform-tools folder to the environment PATH variable.

Friday, November 26, 2010

AdMob as shows in Landscape but not in Portrait

This was really weird. I added AdMob Ad to an Android application, and it didn't show. I tried rotating to landscape & the ad appeared.

Solution: I found the solution here - the AdMob ad must not be padded, or be in a padded container.

Monday, November 8, 2010

Android application installation stuck on "Downloading"/"Installation"

Problem: Application installation hangs/stuck on "downloading" or "installing" from the Market. Reboot does not help.

Solution: Clearing the Android Market application cache -
* Menu => Settings => Applications => Manage Applications => "All" tab => Market
* Click on "Clear cache" (you might get 'Force Close' on the Market application after that).
* Reopen the market & download

Note: This is an issue with the Android Market application not the application you're downloading.

Thursday, October 14, 2010

Attachment disappears after e-mail sent programatically

I banged my head in the wall for about an hour to fix this issue.

I wrote a small function in Android that let the user send an e-mail from my application. Everything worked just fine, but when the e-mail was sent the attachment disappeared (the attachment appeared within the GMail client on the android device before sending).

Solution: use the external storage (SD Card) instead of the application cache. The GMail client probably can't access the application cache folder, buf for some reason it shows as if the attachment is OK in the client).

Tuesday, October 12, 2010

Android's ListView performance for large list

I needed to use a large ListView however the performance of the ListView loading time was very poor. Since I've used SimpleAdapter to map the data to the layout I was forced to populate all the data when creating the SimpleAdapter.

The solution I've decided to take is creating an adapter specific for the task, which populate the data from the objects only during creation of the item's view.

This is the pseudo code (note that the object data retrieval should by lazy too):

public class MyObjectAdapter extends BaseAdapter {
private ArrayList mData;
private int mResource;
private LayoutInflater mInflater;

public TimeZoneDisplayAdapter(Context context, ArrayList data,
int resource) {
mData = data;
mResource = resource;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public int getCount() {
return mData.size();
}

@Override
public Object getItem(int position) {
return mData.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView == null)
v = mInflater.inflate(mResource, parent, false);
else
v = convertView;

bindView(position, v);
return v;
}

private void bindView(int position, View view) {
MyObject o = mData.get(position);

((TextView)view.findViewById(R.id.list_item_resource_id)).setText(o.getData1());
......
......
......
}
}

Note: there are few examples online how to load data to ListView using threads. This wasn't my problem, and it's like killing a fly with a sledge-hammer. The loading time of a specific item was very short, the problem was that there were simply too many items to load at construction time.

Friday, October 8, 2010

Making TextView clickable (http)

The problem: I had a TextView which I wanted to make clickable, and open a web browser.

1. Brute force solution: change the TextView style to blue & underline. Set the onClick event to open web browser.

2. The following code:

SpannableString s = SpannableString.valueOf(entryText);
URLSpan span = new URLSpan(urlText);
s.setSpan(span, 0, entryText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mTextView.setText(s);
mTextView.setMovementMethod(LinkMovementMethod.getInstance());

Monday, August 23, 2010

AlertDialog with single selection & no radio button

Current Android version AlertDialog.Builder default behavior of "setSingleChoiceItems" creates a list with radio buttons from which you can select.

I wanted to get this list without the radio button. After digging a bit in AlertDialog.Builder & AlertController.AlertParams I found the solution: instead of using setSingleChoiceItems use setAdapter.


ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.select_dialog_item, itemActionsList);
dialog.setAdapter(adapter,
new OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// Do something
arg0.dismiss();
}
});

Android hangs: "Waiting For Debugger"

I developed an application that worked just fine, and then it started to hang with the message: "Waiting For Debugger". Even when I disconnected the device from the computer the application insisted that it's waiting for the debugger...

Solution:
1. Restart Eclipse [it's probably not needed].
2. Restart the Android device.

Friday, August 20, 2010

Android requires .class compatibility set to 5.0. Please fix project properties.

I've created a new workspace in Eclipse & imported an Android project.

* Issue #1:
Android requires .class compatibility set to 5.0. Please fix project properties.

* Solution:
1. Fix project:
Package Explorer ->
Right click the project ->
"Android Tools" -> "Fix Project Properties"
2. Restart Eclipse:
"File" -> "Restart"

* Issue #2: The following error appears many times
The method xyz() of type ABC must override a superclass method

* Solution:
1. Fix the project again:
Package Explorer ->
Right click the project ->
"Properties" -> "Java Compiler" -> "Compiler Compliance Level" = 1.6

Monday, August 16, 2010

DataView RowFilter performance

I needed to use DataView but the performance I got was very poor. Searching the web I found this resource which explains the root cause for this issue: after each RowFilter the DataView is re-indexed.

Searching a bit more yield the answer from Microsoft: don't use RowFilter if you don't have to. Use FindRows.

For my scenario, using FindRows instead of Row filter resulted in at least factor of 6 improvement (i.e. 1 second instead of 6).

Thursday, August 12, 2010

Eclipse hangs during building Android projects workspace

Problem: Eclipse kept on hanging during auto-building Android projects.
I found a resource which said (escalating solutions):
1. Clean the projects.
2. Create a new workspace & import all projects.
3. Reinstall Eclipse

After trying 1 & 2, I found the following weird solution:
- Remove the auto-build (Project => Build Automatically). Kill the Eclipse (since it hangs...)
- Restart Eclipse.
- Delete the 'gen' folder of all the projects (using the Package Explorer)
- Project => Clean (clean all projects)
- Build the projects

Don't know why it worked (at least until now).

Android/Eclipse: Project 'MyProject' is missing required source folder: 'gen'

I'm having lots of problems with my Eclipse (when I'll solve them I'll write about it).

Anyhow, after creating a new project in a new workspace I get the following error:
Project 'MyProject' is missing required source folder: 'gen'
After building the project there's a second error:
The project cannot be built until build path errors are resolved

A temporary solution: in the Package Explorer delete gen folder. Rebuilding the project again will fix the problem. Why it's temporary? you'll have to do it with every new project.

Thursday, August 5, 2010

Starting android calculator programmatically

Here goes:

public static final String CALCULATOR_PACKAGE =
"com.android.calculator2";
public static final String CALCULATOR_CLASS =
"com.android.calculator2.Calculator";

public static void OpenCalculator(Context context) {
Intent i = new Intent();
i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);

i.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
i.setComponent(new ComponentName(
CALCULATOR_PACKAGE,
CALCULATOR_CLASS));
context.startActivity(i);
}

Saturday, July 31, 2010

Colors in AlertDialog

I wanted to use colors in AlertDialog and I found this post. It work great although the solution there is not full (there are features of AlertDialog that will not work). One issue with that post - the code & XML there can not be easily copied.

Here's that code again, with some changes/improvements:
* Renamed the class name to ColorAlertDialog
* ColorAlertDialog.Builder does not inherits AlertDialog.Builder. This caused some confusion (you could call function but they didn't do anything).
* Added functionality to ColorAlertDialog.Builder
* Fixed force-close on Android 1.5

Class (I've renamed the class):

import java.util.ArrayList;
import java.util.Iterator;

import android.app.AlertDialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;

public class ColorAlertDialog extends AlertDialog {
private static int NONE = -1;
private int tint = NONE;

/**
* @param context
* @param theme
*/
protected ColorAlertDialog(Context context) {
super(context);
init();
}

/**
* @param context
* @param theme
*/
protected ColorAlertDialog(Context context, int theme) {
super(context, theme);
init();
}

/**
*
*/
private void init() {
final Theme theme = getContext().getTheme();
final TypedArray attrs = theme.obtainStyledAttributes(new int[] { android.R.attr.tint });
tint = attrs.getColor(0, NONE);
}

/* (non-Javadoc)
* @see android.app.Dialog#show()
*/
@Override
public void show() {
super.show();
setTint(tint);
}

/**
* @param tint
*/
public void setTint(int tint) {
this.tint = tint;

if ( tint != NONE ) {
Iterator vi = iterator(android.R.id.content);
while ( vi.hasNext() ) {
tintView(vi.next(), tint);
}
}
}

/**
* Set the {@link tint} color for the {@link View}
*
* @param v the {@link View} to change the tint
* @param tint color tint
*/
private static void tintView(final View v, final int tint) {
if ( v != null ) {
final Mode mode = Mode.SRC_ATOP;
if ( v instanceof ImageView ) {
final Drawable d = ((ImageView)v).getDrawable();
if ( d != null ) {
try {
d.mutate().setColorFilter(tint, mode);
} catch (Exception ex) {
// Patch for Android 1.5
}
}
}
else {
final Drawable d = v.getBackground();
if ( d != null ) {
d.setColorFilter(tint, mode);
}
}
}
}

/**
* @param button
*/
public void setCancelButton(Button button) {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cancel();
}
});
}

/**
* @param button
*/
public void setPositiveButton(Button button) {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}

/**
* Return a {@link ChildrenIterator} starting at the {@link ViewGroup}
* identified by the specified resource id.
*
* @param res resource id of the {@link ViewGroup} to start the iteration
* @return iterator
*/
public Iterator iterator(int res) {
final ViewGroup vg = (ViewGroup)findViewById(res);
return new ChildrenIterator(vg);
}

public static class Builder {
private ColorAlertDialog dialog;

public Builder(Context context) {
dialog = new ColorAlertDialog(context);
}

public Builder(Context context, int theme) {
dialog = new ColorAlertDialog(context, theme);
}

public ColorAlertDialog create() {
return dialog;
}

public Builder setMessage(CharSequence message) {
dialog.setMessage(message);
return this;
}

public Builder setTitle(CharSequence title) {
dialog.setTitle(title);
return this;
}

public Builder setPositiveButton(int resId, OnClickListener listener) {
return setPositiveButton(dialog.getContext().getString(resId), listener);
}

public Builder setPositiveButton(CharSequence text, OnClickListener listener) {
dialog.setButton(BUTTON_POSITIVE, text, listener);
return this;
}

public Builder setNegativeButton(int resId, OnClickListener listener) {
return setNegativeButton(dialog.getContext().getString(resId), listener);
}

public Builder setNegativeButton(CharSequence text, OnClickListener listener) {
dialog.setButton(BUTTON_NEGATIVE, text, listener);
return this;
}

public Builder setIcon(int iconId) {
dialog.setIcon(iconId);
return this;
}

public Builder setCancelable(boolean flag) {
dialog.setCancelable(flag);
return this;
}

public ColorAlertDialog show() {
dialog.show();
return dialog;
}
}

public class ChildrenIterator implements Iterator {
ArrayList list;
private int i;

public ChildrenIterator(ViewGroup vg) {
super();

if ( vg == null )
throw new RuntimeException("ChildrenIterator needs a ViewGroup != null to find its children");

init();
findChildrenAndAddToList(vg, list);
}

private void init() {
list = new ArrayList();
i = 0;
}

@Override
public boolean hasNext() {
return ( i < list.size() );
}

@Override
public V next() {
return list.get(i++);
}

@Override
public void remove() {
list.remove(i);
}

@SuppressWarnings("unchecked")
private void findChildrenAndAddToList(final ViewGroup root, final ArrayList list) {
for (int i=0; i < root.getChildCount(); i++) {
V v = (V)root.getChildAt(i);
list.add(v);
if ( v instanceof ViewGroup )
findChildrenAndAddToList((ViewGroup)v, list);

}
}
}
}


And the styles (put in an XML file under the 'res/values' folder):











#88FF0000
#880000FF
#88FFFF00
#88995f86
#aaffbf00
#88ff33cc
#0000

Sunday, July 25, 2010

Notes on Android SQLite bulk insert

There's no real bulk insert in SQLite I'm aware of to date. I've tried various ways to insert data fast into Android's SQLite DB, and here are my notes:
1. Use transactions. (e.g. db.beginTransaction, etc..).
2. Use compiled statement: db.compileStatement(insertStatementString), it's much faster than db.insert().

So, in short:

db.beginTransaction();
try {
string sql = "insert into products (id) values (?)";
SQLiteStatement insert = db.compileStatement(sql);

for (.....) {
insert.bindLong(1, 12345);
insert.executeInsert();
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

Tuesday, July 20, 2010

ASP.NET error: Object Expected / ScriptResource.axd

What this error means in plain English: JavaScript error.

The following case is how I solved a specific error in ASP.NET. It might give you ideas how to solve similar issues of ("Object Expected" with ScriptResource.axd). The easiest way to solve it is to use Firefox & firebug to trace down the specific JavaScript line which cause the problem.

In the scenario bellow a resource (JavaScript) could not be loaded by the browser because the clock on the computer was set back in time. This caused this problem in another JavaScript (missing definition) which caused the error message to pop-up.

Step by step how I traced down the problem:
1. When running an ASP.NET site with Menu item I got the "Object expected" error with the following information: "ScriptResource.axd". When I clicked the detailed information it gave me the URL of the resource which cause the problem.

Bottom line:
*
This error is a result of an unspecified JavaScript Error which accrued during running of a JavaScript file embedded in an ASP.NET project.
* Verify you can open the JavaScript URL using the browser.
* Debug the page using Firebug (on Firefox), see (2)

2. When opening the page in Firefox with Firebug and setting the Firebug "console" to "enabled" (with "Show JavaScript errors") it caught the following exception:
"WebForm_GetElementByTagName is not defined"

The function "WebForm_GetElementByTagName" is declared in an embedded resource called: "WebForms.js", which is in many cases the first Java script included in an HTML generated by an ASP.NET page.

Searching about this error online yielded only the following result:
http://forums.asp.net/p/1439101/3253854.aspx

Buttom line:
* Try to open in the browser each and every JavaScript include files (.AXD) in the page.

3. The error I got when I've tried to open the first ".AXD" JavaScript include file was - Parameter: "utmDate" out of range/out of date - which basically pointed me to check the computer date, since I've taken it back in time.

Setting the date forward again fixed my problem.

Sunday, July 18, 2010

Combo box / Drop down list box in Android

As usual doing something simple in Android is frustrating - this time: a simple Combo (or DropDownList). The little and important tweak - calling "setDropDownViewResource" to set the style of the items in the dialog box.

XML:
<spinner id="@+id/spinner" layout_width="wrap_content" android:layout_height="wrap_content" />

Code to add the data:

Spinner spinner = (Spinner)this.findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_spinner_item,
new String[] { "1", "2", "3" });
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);


A common task is to populate a spinner using a string array defined in a resource file. Here's a function which do just that:

public static void populateSpinnerWithArray(Spinner spinner, int stringArrayResId) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
spinner.getContext(),
android.R.layout.simple_spinner_item,
spinner.getContext().getResources().getStringArray(stringArrayResId));
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}

App crash when setting layout_weight without layout_width

While playing with the layout on Android I encountered the following weird problem: when using "android:layout_weight" attribute for an element without "android:layout_width" attribute it works just fine in the emulator but on the real phone it crash (Nexus One, Android 2.2).

Since using "android:layout_width" gives me unwanted results I've tried to work around this issue and found the following solution:
android:layout_width="0dip"

Thursday, July 8, 2010

Displaying a simple message box in Android

There are 2 options to display a pop-up in Android (both are not blocking):
Toast - display a short balloon pop-up that will disappear after few seconds
AlertDialog - display a pop-up window with buttons.

Toast:

Toast.makeText(this, "Hello World", Toast.LENGTH_SHORT).show();


AlertDialog:

AlertDialog ad = new AlertDialog.Builder(this).create();
ad.setCancelable(false); // This blocks the 'BACK' button
ad.setMessage("Hello World");
ad.setButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
ad.show();


Note: it's better to use "this.getString(R.string.ok)" and get the string from a resource file.

Sunday, July 4, 2010

Android Debug.startMethodTracing() failed

With the following exception: "file open failed".

Reason: No SD card write permission was given to the application (Android 1.6+)
Solution: Make sure you add the permission to the Manifest file -

Friday, July 2, 2010

Setting Android volume programmatically to maximum

I searched a bit how to the volume of an Android application to maximum, and I saw few post regarding people asking about MediaPlayer.setValue function.

It's not the right function for setting the volume (see the help).
To set the volume to maximum (or any relative value):

// Get the AudioManager
AudioManager audioManager =
(AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
// Set the volume of played media to maximum.
audioManager.setStreamVolume (
AudioManager.STREAM_MUSIC,
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
0);

Tuesday, June 22, 2010

Polishing Android application

Before deployment of an Android application there are few common steps that you should consider to ensure the application has a professional look:
  1. Add an EULA - See here how.
  2. Set the correct sound control - Android has multiple sound controls (alarm volume, sound volume, phone volume etc.). You should me sure that when the user click on the volume buttons the correct volume is set (See here how). For example, to set the volume button to control the media volume:
    this.setVolumeControlStream(AudioManager.STREAM_MUSIC);

  3. Disable buttons that are not in use - Except the "Home" buttons, all other buttons can be disabled by overriding "onKeyDown" function.

  4. Hide the window title bar & the Android status bar - To hide the status bar:
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
    To hide the window title:
    requestWindowFeature(Window.FEATURE_NO_TITLE);

Monday, June 21, 2010

Android app requires un-needed permissions

After finishing writing Android app, during installation the application request permissions for:
* Storage
* Phone calls

However those permissions are not requested in the AndroidManifest.

Solution:
This is a backward compatibility issue with Android 1.5 or less. Just add: android:targetSdkVersion="4" to the uses-sdk tag, for example:

(you must compile the application with platform SDK 1.6 or later).

Wednesday, June 16, 2010

Project wouldn't run after importing to Eclipse

With the following error message:
"The selection cannot be launched, and there are no recent launches"

I got it for my Android project, but it's not limited to android.
Since I'm newbie to Eclipse I started to googling but I couldn't find a solution. Playing with the UI got me to the right place:

In the main menu: "Run" -> "Run configurations..."
Double click the project type you want (in my case "Android Application") & select the project you want to run.

Thursday, June 3, 2010

How to delete VPN or Dail-up connection in Windows 7

It took me a while to find out how to delete a VPN connection I've setup on Windows 7.

So here's how:
1. Click on the connection icon in the icon tray (right-bottom side of the screen)
2. Click on "Open Network and Sharing Center" (you can open it also from the Control Panel)
3. On the left side of the window, click on "Change adapter settings"
4. Delete the VPN/Dail-up

Wednesday, June 2, 2010

SharePoint web part deployment error: Object reference not set to an instance of an object error

After deploying a SharePoint web-part developed using VSeWSS I get:
"Object reference not set to an instance of an object error"

Solution: copy the web part DLL to the GAC (it's also possible to register the DLL to the GAC on the batch file 'setup.bat' created by VSeWSS by calling gacutil.exe).

Monday, May 31, 2010

Exception: Error executing child request for ChartImg.axd

I got this exception when I used the charts built-in to .NET 3.5. The scenario in which I got this exception was only when the charts first appeared after postback.

Solution: In the web.config file add 'POST' to the DataVisualization verbs:
The old syntax:
<add path="ChartImg.axd" verb="GET,HEAD" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
validate="false" />

The new syntax:
<add path="ChartImg.axd" verb="GET,HEAD,POST" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
validate="false" />

Tuesday, May 11, 2010

Android SDK Error: Unable to resolve target 'android-X'

There are few variants of this error message:
Unable to resolve target 'android-1'
Unable to resolve target 'android-2'
Unable to resolve target 'android-3'
Unable to resolve target 'android-4'
Unable to resolve target 'android-5'
Unable to resolve target 'android-6'
Unable to resolve target 'android-7'
Unable to resolve target 'android-8'
Unable to resolve target 'android-9'
Unable to resolve target 'android-10'
Unable to resolve target 'android-11'
Unable to resolve target 'android-12'
Unable to resolve target 'android-13'
Unable to resolve target 'android-14'
Unable to resolve target 'android-15'
Unable to resolve target 'android-16'
Unable to resolve target 'android-17'
Unable to resolve target 'android-18'
Unable to resolve target 'android-19'
Unable to resolve target 'android-20'
Unable to resolve target 'android-21'

Reason: Could not find the proper Android SDK version. If the android SDK is installed correctly the problem is that the platform SDK requested by the "default.properties" is not installed. For example:
Unable to resolve target 'android-1' - (Android 1.0) change the "default.properties"
Unable to resolve target 'android-2' - (Android 1.1) change the "default.properties"
Unable to resolve target 'android-3' - install SDK Platform Android 1.5
Unable to resolve target 'android-4' - install SDK Platform Android 1.6
Unable to resolve target 'android-5' - install SDK Platform Android 2.0
Unable to resolve target 'android-6' - install SDK Platform Android 2.0.1
Unable to resolve target 'android-7' - install SDK Platform Android 2.1
Unable to resolve target 'android-8' - install SDK Platform Android 2.2
Unable to resolve target 'android-9' - install SDK Platform Android 2.3
Unable to resolve target 'android-10' - install SDK Platform Android 2.3.3
Unable to resolve target 'android-11' - install SDK Platform Android 3.0
Unable to resolve target 'android-12' - install SDK Platform Android 3.1
Unable to resolve target 'android-13' - install SDK Platform Android 3.2
Unable to resolve target 'android-14' - install SDK Platform Android 4.0
Unable to resolve target 'android-15' - install SDK Platform Android 4.0.3
Unable to resolve target 'android-16' - install SDK Platform Android 4.1
Unable to resolve target 'android-17' - install SDK Platform Android 4.2
Unable to resolve target 'android-18' - install SDK Platform Android 4.3
Unable to resolve target 'android-19' - install SDK Platform Android 4.4
Unable to resolve target 'android-20' - (Android 4.4w) change the "default.properties"
Unable to resolve target 'android-21' - install SDK Platform Android 5.0.1

You can do this using the Android SDK Setup utility:
Option 1: Eclipse -
"Windows" \ "Android SDK and AVD Manager" \ "Available packages"

Option 2: Command line - start the "SDK Setup" here (x86):
C:\Program Files\Google\Android SDK\SDK Setup.exe
or here (x64)
C:\Program Files (x86)\Google\Android SDK\SDK Setup.exe

Sunday, April 11, 2010

GoDaddy windows hosting with WordPress Permalinks

After moving multiple domains hosted in GoDaddy to a single Delux windows account I found out that the WordPress permalinks (e.g. SEO nice URL) aren't working anymore.

There are multiple discussions online regarding this problem, mostly regarding redirecting the 404 error page. However the solution is SUPER simple - RTFM (the following answer appears in the WordPress permalink setting page): add a file "web.config" containing the following lines

<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Saturday, April 10, 2010

Twitter statistics: Avg. number of follower by time zone

About a week ago I saw this post on TechCrunch and I wondered what other irrelevant statistics I can find on Twitter (given the fact I've already put some time in collecting and parsing Twitter data).

Here is the number of followers by time zone settings (removed time zones with less than 10,000 users, sorry Sydney).

Minimal analysis:
  • Greenland - More people set their time zone to Greenland than the population there...
  • Alska - Over 6% (!) of the population are tweeting [see also - 'Greenland'].
  • Tokyo - Don't set your time zone to Tokyo if you want people to listen to you, lot's of people are tweeting from Tokyo but no one listens.
  • No Time Zone - There's a very low followers count for people with no time zone setting - I guess the reason is that those people are new to Twitter or just don't care enough (those people are about 20% of this entire sample).



Data collected from the Twitter Sampling API, March 21st-25th, 2010.
Total number of users visible during that time frame: 2.5M (which is a very nice sample).

Saturday, March 27, 2010

Parsing Twitter JSON: Comparing C# libraries performance

Twitter stream API return the data in JSON format. There are multiple JSON libraries in C#, however since I wanted to parse large volumes of data I did a short performance test to see which library gives the best performance in parsing Twitter JSON data.

The libraries tested:
* Json.NET - A popular C# JSON library.
* Gapi.NET - Gapi.NET is not a JSON parsing library, but it contains JSON parsing routines.
* Procurios - Yet another C# JSON library. See also this blog post how to use it to parse Twiter data.
* JavaScriptSerializer - .NET 3.5 built-in JSON parser.
* DataContractJsonSerializer - .NET 3.5 built-in JSON parser.
* AjaxPro - A C# AJAX library.

Results:
Parsing Twitter JSON: Comparing C# libraries performance

The test:
* Data: Twitter Stream API sampling interface data for one hour (2PM GMT) during Match 24th 2010. File size is 285Mb, contains 208,530 lines, one JSON object per line.
* Computer: HP Pavillion DV6000, Intel T9300 2.5GHz, 4GB Memory running Windows 7 x64
* Software: with each library I've performed a very simple test - parse all the messages & get the 'text' field data of every message, if it exists (see code below).

Results:
* Json.NET - 12 seconds, no errors.
* Gapi.NET - 10 seconds, no errors.
* Procurios - 35 seconds, 207 errors.
* JavaScriptSerializer - 77 seconds, no errors.
* DataContractJsonSerializer - 24 seconds, 7452 errors (all the JSON objects that did not contain 'text' element).
* AjaxPro - 16 seconds, no errors.

Code:
Here's the code used for parsing a single line in each of the libraries. Variable line contains a JSON object, the extracted tweet is stored in the variable text.

Json.NET parsing code

Dictionary jsonObjects = new Dictionary();
StringReader lineReader = new StringReader(line);
using (Newtonsoft.Json.JsonTextReader jsonReader =
new Newtonsoft.Json.JsonTextReader(lineReader))
{
while (jsonReader.Read())
{
if ((jsonReader.ValueType != null) && (jsonReader.Depth == 1))
{
string key = jsonReader.Value.ToString();
jsonReader.Read();
jsonObjects.Add(key, jsonReader.Value);
}
}
}

object textObject;
if (jsonObjects.TryGetValue("text", out textObject) == true)
text = textObject.ToString();


Gapi.NET parsing code

Gapi.Json.JsonObject jsonLine = Gapi.Json.JsonObject.Parse(line);
Gapi.Json.JsonValue textValue;
if (jsonLine.TryGetValue("text", out textValue) == true)
text = textValue.ToString();


Procurios parsing code

Hashtable jsonHash = (Hashtable)Procurios.Public.JSON.JsonDecode(line);
text = jsonHash["text"] as string;


JavaScriptSerializer

public class TwitterJsonObject
{
public string text;
}


JavaScriptSerializer jSerialize = new JavaScriptSerializer();
TwitterJsonObject twitterJsonObject = jSerialize.Deserialize<twitterjsonobject>(line);
text = twitterJsonObject.text;



DataContractJsonSerializer

// This line is executed once
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TwitterJsonObject));

// This code is executed for every JSON object
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(line));
TwitterJsonObject twitterJsonObject = ser.ReadObject(ms) as TwitterJsonObject;
text = twitterJsonObject.text;


AjaxPro

TwitterJsonObject twitterJsonObject = AjaxPro.JavaScriptDeserializer.DeserializeFromJson(line, typeof(TwitterJsonObject)) as TwitterJsonObject;
text = twitterJsonObject.text;

Thursday, March 25, 2010

DoDragDrop prevents DoubleClick event from firing

I've tried implementing Drag & Drop in a ListView object, however, calling DoDragDrop from either MouseMove or MouseDown prevented DoubleClick event from firing.

There are few posts online about it, mostly saying using MouseDown event and checking:
e.Clicks == 1
(see for example: here)

However this didn't work for me (DoubleClick fired some times, but most of the time it didn't). After doing further research I came with the following full solution:


bool _beginDragDrop = false;

void ListViewBase_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left)&&(_beginDragDrop == true))
{
// Replace this with the object you want to Drag & Drop
object draggedObject = this;
this.DoDragDrop(draggedObject, DragDropEffects.Copy);
}
}

void ListViewBase_MouseDown(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left) && (e.Clicks == 1))
_beginDragDrop = true;
else
_beginDragDrop = false;
}

Monday, February 22, 2010

AjaxToolkit: TabContainer not visible after setting TabPanel.Visible = false

After upgrading AjaxToolkit I had the following weird problem: a TabContainer disappeared.

A short investigation showed that it was cause because I was setting a TabPanel property
tabPanel.Visible = false

Bottom line: If you set the ActiveTab of the TabContainer to Visible=false => the TabContainer will not be drawn. I'm not sure if it's a bug or a feature.

Resolution: Change the ActiveTab when you set TabPanel.Visible = false

Wednesday, February 10, 2010

Error 2869 during installation

The problem:
Error message during installation on Windows Vista / 7:
The installer encountered an unexpected error installing this package. This may indicate a problem with the package. The error code is 2869.

Reason:
The MSI contains a custom action that require more privileges than the current user have.
Due to UAC (user access control) even if you're administrator, you're not REALLY administrator unless specifically run as such.

Resolution:
- Simple option - Install as administrator.
- If you wrote the package in Visual Studio 2005/2008 add the following to require administrator privileges to begin installation:
1. Right click on the setup project -> View -> Launch Conditions
2. In the Launch conditions window, right-click the node "Launch Conditions" and select "Add launch condition".
3. Rename the new launch condition to something like "Require Administrator".
4. In the new launch condition property window set "Condition" to "AdminUser"
5. Set the error message to something meaningful ("Only administrator can install this software").
6. Check the following post & add "NoImpersonate.js"
7. Rebuild the package.

Thursday, January 28, 2010

MAPIInitialize fails with code 0x80010106 in C#

I've tried to use MAPI in C# but MAPIInitialize keeped on failing with error code: 0x80010106.

The clue I found only is that this error code is related to multi-threading.
The answer was simple - set the application attribute:
[STAThread]

Thursday, January 21, 2010

WinSNMP C# wrapper fails in 64 bit systems

Some time ago I wrote a C# wrapper for WinSNMP. Recently I moved to Win7 64 bit and that application failed to run. I thought it's because of Win32 API change, but it seems like the issue was with 32 bit vs. 64 bit.

Solution: (work-around) compile the application to x32:
Right click the project -> Build -> Platform Target -> x86

It could be that I did something wrong in the wrapper, but I really don't have the time to check it out.

Sunday, January 10, 2010

Convert SQL Server Database to Access MDB

I tried looking around the web how to accomplish the following task:
Convert SQL Server Database to Access MDB

I couldn't find any answer online, but on the way to work it hit me: use SQL Server Management Studio "Export". I just checked it and it works like a charm. In 2 minutes I was able to export the SQL Server database to Access MDB.

Just do:
1. Open SQL Server Management Studio & connect to the SQL Server database.
2. Right click the database and select - "Tasks" => "Export"
3. Select the source database & select Access MDB as destination.
Continue with the instructions.