My experience writing a program for Android



Hello!
In this article I would like to talk about writing a program for the Android platform to send animated messages. It will be more of a little story of creation than a deepening in programming.
It was about two months ago, I thought a lot about what can now be written so that it is in demand, users liked it and was original. Considering how cluttered the market is, even coming up with an idea seemed complicated to me. There were already all kinds of system utilities, hundreds of animated wallpapers, programs for cameras, clients for social networks, games and even antiviruses (which for some reason are wildly popular!). Of course, most of all there is the Chinese city, which with the advent of the new market has become less noticeable.

The idea came quite suddenly and pushed me to her sitelivetyping.ru . “And why not,” I thought, and began to think about how it would look and how to write it. Who is too lazy to go to the site, I’ll explain that the point is that the user writes the text, and then he is generated in a gif file, displaying the writing process, including all changes. It turns out pretty funny, you can write a message with one meaning, then wipe everything and write with the exact opposite. In general, the user is limited only by his imagination.
Someone will say that the idea of ​​the program is not very ... because many Android phones do not know how to view animated gifs using the built-in tools. And partly it will be right, since judging by the reviews on the Internet, many Androids lack this support. But, as it turned out, my phone with firmware 2.3.3 can do this, which inspired me with hope that in the future manufacturers will add support to all devices. Maybe a little optimistic, but at the office. According to Android should be able to decode the hyphae (but does not say which one).

Development


Program core

The first difficulty was that the generated text must be exactly the same formatted as the original. There were two options:

  1. Make a server to send all the text typed by the user, field size, font size and color, generate a gif and return the link or the file itself.
  2. Generate everything on the client.

The second option was immediately chosen, because I am not friends with the web, and it does not need server costs.
In order to make GIF animation, you had to first generate all the frames, and then put them together in a heap. Thinking that this operation would work faster in si rather than Java, I rummaged through the internet and found the source of the class I needed , which I successfully compiled with the NDK. This class allowed adding a frame as an array of pixels obtained from an instance of the Bitmap class, generating an animated GIF file at the end.
Just as written in the example at the link:

static 
{
     System.loadLibrary("gifflen");
} 
....
public native int Init(String gifName, int w, int h, int numColors, int quality, int frameDelay);
public native void Close();
public native int AddFrame(int[] inArray);
....
// Filename, width, height, colors, quality, frame delay
if(Init("/sdcard/foo.gif", width, height, 256, 100, 4) != 0)
{
     Log.e("gifflen", "Init failed");
}
int[] pixels = new int[width*height];
// bitmap should be 32-bit ARGB, e.g. like the ones you get when decoding
// a JPEG using BitmapFactory
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// Convert to 256 colors and add to foo.gif
AddFrame(pixels);
Close();

The next task was to figure out how to render the typed text in Bitmap. Digging into the Android API, the StaticLayout class was found, which allows you to draw this text using Paint in Canvas, which in turn is in Bitmap. It all looks something like this:

