Wednesday, December 26, 2012

Binding bitmap to ImageView with SimpleAdapter

SimpleAdapter does not bind bitmaps to ImageView. That's the bottom line. From viewing the source of SimpleAdapter it seems it only binds text and integers (???) to ImageView.

I didn't like the extension I've found which do that (it overrides the whole binding function instead of just enhancing it). so I wrote my own.

package com.utils;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SimpleAdapter;

public class SimpleAdapterEx extends SimpleAdapter {
 private int mResource;
    private int[] mTo;
    private String[] mFrom;

    private List<? extends Map<String, ?>> mData;
 
 public SimpleAdapterEx(Context context, List<? extends Map<String, ?>> data,
            int resource, String[] from, int[] to) {
  super(context, data, resource, from, to);
  
  mResource = resource;
  mData = data;
  mTo = to;
  mFrom = from;
 }

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
  View v = super.getView(position, convertView, parent);

  v = createViewFromResourceEx(v, position, convertView, parent, mResource);

  return v;
    }
 
 @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
  View v = super.getDropDownView(position, convertView, parent);
  
  v = createViewFromResourceEx(v, position, convertView, parent, mResource);
  
  return v;
 }
 
    private View createViewFromResourceEx(View v, int position, View convertView,      
            ViewGroup parent, int resource) {
     
        bindView(position, v);

     return v;
    }
        
    private void bindView(int position, View view) {
        final Map dataSet = mData.get(position);
        if (dataSet == null) {
            return;
        }

        final ViewBinder binder = getViewBinder();
        final String[] from = mFrom;
        final int[] to = mTo;
        final int count = to.length;

        for (int i = 0; i < count; i++) {
            final View v = view.findViewById(to[i]);
            if (v != null) {
                final Object data = dataSet.get(from[i]);
                String text = data == null ? "" : data.toString();
                if (text == null) {
                    text = "";
                }

                boolean bound = false;
                if (binder != null) {
                    bound = binder.setViewValue(v, data, text);
                }

                if (!bound) {
                    if (v instanceof ImageView) {
                        if (data instanceof Bitmap) {
                            setViewImage((ImageView) v, (Bitmap)data);                            
                        }                        
                    }
                }
            }
        }     
    }      
    
    private void setViewImage(ImageView imageView, Bitmap bitmap) {
     imageView.setImageBitmap(bitmap);
    }
}

Friday, December 21, 2012

Android Market Optimization: Part II

Earlier this year I wrote about Android Market Optimization blog posts. Now there are few sites that can help you do that:
In general you should follow ASO tag in your favorite tech blog, for example on TechCrunch.

Thursday, November 22, 2012

Eclipse: Unable to find Action Set

