Monday, December 24, 2012

Android BroadcastReceiver is not working after install ? How to fix this ?

Starting from Android 3.1 after you install an application all broadcast receivers are in "STOPPED" state until you click on the icon and start the application. I wanted dig-in to find a solution for this problem. This is what I discovered under the hood.

 com.android.server.pm.Settings.readStoppedLPw() is invoked on BOOT_COMPLETE and it checks for


String tagName = parser.getName();
if (tagName.equals("pkg")) {
    String name = parser.getAttributeValue(null, "name");
    PackageSetting ps = mPackages.get(name);
    if (ps != null) {
        ps.stopped = true;
        if ("1".equals(parser.getAttributeValue(null, "nl"))) {
            ps.notLaunched = true;
        }
    } else {
        Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + name);
    }
so, what is this "nl" ? When you install an apk, your broadcast receiver will listed on /data/system/packages-stopped.xml 


<stopped-packages>
<pkg name="test.broadcast" nl="1" />
</stopped-packages>

So, If you want to enable your packages back, you must modify this file and push it back to /data/system/packages-stopped.xml  with nl="0" 

to get it to work.

and then rebroadcast the BOOT_COMPLETED and you should be fine

adb shell am broadcast -a android.intent.action.BOOT_COMPLETED

to do all these you must have root. otherwise no choice

Wednesday, October 3, 2012

How to get all installed SD cards on Android

Today, I wanted to get all installed SD Cards on the device. In Android you can use Environment.getExternalStorageDirectory() get the  external device path but if you have more than 1, (in Galaxy S3 it has 2) you are in trouble. After few hours of Googling i managed to put this code together and hope it will help someone else too..

private static ArrayList<String> mMounts = new ArrayList<String>();
private void dumpAllSDCards() {
mMounts.add("/mnt/sdcard");
     
        try {
            Scanner scanner = new Scanner(new File("/proc/mounts"));
            while (scanner.hasNext()) {
              String line = scanner.nextLine();
              if (line.startsWith("/dev/block/vold/")) {
                String[] lineElements = line.split(" ");
lineElements[1].replaceAll(":.*$", "");
String element = lineElements[1];
                if (!element.equals("/mnt/sdcard")) mMounts.add(element);
              }
            }
          } catch (Exception e) {
           Log.d("MainActivity", e.toString());
          }
     
        for (int i = 0; i < mMounts.size(); i++) {
String mount = mMounts.get(i);
File root = new File(mount);
if (!root.exists() || !root.isDirectory() || !root.canWrite())
mMounts.remove(i--);
}
     

        for (String drive : mMounts) {
Log.d("MainActivity", drive + " exist!");
}     
}

Thursday, September 27, 2012

How to create a thumbnail from a video in Android


/**
     * Create a video thumbnail for a video. May return null if the video is
     * corrupt or the format is not supported.
     *
     * @param filePath the path of video file
     * @param kind could be MINI_KIND or MICRO_KIND
     */
    public static Bitmap createVideoThumbnail(String filePath, int kind) {
        Bitmap bitmap = null;
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(filePath);
            bitmap = retriever.getFrameAtTime(-1);
        } catch (IllegalArgumentException ex) {
            // Assume this is a corrupt video file
        } catch (RuntimeException ex) {
            // Assume this is a corrupt video file.
        } finally {
            try {
                retriever.release();
            } catch (RuntimeException ex) {
                // Ignore failures while cleaning up.
            }
        }

        if (bitmap == null) return null;

        if (kind == Images.Thumbnails.MINI_KIND) {
            // Scale down the bitmap if it's too large.
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            int max = Math.max(width, height);
            if (max > 512) {
                float scale = 512f / max;
                int w = Math.round(scale * width);
                int h = Math.round(scale * height);
                bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
            }
        } else if (kind == Images.Thumbnails.MICRO_KIND) {
            bitmap = extractThumbnail(bitmap,
                    TARGET_SIZE_MICRO_THUMBNAIL,
                    TARGET_SIZE_MICRO_THUMBNAIL,
                    OPTIONS_RECYCLE_INPUT);
        }
        return bitmap;
    }

Sunday, September 9, 2012

How to use SQL LIKE with content uri?

Today, I wanted to look something up from the Android calendar using URI. Its simple

String where = "title LIKE '%"+ searchText +"%'";

String[] projection = new String[] { "_id", "title", "description", "dtstart", "eventLocation" };
Cursor cursor = context.getContentResolver().query(
Uri.parse(getCalendarUriBase()), projection, where, null, null);

Don't use Selection and SelectionArgs. It does not work

Monday, August 13, 2012

Adapter pattern explained in real life example

Today, I was going through one of the projects in Google code repository and I found this. After reading this only even I understood whats the Adapter pattern is about :)


/**
 * If you don't know about "Adapter", let me explain it in a short example:
 * You are a girl and you have to sit during the time taking a piss.
 * I am a boy and I can stand straight while taking a piss.
*
 *If you have water-spout in your hands, you can stand upright to have a  piss =))
 * And from that point, you would have known: Yes, water-spout is an Adapter
 *
 * Just joking, forget it! Google Apdater design patterns =))
*/

Wednesday, June 20, 2012

android::CameraHardwareSec::takePicture() : capture already in progress error

Today, One of the Android devices keep getting crashed while taking a picture in a TimerTask. I was keep getting this error


E/CameraHardwareSec(75): virtual android::status_t android::CameraHardwareSec::takePicture() : capture already in progress
E/PanicImageActivity(1750): java.lang.RuntimeException: takePicture failed


problem is before you call this method again in the TimerTask run method. you need to make sure that there is one not in progress. Some devices cameras are very slow on processing picture frames.


private final Semaphore mutex = new Semaphore(1);



try {

mutex.acquire();


mCamera.takePicture(null, null, new PictureCallback() { 
        public void onPictureTaken(byte[] data, Camera camera) {
try {
             // Do something here
              mutex.release();
         }

         catch(Throwable t) {
          mutex.release();
         }

});
}
catch (Throwable t) {

 }

Tuesday, June 19, 2012

How to check whether Android Media Scanner is running ?

Here is the code


    public static final boolean isMediaScannerScanning(final ContentResolver cr) {
        boolean result = false;
        final Cursor cursor = query(cr, MediaStore.getMediaScannerUri(), new String[] { MediaStore.MEDIA_SCANNER_VOLUME }, null,
                null, null);
        if (cursor != null) {
            if (cursor.getCount() == 1) {
                cursor.moveToFirst();
                result = "external".equals(cursor.getString(0));
            }
            cursor.close();
        }
        return result;
    }

How to open a local file in Android browser?

Important thing here is you have to use file:// + path


 private String genLocalPageUrl(String fileName)  {
    return "file://" + this.getFilesDir() + "/" +  fileName ;
 }

How to open browser link in new tab or not open in Android?

This is not something I was not looking for but I just found it. I thought it will be helpful for someone out there.

key point here is putExtra("create_new_tab", false);

Intent  intent  = new Intent("android.intent.action.VIEW", null);
intent.addCategory("android.intent.category.BROWSABLE");
intent.setComponent(paramComponentName);
intent.putExtra("create_new_tab", false); // true or false
intent.putExtra("com.android.browser.application_id", paramComponentName.getPackageName());
startActivity(intent);

Tuesday, May 29, 2012

How to convert and Java project to Android Library project ?

Today, I had to add  reference to a Java project. So I right clicked on the project and checked Properties but there was no "Android" in the treeview in the properties. How to fix this ?

1. Right click and close the project.
2. Open the .project file in notepad.
3. Search for <natures> </natures> tag and change to

<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
4. Save the file and open again in Eclipse.
5. Now you need to create "project.properties" and "AndroidManifest.xml" manually. (I just copied these two files from another project :D)
6. Right click on the project -> Android Tools -> Fix project properties.

After that when I right click and go to properties I can see "Android" in the listview :)



Friday, May 25, 2012

How to change screen timeout to never programmatically?



Settings.System.putString(cr,                     Settings.System.SCREEN_OFF_TIMEOUT, "-1");

Wednesday, May 23, 2012

How to capture sound from microphone and play it on speakers in c#

I have been using NAudio for one of our applications to record sound. Today, I wanted to play back the live recording over the speakers while doing the live record. After few mins of Googling, hammering and fixing. I managed to get something working.


private IWavePlayer waveOut;
private BufferedWaveProvider waveProvider;
private WaveIn m_WaveIn;


private void StartRecording() {
       // Setup Incoming
m_WaveIn = new WaveIn();
m_WaveIn.BufferMilliseconds = 50; // This is very very important.
m_WaveIn.DeviceNumber = set your device here;
m_WaveIn.DataAvailable += WaveIn_DataAvailable;
m_WaveIn.WaveFormat = m_waveFormat;
m_WaveIn.StartRecording();

       // Setup Output


waveOut = new WaveOut();
waveProvider = new BufferedWaveProvider(m_waveFormat);
waveOut.Init(waveProvider);
waveOut.Play();


}


public void WaveIn_DataAvailable(object sender, WaveInEventArgs e) {
    byte[] buffer = e.Buffer;
    waveProvider.AddSamples(buffer, 0, buffer.Length);
}

Thats it. This works like a charm. Hope this will be useful for someone else as well.


Wednesday, May 9, 2012

Your own CountDownTimer in Android


Android CountDownTimer sucks. Why ? because in CountDownTimer.java (Android source code) it creates a mHandler inside the code which requires to call Looper.prepare() and Looper.loop() before calling new CountDownTimer(), You are likely to get Can't create handler inside thread that has not called Looper.prepare() because of this.

  So I wrote my own version of  CountDownTimer using Thread.

Here is it.


abstract class CountDownTimer extends Thread {
    public abstract void onFinish();
    private boolean mCancelled = false;
 
    public void run() {
    mCancelled = false;
    start(60);
    }
 
    private final void start(long secs) {
    long delay = secs * 1000;
do {
delay = delay - 1000;
try {
Thread.sleep(1000);
} catch (InterruptedException e) { }
if(mCancelled) {
return;
}
} while (delay > 0);
onFinish();
    }
        public final void cancel() {
    mCancelled = true;
    }
}

How to use
=========


CountDownTimer countDownTimer = new CountDownTimer()  {
@Override
public void onFinish() {

}
};

countDownTimer.start();




Thursday, April 26, 2012

getElementsByTagName returns null in Android 4.0 or 3.0

Today, my application crashed on Android 4 device. I always thought it will work on Android 4 because it was a simple application but I guessed wrong.

For some reason  getElementsByTagName  returns null in Android 4.0 or Android 3.0, if your  code look somewhat like this.


 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 DocumentBuilder builder = factory.newDocumentBuilder();
 InputSource is = new InputSource(new StringReader("Some XML here and there"));
 Document document = builder.parse(is);
 Element root = document.getDocumentElement();
 root.normalize();
           
 NodeList items = root.getElementsByTagName("tag");  <-- this function will always return null on Android 4 


When i dig in I found a bug reported in Google forums. I found this very hard to believe because this is a very primary level issue and how did it get passed?

Anyway, As a work around I had to use XPath. Just remember to change the project's Android SDK to 2.2 or higher otherwise XPath classes are not visible. They resides in javax.xml.xpath namespace. Or you can use XmlPullParser which reads documents from top to bottom.


InputSource is = new InputSource(new StringReader("Some XML here and there"));
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();
NodeList nodeList = (NodeList) xPath.evaluate("/xpath", is, XPathConstants.NODESET);




Sunday, March 11, 2012

Android requires compiler compliance level 5.0. Please fix project properties

Today, I moved a different work space from my old work space, but I imported some of the projects from my previous project and I started to get this error out of no where. I figure out it's something to do with the Eclipse compiler issue. To fix this you need to change globe flag which is located here

Window - > Preferences -> Java -> Compiler - > Change JDK compiler complience level to 1.5 or greater. (I use 1.6)

Tuesday, February 7, 2012

Wi-Fi Keep Alive / On for Kindle Fire

I have uploaded my first app to Amazon App Store, Check it out here

Wi-Fi Keep Alive


It is a simple for kindle fire to keep the wi-fi connection always on even the device screen goes off. This might use some extra battery power to keep the Wi Fi up but it wont disconnect your streaming music :)

Tuesday, January 31, 2012

debug.keystore keystore password ?

Today when i wanted to play with Google Maps, i had to generate a new Certificate fingerprint to include Maps. To generate a new Certificate fingerprint you need to use the keytool that comes with the SDK,

so i executed this line in the CMD,

keytool -list -keystore .android/debug.keystore

but it's asking for a password, duh! after few seacrches on google, I found out, it's android, type android and you shall passed