Fixing GPG keys in Elementary OS

Sometimes after adding lot of new PPAs and dealing with your system in everyday usage you may encounter that kind of waring in your terminal:

W: GPG error: http://ppa.launchpad.net precise Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 55E2097C08E6D617

The hexadecimal number in warning of course can be different. This message means that you need to add public key of PPAs repository to trusted one. You can do this in two ways.

Fetching public key manually from terminal

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 0F678A01569113AE 497A0F381F691896 BF36996C4E1F8A59 B055FE50347540E8

You can pass more that one key as parameter for above command. Remember to replace every hexadecimal sequence with your own that’s causing problems.

Using Y-PPA-Manager application
This is the simplest way to handle this problem if you’re afraid of terminal. To install it, first add the webupd8 repository for this program:

sudo add-apt-repository ppa:webupd8team/y-ppa-manager

Update your software list and install Y-PPA-Manager:

sudo apt-get update
sudo apt-get install y-ppa-manager

Run application, then click on “Advanced.” From the list of advanced tasks, select “Try to import all missing GPG keys” and click OK.

You’re done! Be aware that operation may take quite a while depending on how many PPA’s you have and the speed of your connection, even couple minutes.

Open Play Store directly from your app

Google Play can be opened just by using Intent mechanism and using market:// prefix when writing URI. You need to consider situation when your app runs on device which does not have Play Store installed and then ActivityNotFoundException will be thrown. Then we can handle that by preparing alternative URI that will be opened by the browser.

    public static void openPlayStore(Context ctx, String appPackageName) {
        try {
            ctx.startActivity(new Intent(Intent.ACTION_VIEW,
                    Uri.parse("market://details?id=" + appPackageName)));
        } catch (ActivityNotFoundException ex) {
            ctx.startActivity(new Intent(Intent.ACTION_VIEW,
                    Uri.parse("http://play.google.com/store/apps/details?id="
                            + appPackageName)));
        }
    }

Add custom application to “Applications” menu in elementary os

Elementary os Applications menu looks for installed applications in directory /usr/share/applications/ where files with extenstion *.desktop are located. Those files known as “desktop entries” are also used in KDE or GNOME desktop environments and detailed specification of their format is described at standards.freedesktop.org.

To keep things simple let’s say we downloaded latest version of Android Studio extracted tar file in desired location and we run application by studio.sh file by double clicking on it. When we open applications drawer in elementary os (or other desktop environment) we won’t be able to find it there. That’s because we don’t have desktop entry defined. So let’s do it!

Open terminal (Ctrl+Alt+T by default) and as system admin create empty android-studio.desktop file

cd /usr/share/applications/
sudo touch android-studio.desktop

Now we need to open file we just created in our favourite editor as admin and paste content like belowe into it.

[Desktop Entry]
Encoding=UTF-8
Name=Android Studio
Comment=Android IDE
Exec=/home/falvick/Android/android-studio/bin/studio.sh
Icon=/home/falvick/Android/android-studio/bin/idea.png
Terminal=false
Type=Application
Categories=GNOME;Application;Development;
StartupNotify=true

The most important line in this file is Exec where you need to put path to android studio executable. You can do this for any of your applications.

Note: I also found an article about App Launchers in elementary os documentation over here.

Generate placeholders inside SQL “IN” clause

Sometimes you need to create really complex SQL query in your android app and the only way to do this is by executing rawQuery() method on SQLiteDatabase object. Of course we have SQLiteQueryBuilder with its API but there is no method which helps us to create query with IN statement from SQL syntax. I realised that everytime I need to use it I write method which creates string with question marks (placeholders) and place it in some class with helper methods. The snippet of code looks like this and can really make your SQL helper development easier.

public static String createSQLPlaceholders(int length) {
    if (length < 1) {
        throw new RuntimeException("There are no placeholders in your query!");
    } else {
        StringBuilder sb = new StringBuilder(length * 2 - 1);
        sb.append("?");
        for (int i = 1; i < len; i++) {
            sb.append(",");
        }
        return sb.toString();
    }
}

And the most simple usecase of this method is presented below.

SQLiteDatabase mDb = databaseHelper.getWritableDatabase();
// example array with Strings to be inerted in
// place of questionmarks
String[] names = { "name1", "name2", "name3", "name4" };
String query = "SELECT * FROM tableName WHERE name IN ("
 + createSQLPlaceholders(names.length) + ")";
Cursor cursor = mDb.rawQuery(query, names);

As far as I’m concerned this is the only way to use parametrized IN queries in SQLite database.

Make your Thinkpad quiet under Linux

In description below I use Debian-based OS so package manager is apt. I don’t know if this package is available for non-debian distros.

Problem with noise

While ago after changing my laptop to Lenovo’s Thinkpad T420 I realised that my computer is much more louder when I work under Linux then in Windows. This was always true, even I was performing some easy not demanding tasks like browsing the internet. The reason for this was lack of drivers for CPU fan which was working all the time with speed approx 3800RPM!

Tests and theory

In Thinkpad T420 review noise produced by laptop was measured and it was between 32.3dB (IDLE) and 37.0dB (maximum load). I measured the speed of my fan and found out that minimum speed is approx 2000RPM and maximum can be even 4500RPM. Some of my friends told me that I’m a little touchy so let’s have a look at a bit of theory. Some may say that difference between 32 and 37dB is small, yes it could be if dB was not a logarithmic type of unit (where the base of logarithm is 10) which means that difference between 30-40db it’s not just 10 units but ten times!

Quick fix

Be aware that every laptop behaves differently and I don’t take responsibility if your’s get overheated or burned because of improper use of thinkfan tool.

Because we are lucky developers someone already has created package called thinkfan which is available on sourceforge (http://thinkfan.sourceforge.net/) and in Ubuntu repositories. Let’s install all packages we need by running command in terminal:

sudo apt-get install thinkfan

After that we need to add coretemp to kernel modules and then load it:

sudo sh -c ‘echo coretemp >> /etc/modules’

sudo modprobe coretemp

After that we edit file /etc/thinkfan.conf  and we need to paste some sensors we will be using and deffinitions of speed levels. In my particular case file looks like below.

sensor /sys/devices/platform/coretemp.0/temp1_input
sensor /sys/devices/platform/coretemp.0/temp2_input
sensor /sys/devices/virtual/hwmon/hwmon0/temp1_input

(0, 0, 55)(1, 48, 60)(2, 50, 61)(3, 52, 63)(4, 56, 65)(5, 59, 66)(7, 63, 32767)

We are not done yet. Now we need to edit /etc/modprobe.d/thinkfan.conf and set acpi_fan_control to 1 and after that reload kernel module thinkpad_acpi

sudo sh -c ‘echo “options thinkpad_acpi fan_control=1” >> /etc/modprobe.d/thinkfan.conf’

sudo modprobe -r thinkpad_acpi

sudo modprobe thinkpad_acpi

Now open file /etc/default/thinkfan  and set parameter START=”yes”Finally we can start thinkfan deamon by command line:

sudo /etc/init.d/thinkfan start

And check if it’s working properly (output should be number from 1 to 7 those are speed levels declared by us in thinkfan.conf before)

sudo cat /proc/acpi/ibm/fan

It was a bit of work to configure this package but in my case it works like a charm!

Migrate from Eclipse to Android Studio without pain

I advise you to read entire post and then start working on migration from Eclipse to Android Studio. You can also try to move along with migration while reading it. I think it’s most efficient way of doing this.

In the beginning I need to mention that in this post I use Eclipse Kepler 4.3 with ADT 22.3.0Gradle 1.10 and Android Studio 0.4.4 you need to keep that in mind because last two of these projects are still in early development process and there are many problems you may encounter that are specific to software version that you’re currently using.

Export projects from Eclipse

The best way to export projects from eclipse is to follow guide on android developers website but at the time of writing this post gradle build files generated by ADT plugin was a bit outdated so you will probably came across some errors. First of all…

Most common error – Gradle version not supported

Android Studio will probably will greet you with similar error message in event log:

You are using Gradle version 1.6, which is not supported. Please use version 1.9.

The reason why this error occurs is because generated  build.gradle files tells Android Studio to use older version of Android Gradle Plugin. So let’s open the file build.gradle which was created by Eclipse in root of your project (if you exported app which has some library project dependencies open build.gradle located in the very root of your multiproject setup) and modify it to look something like this:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.8.+'
    }
}

After that your Android Studio Copy uses correct version of Gradle. Choose File -> Settings -> Gradle and mark “Use local gradle distribution” and enter path to your Gradle home. Click apply and rebuild your whole project.

Still not working – missing Android API error

You may also get error about missing API target. To resole this kind of  error just open Android AVD manager and download missing API level. This error is quite natural and won’t occur if like me you were using the same Android SDK directory for eclipse and Andoid Studio.

Manifest error – Could not find element “Application”

I came across this error while I was trying to import really large android project set with many library projects. The reason of this error is that Eclipse doesn’t require every android project to have an <application/> tag included in AndroidManifest.xml file. Unfortunately  for us Android Studio does require it. To solve this issue just add empty <application/> tag to project manifest that has an error.

Manifest merging min/targetSdkVersion

This is another error which I encounter in my large project set. The first reason for this error was that min and target SDK versions secified in build.gradle and AndroidManifest.xml were different for my project exported from Eclipse. If you already fixed that in all of your projects and you still see this error there is another reason. I found out that if some of libraries (AndroidStudio calls them modules) has incompatible SDK level with another module (that it depends on) in workspace an error will still be present.

Library project error

This error is really rare and happens only if Eclipse somehow don’t see your project as library and won’t generate “android-library” attribute in build.gradle. To solve it just change apply plugin  line (probably first line in your library build.gradle) to look like:

apply plugin: 'android-library'

Hopefully after all that you’ll enjoy building your project in your new favourite IDE 😉

Parameterized Activity in android

Android activities can be invoked by other applications installed on a device by use of Intents. That’s the way the platform was designed, to use the benefit of fact that other apps are able to do something and we don’t need to implement that functionality. You would probably think: “That’s great!” and yes it is but there’s always a catch.

Let’s take a look at rare scenario when you user use Honeycomb tablet (I know… old… not visible on a market… this is only an example). You now that in activity called TestActivity you have code that won’t be able to run on this version of android. You can write some if statements in you java code to handle that kind of situation. OK but there’s more elegant solution. Why even show this activity to other applications? We can accomplish that by using parameters in AndroidManifest.xml.

In android we can define resources that are specific to API version that user device is using. That kind of resources are usually strings or selectors but we can also define there booleans. For example let’s create a folder values-v11 and inside of it file bools.xml with content like below.

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
    &lt;!-- True if running under Honeycomb or later. --&gt;
    &lt;bool name=&quot;atLeastHoneycomb&quot;&gt;true&lt;/bool&gt;
&lt;/resources&gt;

Then we would create next file for API other versions. Now let’s add checking this parameter in our application tag in manifest.

&lt;activity android:name=&quot;com.example.project.TestActivity&quot;
                  android:enabled=&quot;@bool/atLeastHoneycomb&quot; &gt;
            . . .
&lt;/activity&gt;

Now our activity won’t be visible to other apps installed on device running Honeycomb. Attributes defined this way can be used in many other situations.