Problem: After updating Eclipse my Android plug-in stopped working. Checking a bit more, all my Eclipse plug-ins stopped working (they even didn't appear in the Help->About windows).

In the errors log window (Window->Show View->Error Log) I saw the error "Unable to find Action Set" for all the plug-ins. For example, the Android plug-ins errors:
Unable to find Action Set: adt.actionSet.lint
Unable to find Action Set: adt.actionSet.avdManager
Unable to find Action Set: adt.actionSet.refactorings
Unable to find Action Set: adt.actionSet.wizards

Solution: I checked many options, bottom line, the problem was solved in my case when I've uninstalled (Help->About->Installation Details) a package called: Object Teams Patch for JDT/Core

Tuesday, September 11, 2012

Advanced ACRA 2: Frequent errors detection

In my first ACRA post I wrote about detecting which Android versions generates the errors using Google Docs. This time I'll write on the most basic problem - finding which error happens the most. It is possible to group by full stack trace, however, the stack trace are not the same even on exactly the same errors. Instead, my approach is to compare the exception & the function that actually threw the exception. It might produce incorrect results if there are multiple similar exceptions.

Here's how it's done, open the Google Doc's ACRA spreadsheet:
  1. Rename the first sheet to 'Sheet1'
  2. Add new sheet
  3. In Cell A1 set text: "Short Stack"
  4. In Cell A2 set text: "=LEFT(Sheet1!P2,FIND("(", Sheet1!P2, 1))"
  5. Copy cell A2 to match the rows in Sheet1 (e.g. to cells A3, A4, A5, ...)
  6. Select column A in Sheet2, and create a pivot table ("Data" -> "Pivot table report...")
  7. In the pivot table sheet:
    • "Rows" -> "Add field" : "Short Stack"
    • "Values" -> "Add field" : "Short Stack", summarize by: "COUNTA"
Note: this list is for ACRA v4.2.3. With ACRA 4.3.0+ the 'Stack Trace' column might not be P

Monday, August 13, 2012

Eclipse autocomplete doesn't work

After formatting my computer I had to reinstall everything. When I started to work with my new Eclipse Juno on my Android project the autocomplete didn't work. It took my few searches on Google to find the answer, so I'll improve that page pagerank so others can find it faster. The answer is here.

Wednesday, August 8, 2012

Diagnosing repetitive BSOD

I had repetitive BSOD on my Windows 7 x64 Samsung laptop.

Here is the steps I think I should have taken (stop when the problem found):
1. Download Blue Screen View by Nir Sofer and check which driver cause the BDOS. If it's the same driver all the time - root cause found.

2. Memory check: (don't use the Windows 7 built-in memory check, it missed my problem) Download memtest86+ and check your physical memory. This tool might taken few hours to run.

3. Disk check: Run full disk check - open the disk in Windows Explorer, right click on the driver root, click on "Properties", than "Tools", under "Error Checking", check all check boxes and press on check now. After rebooting you can view the results in the "Events Viewer" under "Windows Logs" -> "Application", sort by "Source" column and search for "Wininit"

If nothing found so far, my best guess is  to backup the computer & re-format it. If the BDOS continues it's an hardware issue, otherwise it was some other software issue.

Thursday, August 2, 2012

Android SDK installation: Java not found

If you don't have Java installed - do that.
If you do, check the following:
  • Windows x64: The Android SDK is looking for Java 32bit. If you installed Java 64bit, install 32bit too.
  • In the Android SDK installer, try pressing "Back and "Next". Few people reported that this fix the problem.

Mobile application analytics

Just viewed this presentation from Google IO 2012, in which Google describe the new Google Analytics for mobile. The interesting part, is how they list what should be included in a mobile app analytics:
  • User acquisition - Where should I spend my marketing dollars?
    • Application store download - from which sources the download are coming (store search, web search, ad campaign, e-mails, referrals).
    • New users
    • Active users
  • Engagement - Once the user get your application how they are using it?
    • Engagement flow
    • Top app screens
    • Events
    • App crashed - A bit overlapping with the app store.
  • Outcome
    • App sales
    • In-app purchases
    • Ad-monetization 
    • Goal conversions

Thursday, July 12, 2012

Advanced ACRA 1: OS Version reporting

Assumption: ACRA is set and running.

Here's how to display in which Android OS version you get the most exceptions. If the exceptions distribution are different from Android OS distribution in the market - the issues might be OS version dependent.

You can use Google Visualization API as described here.

but there's a simpler solution - create a summary with-in the Google Docs spreadsheet.

Steps:
1. Open an active ACRA reporting spreadsheet (containing data).
2. On the main menu: 'Data' -> 'Pivot table report'
3. In the 'Report Editor' do:
3.1. Select: 'Rows' -> 'Add field' and select ANDROID_VERSION
3.2. Select (Optional): 'Columns' -> 'Add field' and select APP_VERSION_NAME
3.3. Select: 'Values' -> 'Add field' and select 'Timestamp'. Click on 'Summarize by' and select COUNT.
3.4. Select (Optional): 'Filter' -> 'Add field' and select APP_VERSION_NAME, and select which app versions to display

Wednesday, July 11, 2012

Few tips for Android (game) developer

Alternative title: What to do to NOT get NOT featured on Google Play

Here are the main headlines from Google I/O 2012 - Ten Things Games Developers Should Know talk.
  1. Very that your app works on the latest version of Android & high-res devices. Verify you're using relevant features for the latest version (not comparability mode).
  2. Try to stop pirates & vampires.
    Pirate - steal software. Google solution: use LVL - License Verification Library.
    Vampire - steal bandwidth. Google solution: don't download large resource files - use APK expansion files.
  3. Don't mess with the buttons. Make the 'Back' button behave as the user expect.
  4. Respect the life cycle. When a device is locked/exited/etc - pause your game. When your game is paused, don't play music.
  5. Minimize permissions. Bad permissions: (1) change wifi settings, (2) Receive boot completed, (3) Query running tasks, (4) Obtain fine location, (5) Read system log, (6) Directly call phone numbers, (7) Read/write contacts/calendar, (8) Read/write bookmarks, (9) Display system level alerts & (10) Send/receive SMS.
  6. Conserve resources. Minimize battery, memory, storage, bandwidth. Use the APK expansion files in-place, don't unpack them & delete (the Google Play will re-download it).
  7. Play by the rules of Google Play. (1) No payment providers other than Google Play, (2) Don't upload an app that downloads another app (e.g. alternative app store), (3) Don't bribe customers for 5-stars reviews.
  8. In app payments problems. For example: you app is asleep when the billing message arrives. The correct way for in-app billing: the in-app billing service should directly persist the purchase information to a storage, and your app will read it from the storage.
  9. Testing: Input devices, Form factor, OS Version. Driver stack & GPU hardware.
  10. Play listings. Problem with the listings, images that do no fit small screens (small subtitles).

Tuesday, June 26, 2012

Unsuccessful app? sell it

There's an on-line market for app developers you might want to try:
http://www.apptopia.com

You might get lucky (or not).

Monday, June 11, 2012

Which SDKs are popular in the Android Market?

It's always good to know which SDKs are trending, and which are niche player. Few weeks ago I found a site that created statistics on the Android Market just for that:
http://www.appbrain.com/stats/libraries/dev

I found it very useful. Hope it helps you too.

Thursday, April 26, 2012

Error 2: Failed to connect to device as it is pin locked.

When trying to run a Windows Phone application on a device for the first time, you might get the following error:
Error 2: Failed to connect to device as it is pin locked. 0 0

Solution: Register your phone for development with Microsoft.
Note: if you still get this error after registering the device, you might need to restart Zune & Visual Studio.

Tuesday, April 24, 2012

No invoice for Windows Phone developer registration fee

I registered to Microsoft's App Hub (Windows Phone developer account), paid the registration fee (~100$), but I didn't get an invoice. Checking online only made it clearer that Microsoft does not send an invoice for App Hub registration fee since more people had the same problem.

I opened a ticket at App Hub support here: https://windowsphone.create.msdn.com/support

I've waited for 4 days and got no answer, than:

(1) I asked a friend from Microsoft what to do. He sent me to Microsoft regional support.
(2) Calling the support they redirected me to MSDN support (since the registration is on create.msdn.com).
(3) MSDN Support told me to send an e-mail to apphub@microsoft.com
(4) The answer from apphub@microsoft.com was to open a ticket at Hub App support..... CRAP.

I still don't have an invoice, but I do have second thoughts about developing for Windows Phone.
Way to go Microsoft.

Sunday, March 18, 2012

AdMob: ad pending approval

My AdMob ad was pending approval for 3 weeks until it was approved.

It's a bit more than what I expected.

Sunday, March 11, 2012

Enum.GetValues does not exist on Windows Phone

Enum.GetValues does not exist on Windows Phone. The solutions here and here requires LINQ.
I've changed the solutions so they would fit Windows Phone without LINQ. I also reduced memory allocations (not using enumerators and generic collections):

public static T[] GetValues<T>()
{
Type enumType = typeof(T);
if (!enumType.IsEnum)
throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");

FieldInfo[] fields = enumType.GetFields();
int literalCount = 0;
for (int i = 0; i < fields.Length; i++)
if (fields[i].IsLiteral == true)
literalCount++;

T[] arr = new T[literalCount];
int pos = 0;
for (int i = 0; i < fields.Length; i++)
if (fields[i].IsLiteral == true)
{
arr[pos] = (T)fields[i].GetValue(enumType);
pos++;
}

return arr;
}

Monday, February 20, 2012

Android Market Optimization

This subject also known as App Store Optimization (ASO). Few people started to write posts on this subject for Android, this post is an on-going work to collect links to those posts:

Wednesday, February 15, 2012

Android promotion: pay per install

I tried looking for ways to promote Android apps. It was hard. Why companies aren't saying: we're doing Pay-Per-Install campaigns? (alternative names include: Cost-Per-Install, CPI, Cost-Per-Action, CPA)

Here's a list of pay-per-install for Android I've found so far (on going work, please correct me if there's something wrong here):
  • AppBrain - Free apps only, Minimum bid: 0.20$, minimal daily budget: 25$, minimal campaign budget: 100$. See more details here. No SDK integration required,
  • TapJoy - Pay-per-install plus optional pay-per-action (which probably cost much more). Minimum bid: 0.10$ for rewarded install. SDK integration required. Does not accept PayPal.
  • Flurry AppCircle - Free & paid apps. Minimum bid: 0.75$
  • Everbadge - Free & paid apps. Minimum bid: 0.15$. SDK integration required,
  • AppRedeem - Free & paid apps. Minimum bid: 0.50$ (paid apps), 0.15$ (free apps)
  • PlayMobs - Minimum bid: 0.10$ for rewarded install. No SDK integration required.
Possible Pay Per Install, not sure:
References:

Monday, January 30, 2012

Downloading Android source code on Windows

Here's the short-short version:
  1. Download and install command line Git client: msysgit.
  2. Download the root Android project using Git.exe (located in /bin folder of msysgit)
    git clone https://android.googlesource.com/platform/manifest
  3. In the target folder you'll find few XML files. Open default.xml. You can see multiple tags . Choose the project you want to download. You need the name attribute of the project. Write the following line to download:
    git clone https://android.googlesource.com/
Example:
To download the most interesting project (IMHO) frameworks/base, the GIT command is:
git clone https://android.googlesource.com/platform/frameworks/base

Projects of interest:
  • packages/apps/XXXX - The project names of the apps that comes bundled with Android (excluding proprietry Google apps such as the Android Market) such as the Gallery, Camera etc.
  • external/XXXX - 3rd party software (ping, bzip, etc).
  • frameworks/base - The sources of the Java system.

Saturday, January 21, 2012

Android (Java) object pool

There are many ways to implement an object pool. Here's the way it's implemented in some classes in Android (Message, MotionEvent, Parcel, VelocityTracker):

private MyObjectName mNext;
private static Object gPoolSync = new Object();
private static MyObjectName gPool;
private static int gPoolSize = 0;
private static final int MAX_POOL_SIZE = 10;

public static MyObjectName obtain() {
  synchronized (gPoolSync) {
    if (gPool != null) {
      MyObjectName m = gPool;
      gPool = m.mNext;
      m.mNext = null;
      gPoolSize--;
      return m;
    }
  }
  return new MyObjectName();
}

public void recycle() {
  synchronized (gPoolSync) {
    if (gPoolSize < MAX_POOL_SIZE) {
      // Perform object data cleaning and data releasing before recycling
      clearForRecycle();
                
      mNext = gPool;
      gPool = this;
      gPoolSize++;
    }
  }
}

Wednesday, January 11, 2012

Reducing ArrayList add()/remove() memory re-allocation/shifts

This post is Android related, but probably goes to all java systems.

Reason: ArrayList implementation is based on an array, with a pointers to the start and end of the array.
(1) When you remove the first or last items, the pointers are moved. If you remove and items from the middle all the items after the removed location are shifted.
(2) After many removes/adds the start pointer is set so high the ArrayList is forced to shift all the items.

Solution: when removing item - swap the item with the last item, and remove the last item. Drawback - you lose the order of the items in the ArrayList.

import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;

public class SwapArrayList extends ArrayList {
private static final long serialVersionUID = 2995040970224168173L;

public SwapArrayList() {
this(0);
}

public SwapArrayList(int capacity) {
super(capacity);
}

public SwapArrayList(Collection collection) {
super(collection);
}

@Override
public boolean remove(Object object) {
int index = indexOf(object);
if (index >= 0) {
int size = this.size();
if (index < size - 1) {
// Swap the last item with the item to be removed
E tmp = this.get(size - 1);
this.set(size - 1, this.get(index));
this.set(index, tmp);
index = size - 1;
}

remove(index);
return true;
}
return false;
}

@Override
public E remove(int location) {
int size = this.size();
if (0 <= location && location < size) {
if (location < size - 1) {
// Swap the last item with the item to be removed
E tmp = this.get(size - 1);
this.set(size - 1, this.get(location));
this.set(location, tmp);
location = size - 1;
}
} else {
throw new IndexOutOfBoundsException();
}

return super.remove(location);
}
}

Sunday, January 8, 2012

onKeyDown/onKeyUp/onTrackballEvent does not fire in a View

When trying to get keypad events in a view, the view does not get those events unless explicitly sent by the Activity, so to fix this add the following code in the Activity:

@Override
public boolean onTrackballEvent(MotionEvent event) {
if (mView.dispatchTrackballEvent(event) == true)
return true;

return super.onTrackballEvent(event);
}