Maven and apklib: Duplicated file error

31 05 2014

The maven build error occurred when I had two Android projects: the one is apklib and the second one that is the actual application (the apk file) that uses apklib.

The error is saying that apk project contains duplicated R.java and BuildConfig.java files under target directory. The first file comes from apk project, and the second one from apklib.

There are two solutions for this problem:

Solution 1: Update android-maven-plugin

Update android-maven-plugin to the newest version (currently it is 3.8.2 or 3.9.0 release candidate to be checked here) where this bug is fixed.

The problem is that for example the 3.8.2 release is supporting only maven in version 3.1.1. no lower nor higher version will work. This would require downgrading maven on few machines so I decided to use another solution.

Solution 2: Remove conflicting files during apklib build with maven ant plugin

I’ve found solution on the Internet to remove duplicated files from the apklib target with ant plugin during build. The maven-antrun-plugin can do it. I added these lines to apklib pom.xml:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-antrun-plugin</artifactId>
	<executions>
		<execution>
			<phase>process-classes</phase>
			<goals>
				<goal>run</goal>
			</goals>
			<configuration>
				<tasks>
					<delete dir="${project.basedir}/gen" />
				</tasks>
			</configuration>
		</execution>
	</executions>
</plugin>

Then rebuild the apklib project and apk after that. This works!

Eclipse problems with ant plugin

Ant plugin is not recognized by eclipse maven m2e connector and eclipse displays errors. the project still can be built with either maven or eclipse build, but the error is visible on the pom.xml.

Then with plugin management in apklib you can force eclipse to ignore the ant plugin command. It does not affect maven build, just the eclipse compilation.

You can do it by eclipse quick fix or by adding manually plugin management directive to apklib’s pom.xml:

<pluginManagement>
<plugins>
	<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
	<plugin>
		<groupId>org.eclipse.m2e</groupId>
		<artifactId>lifecycle-mapping</artifactId>
		<version>1.0.0</version>
		<configuration>
			<lifecycleMappingMetadata>
				<pluginExecutions>
				<pluginExecution>
					<pluginExecutionFilter>
						<groupId>
							org.apache.maven.plugins
						</groupId>
						<artifactId>
							maven-antrun-plugin
						</artifactId>
						<versionRange>
							[1.3,)
						</versionRange>
						<goals>
							<goal>run</goal>
						</goals>
					</pluginExecutionFilter>
					<action>
						<ignore></ignore>
					</action>
				</pluginExecution>
				</pluginExecutions>
			</lifecycleMappingMetadata>
		</configuration>
	</plugin>
</plugins>
</pluginManagement>




Android SQLite schema migration with patches

3 05 2014

When upgrading your Android application you often need to change its data model. When the model is stored in SQLite database, then its schema must be updated as well. I recommend the concept of patching and versioning the database This is very well described in this article:

http://www.greenmoonsoftware.com/2012/02/sqlite-schema-migration-in-android/

The idea behind it

Android lets you upgrade the schema version, detect its changes and react to it when user installs new app version with higher schema version. The SQLiteOpenHelper class that will notify you about this.

You need to override its onUpgrade() method. When onUpgrade() detects that current version is lower than new one, it can apply patches in order and migrate schema to the desired version.

I used that algorythm in one of my apps and it worked very well.





Android status bar notifications [complete tutorial with source code]

1 02 2014

Displaying status bar notification is a common way to unobtrusively inform user that something has happened (like new GMail message notification). In your app you can display it whenever you want. I will guide you how to do it from basics. This is how notifications are presented to the user:

Status bar notifications

Status bar notifications

Google’s documentation regarding the notifications is here.

Source Code

All the source code for this tutorial you can download here.

1. Create Basic notification

Notification consists of three obligatory parameters: title text, content text and small icon image. Here is the code that creates such notification:

private Notification createBasicNotification() {
	NotificationCompat.Builder builder = new Builder(getApplicationContext());
	Notification notification = builder
			.setSmallIcon(R.drawable.me)
			.setContentTitle(getString(R.string.notif_title))
			.setContentText(getString(R.string.notif_text))
			.build();

	return notification;
}

2. Display Basic Notification

After it is built, you can display it to the user with NotificationManager:

private void displayNotification(Notification notification) {
	NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
	notificationManager.notify(myNotificationId , notification);
}

Where myNotificationId is final int and is equal to 1:

private static final int myNotificationId = 1;

Thanks to this ID later you can refer to that notification and update its content  or hide it when you need it.

This is how the notification looks like right now:

notif_my_custom

3. Auto Hide notification after it is touched

As for now nothing happens when user touches notification. To make it disappear after touch add this clause to the builder:

setAutoCancel(true)

4. Start activity after notification is touched

The most common action after user selects notification is to open activity presenting the detailed data that caused notification to be issued. You have to assign PendingIntent to notification in order to do it:

private PendingIntent preparePendingIntent() {
	Intent intent = new Intent(getApplicationContext(), MainActivity.class);
	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

	PendingIntent pendingIntent = PendingIntent.getActivity(
			getApplicationContext(), 
			0, 
			intent, 
			PendingIntent.FLAG_UPDATE_CURRENT);
	return pendingIntent;
}

After that, you assign this intent to notification with the builder command:

.setContentIntent(notificationIntent)

Now you have a basic notification that can issue certain action. Further customization is optional and introduced in newer versions of Android. Since possibilities are quite big, it is worth to continue improving the notification.

5. Filling in remaining small notification fields

Here is the code to fill in the remaining fields of small notification (this should be called on bilder object):