Canvas canvas = new Canvas();
TextPaint paint = new TextPaint(Paint.LINEAR_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
Bitmap bitmap;
paint.setStyle(Paint.Style.FILL);
paint.setColor(fontColor);
paint.setTextSize((int) (fontSizeDP * mDensityScale + 0.5f));
paint.setAntiAlias(true);
paint.setTypeface(font);
paint.setTextAlign(Align.LEFT);
StaticLayout[] layoutTexts = new StaticLayout[mLiveTypeStringArray.size()];
for(int i = 0; i < layoutTexts.length; i++)
{
		layoutTexts[i] = new StaticLayout(mLiveTypeStringArray.get(i), paint, (int) (gifWidthDP * mDensityScale + 0.5f), Alignment.ALIGN_NORMAL, 1, 1, true);
		if(gifHeight < layoutTexts[i].getHeight())
			gifHeight = layoutTexts[i].getHeight();
}
if(gifHeight == 0)
	return 0;
bitmap = Bitmap.createBitmap((int) (gifWidthDP * mDensityScale + 0.5f), gifHeight, Bitmap.Config.RGB_565);
canvas.setBitmap(bitmap);
for(int i = 0; i < layoutTexts.length; i++)
{
		canvas.drawColor(backColor);
		layoutTexts[i].draw(canvas);
		gifEncoder.addFrame(bitmap);
}

Excellent! The typed text, or rather each of its changes, was rendered into Bitmaps, from which the gif file was collected.
Then the following problem appeared. The gif files were huge! On average, GIFs up to 200 frames took 3-5 mb. This is a lot, especially if you need to send it from a mobile device. Then I noticed that on livetyping such gifs take up much less (30-50 kb) and asked the author how he achieved such a result. The answer was the Gifsicle library , which could very strongly and qualitatively optimize GIFs. A similar result was achieved due to the preservation of not every individual frame, but only the difference between them, which was ideally suited for us to save animated text.
Then I started porting Gifsicle to Android using the NDK, which soon ended successfully.
Who cares, here is my Android.mk:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := malloc
LOCAL_SRC_FILES := fmalloc.c dmalloc.c
LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := -DFPM_ARM -ffast-math -O3
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := gifwrite
LOCAL_SRC_FILES := ungifwrt.c
LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := -DFPM_ARM -ffast-math -O3
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := gifopt
LOCAL_SRC_FILES := clp.c giffunc.c gifread.c gifunopt.c \
		merge.c optimize.c quantize.c support.c xform.c \
		gifsicle.c
LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := -DFPM_ARM -ffast-math -O3
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog
LOCAL_STATIC_LIBRARIES := gifwrite malloc
include $(BUILD_SHARED_LIBRARY)

Imagine my surprise when I saw that it was not working correctly on a mobile device. The generation and optimization of the same GIF file each time gave a different result. Very different, the spread was from 50kb to 2 mb. Then I began to compile again, recompile with different parameters, look for a memory leak, etc ... anything to explain this phenomenon. But I did not find anything. So two weeks passed.
One beautiful morning, I realized that it might not be Gifsicle that could fail, because its author also could not understand what the problem was, but the first library (class) that generates GIFs. I turned off the optimization and looked at the result: the files were almost always the same size, only sometimes they differed by 1-2kb. Strange, but not fatal. Not wanting to poke around in someone else's raw si code, I found a similarlibrary on Java ME, and ported it to Android. I also noticed for myself the striking similarity of Java ME and Android API - many almost identical functions (I had no business with ME before). Now everything has become normal.

But again, not for long ... it turned out that after optimization when playing a GIF file on my Android device using the standard Image View'er, sometimes terrible color glitches and frames disappear. At the same time, on the computer the same file was viewed perfectly. I thought that this was all due to poor viewer support for LZW compression and disabled it in the Gifsicle sorts. Now everything really became good, although the files began to occupy a little more than before.

Interface

Until that moment, I spent about a month. For the second month I had to write the program interface. I always wanted to use some kind of Android UI pattern, of all the possible ones I chose Dashboard. Since "everything is already written before us," I downloaded the source code for Google IO and took the code from there. It turned out something like this:


The window for writing a new message turned out like this:

You can view the written animated message or generate it as a gif animation, after which the “Share” button appears with the ability to send by email, mms, twitter, etc.

The height of the field for dialing was chosen so that on different screens the keyboard did not cover it. The smallest screens were banned, because there the keyboard takes up a lot of space. Of course, you could make a height, depending on the size of the screen, but ... it became laziness.

Then, settings were made based on the standard PreferenceActivity class:


As well as a list of my posts.
Only an array of texts (frames) in binary form is saved on the memory card. When viewing a message, it is possible to regenerate it by first changing the settings (font color and size, background color, animation speed).

Result


At first, two versions were planned: free and paid. Now only free is available, which is in the market for about 20 days. In the paid one, more fonts were planned, more font and background colors, more frame limitation - 500 (now 140). But, unfortunately, the success of the free version leaves much to be desired: there are 583 installations in total, 227 of which are active, that is, more than half of the downloaded have already been deleted. Apparently the idea did not work =)
Therefore, the development of the program has been suspended and is unlikely to continue.

That's all, thank you all for your attention! I will answer your questions in the comments. I also apologize for possible errors.

Update: Several mini-reviews on foreign sites:
www.androidapplog.com/2011/09/android-app-reviews/animado-animated-messaging-app-review
www.addictivetips.com/mobile/animado-for-android-share-animated-text-messages-as-gif-files

Who cares about the link to the market .

Also popular now: