Yet another android developer

Jul 13

Dec 8

Debug certificate expired

Once a year you see very starnge error in your android project:

Error generating final archive: Debug certificate expired on …

To fix it on Linux or OS X:

rm -f ~/.android/debug.keystore

Then run Project-> Clean in APDE.

On Windows file debug.keystore should be in folder %USERHOME%/.android, can’t verify it. Find it and delete, then clean project in APDE as described.


Nov 24

Photos by SpookCamera 


Photo by SpookCamera 

Photo by SpookCamera 


Nov 10

How to start activity from broadcast receiver

It’s simple - just create Intent and invoke startActivity, but you may get strange runtime error. To prevent it, make sure you set intent flag:

public void onReceive(Context context, Intent intent) {

Intent launchIntent = new Intent(context, MyActivity.class);

launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK );

context.startActivity(launchIntent);

}

BTW, if you combine it with Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS your activity will not be shown in “recent apps” list (you see it when press and hold Home button).


Nov 9

How to turn on screen when activity starts

Sometimes you need to start activity from service or broadcast receiver. However, screen may be turned off or even locked. Let’s make our activity visible to user (and touchable):

private KeyguardManager keyguardManager;
private KeyguardLock keyLock; 

public void onCreate(Bundle savedInstanceState) { …

getWindow().setFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,  WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
….

keyguardManager = (KeyguardManager) getSystemService(Activity.KEYGUARD_SERVICE);

keyLock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);

keyLock.disableKeyguard();

don’t forget to restore state in your onStop() - invoke keyLock.reenableKeyguard();


Nov 3

Human-Powered Player: 1000+ installations

I released this app September 22th and now it passed 1000 installations mark. 

It simple, yet funny app:

Technology meets Art. Real steampunk player. You need to produce energy to charge this player - shake it or move with that. Perfect jogging companion - it plays while you run.


Nov 2

New app released: Spook Camcorder

Fresh meat, I’ve just published it in Android Market:

Camcorder for spy or paparazzi. Pretend you’ve got a call and start video recording.

* Emulates phone call

* “Call” UI is semi-transparent, camera preview is visible

* Starts recording when your “accept” call (tap)

* Tap to stop

* Result is shown in separate folder in Gallery


Oct 21

Live in GUI thread: be paranoid

In one of my app I deal with camera. I handle byte array from camera, process it, save on sd card, update media store etc - of course in separate thread (using AsyncTask, the easiest way). But I called camera.takePicture(…) in main GUI thread, I was sure it would take less than 5 seconds and it worked for me very well. Of course, I was wrong, one of users of my app was shooting in very bad light conditions and it took more than 5 seconds to focus. My app failed with notorious ANR (Application Not Responding) error. What a shame.

So, never trust to code in main GUI thread, especially if you can’t control it. Hardware my be busy or slow, network will be slow, you know Murphy’s law, yeah? Isolate code which may be slow in separate thread. Just do it.


Oct 19

Register image in MediaStore

If you work with Camera directly, e.g. implementing Camera.PictureCallback you need to register produced image in MediaStore to make it available for other applications, like Gallery.

There is official way to do it, simple, but not reliable

MediaStore.Images.Media.insertImage(getContentResolver(), photo.getPath(), fName, “”)

I found that it may fail with NullPointerException:

10-19 16:20:18.156: ERROR/AndroidRuntime(3144): Caused by: java.lang.NullPointerException
10-19 16:20:18.156: ERROR/AndroidRuntime(3144): at android.provider.MediaStore$Images$Media.insertImage(MediaStore.java:506)

on some devices. Moreover, this code re-read existing JPEG file, so it’s not just unreliable, but slow. As alternative you could do registration manually.

File photo = new File(rootDir, fName);
FileOutputStream fos = null;
try {
    // write bytes to file (jpeg)
    fos =new FileOutputStream(photo.getPath());
    fos.write(jpeg[0]);
    fos.close();

    ContentValues values = new ContentValues(7);
    values.put(Images.Media.TITLE, PHOTO_CATEGORY);
    values.put(Images.Media.DISPLAY_NAME, fName);
    values.put(Images.Media.MIME_TYPE, “image/jpeg”);
    // etc 
       getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values);
 } catch (IOException ie){ …

}


Page 1 of 2