.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.me))
.setContentInfo(getString(R.string.notif_contentInfo))
.setWhen(Calendar.getInstance().getTimeInMillis() + 1000*60+60)
.setVibrate(vibrationPattern)

In order to make vibrations work you need to define pattern (mine is quite sophisticated :P):

long[] vibrationPattern = {0, 200, 800, 200, 600, 200, 400, 200, 200, 200, 100, 200, 50, 200, 50, 200, 50, 200, 500, 200};

but it surely can be simplier:

// Start without a delay
// Vibrate for 100 milliseconds
// Sleep for 1000 milliseconds
long[] pattern = {0, 100, 1000};

and require an VIBRATE permission in android manifest

<uses-permission android:name="android.permission.VIBRATE"/>

6. Apply big style to the notification

What actually is the Big Style? It is the notification with list of String. This is so called InboxStyle, since it is mainy used by GMail to notify user of incoming list of messages. This is how it looks like:

Notice that most of the elements are the same, except the 7 – the details list. Remember that big style works only for android versions higher than or equal to 4.2.

So now – how to build this list? Just create the notificationas it is done until now, and apply style to the builder:

.setStyle(inboxStyle)

And the inboxStyle is built like this:

private InboxStyle prepareBigNotificationDetails() {
	NotificationCompat.InboxStyle result = new InboxStyle();
	result.setBigContentTitle(getString(R.string.notif_inboxStyleTitle));
	result.addLine(getString(R.string.notif_inboxStyle_line1));
	result.addLine(getString(R.string.notif_inboxStyle_line2));
	result.addLine(getString(R.string.notif_inboxStyle_line3));
	result.addLine(getString(R.string.notif_inboxStyle_line4));
	result.addLine(getString(R.string.notif_inboxStyle_line5));
	result.addLine(getString(R.string.notif_inboxStyle_line6));
	return result;
}

Now test it (remember that only android 4.2 or higher will handle such notification). The result is like this:

InboxStyle notification

InboxStyle notification

notice that fields displayed on small notification are not visible in this style.

7. Updating notification content

Notification updates are quite simple: just set the fields you want to change with notification builder and call NotificationManagers’ notify() method providing the ID that you assigned to the notification that you need to update. The notification will be updated accordingly.

Download the Source Code

All the source code for this tutorial you can download here.

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Android: check device screen density programatically

11 01 2014

When designing app for multiple screen sizes it is useful to check screen density (ldpi, mdpi, hdpi, xhdpi) and to know exact value in dpi.

Source: Android Developers

Source: Android Developers

This is how to do it programatically:

public void determineScreenDensity() {
	DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int density = metrics.densityDpi;

    if (density==DisplayMetrics.DENSITY_HIGH) {
        Toast.makeText(this, "DENSITY_HIGH: " + String.valueOf(density),  Toast.LENGTH_LONG).show();
    }
    else if (density==DisplayMetrics.DENSITY_MEDIUM) {
        Toast.makeText(this, "DENSITY_MEDIUM: " + String.valueOf(density),  Toast.LENGTH_LONG).show();
    }
    else if (density==DisplayMetrics.DENSITY_LOW) {
        Toast.makeText(this, "DENSITY_LOW:" + String.valueOf(density),  Toast.LENGTH_LONG).show();
    }
    else {
        Toast.makeText(this, "Density is neither HIGH, MEDIUM OR LOW: " + String.valueOf(density),  Toast.LENGTH_LONG).show();
    }
}

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Android: check device screen size programatically

4 01 2014

When designing app for multiple screen sizes it is useful to check screen size (small, normal, large, xlarge).

Source: Android Developers

Source: Android Developers

This is how to do it programatically:

public void determineScreenSize() {
	if((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {     
        Toast.makeText(this, "Large screen",Toast.LENGTH_LONG).show();
    }else if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL) {     
        Toast.makeText(this, "Normal sized screen" , Toast.LENGTH_LONG).show();
    }else if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_SMALL) {     
        Toast.makeText(this, "Small sized screen" , Toast.LENGTH_LONG).show();
    }else {
        Toast.makeText(this, "Screen size is neither large, normal or small" , Toast.LENGTH_LONG).show();
    }
}

Remember – To get screen size of xlarge, you need to use API >= 3.0

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Android: handle uncaught exceptions

28 12 2013

To avoid the ‘unfortunately app has stopped‘ dialog box, you can handle all uncaught exceptions in your app by setting custom handler.

Uncaught exception Handler

Paste this code in the beginning of your app. This will setup the handler. Do it only once, for example in onCreate of your fisrt activity that is displayed to the user

Thread.setDefaultUncaughtExceptionHandler(
	new UncaughtExceptionHandler() {

		@Override
		public void uncaughtException(Thread thread, Throwable ex) {
			Log.e("Error", "Unhandled exception: " + ex.getMessage());
			Toast.makeText(getApplicationContext(), R.string.app_fatalError, Toast.LENGTH_LONG).show();
			System.exit(1);
		}
	});

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Android rotate animation

21 12 2013

Here is how to make view infinetely rotate around its center:

1. Define animation in xml

Put this file in /res/anim:

<?xml version="1.0" encoding="utf-8"?>
<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2500"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:repeatMode="restart"
    android:toDegrees="360" >

</rotate>

2. Load animation in java file

I load it in onCreate and keep it as a class field. Thanks to that I can access rotateAnim field to start or stop animation:

Animation rotateAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate);

3. Start / stop animation on view

Here is how to start and stop animation:

view.startAnimation(rotateAnimation);
view.clearAnimation();

Did I help you?
I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!








%d bloggers like this: