ViewAnimator (Android)

August 26, 2011 § 1 Comment

Sometimes you want to change content of your activity during some manipulation (it could tap on screen, some gesture or button click). If you have TextView and you can change text it is really easy to do. The same situation is with an image of ImageView. But sometimes the change is more complicated:

  • Change view to another view (same or different type)
  • Have animation during changing the content

In this case you can set visibility property on one view to View.GONE and to VIEW.VISIBLE to another. You should manage animation as well. But there is better solution – ViewAnimator.

ViewAnimator is ViewGroup. Actually it is extended from FrameLayout. So it could contain other views. But at any moment ViewAnimator can show no more than one view. We can ask ViewAnimator to switch to another view by calling showNext(), showPrevious() as well as setDisplayedChild(viewIndex) methods. And ViewAnimator is absolutely indifferent what kind of view it contains.

ViewAnimator would have another name if it was not be able to animate view changes. You can set in and out animation in xml or calling setInAnimation(animation), setOutAnimation(animation) methods.

That is it. It is really easy. Here is example. I set ViewAnimator in xml layout file. Add three child views to it. Then in java file I switch view when user touch screen. Moreover I create 2 alpha animation objects and attach it to the container (ViewAnimator). You can make animation in xml as well but to save a space I set it in code.

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
	<ViewAnimator
		android:id="@+id/container"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content">
		<ImageView
			android:id="@+id/image"
			android:src="@drawable/scarlett"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content">
		</ImageView>
		<Button
			android:id="@+id/button"
			android:text="This is my button"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content">
		</Button>
		<TextView
			android:id="@+id/text"
			android:text="This is simple text"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content">
		</TextView>
	</ViewAnimator>
</LinearLayout>
ViewAnimationActivity.java
public class ViewAnimationActivity extends Activity {
    ViewAnimator mContainer;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        initContainer();
    }

    private void initContainer() {
    	mContainer = (ViewAnimator)findViewById(R.id.container);

    	Animation inAnim = new AlphaAnimation(0, 1);
    	inAnim.setDuration(1000);
    	Animation outAnim = new AlphaAnimation(1, 0);
    	outAnim.setDuration(1000);

    	mContainer.setInAnimation(inAnim);
    	mContainer.setOutAnimation(outAnim);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    	if(event.getAction() == MotionEvent.ACTION_UP) {
    		mContainer.showNext();
    	}
    	return true;
    }
}

Note: in and out animations start at the same time. So if you want them to started in sequence you should set start offset – setStartOffset(long milliseconds).

ViewAnimator has 2 subclasses:

If you want views to be changed periodically you should use ViewFlipper. You don’t have to implement any timers. Just set interval by calling setFlipInterval() and then startFlipping() on ViewFlipper instance. You can set in on xml layout file with no need to write code.

<ViewFlipper
	android:id="@+id/flipper"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:flipInterval="1000"
	android:autoStart="true">
</ViewFlipper>

ViewSwitcher contains only 2 views and switch between them. You can use ViewFactory to create them

mContainer.setFactory(new ViewFactory() {
	public View makeView() {
		double random = Math.random();
		TextView view = new TextView(ViewAnimationActivity.this);
		view.setText(String.valueOf(random));
		return view;
	}
});

Factory creates 2 objects immediately after it was set to ViewSwitcher instance. After it makeView() method is not called. So there are only 2 views in the container. I don’t see the reason to use the class. ViewAnimator can cope with the same task.

MMS in Android. Part 2. Working with MMS storage

August 15, 2011 § 24 Comments

Getting list of MMS from the storage

Multimedia Message consists of MMS and MMParts. First contains message information (date, threadId, message box etc). Lasts contain content (text, images, video, audio). To get whole MMS data we must get MMS and then retrieve all MMS Parts of that message.

  • Getting MMS
     context.getContentResolver().query(
        Uri.parse("content://mms"),
        new String[] {"_id", "date", "msg_box", "read", "sub", "thread_id"},
        null,
        null,
        "date");

    Here we have queried all mms. If we want to get all messages from/to certain address we must specify thread_id and put third parameter like this “thread_id=3″ for recipient with threadId = 3.

  • Retrieving MMS Parts
     String where = "mid"+ " = '" + messageId + "'";
    context.getContentResolver().query(
        Uri.parse("content://mms/part"),
        new String[] {"_id", "ct", "_data", "text", "cl"},
        where,
        null,
        null);

    Here messageId is id of message at content://mms uri.

Inserting/updating/deleting mms data to/at/from storage

To insert MMS we should:

  • Insert message
    ContentValues values = new ContentValues();
    values.put("thread_id", threadId);
    values.put("date", date/1000);
    values.put("read", true); //read status
    values.put("sub", text); //mms subject
    values.put("msg_box", 4); //message box. in this case outbox
    Uri mmsUri = context.getContentResolver().
                 insert(Uri.parse("content://mms"), values);
  • Insert part
    ContentValues mmsPartValue = new ContentValues();
    mmsPartValue.put(MMS_PART_CONTENT_TYPE, mime); //mime; for example image/jpeg
    //id of MMS at content://mms
    String messageId = mmsUri.getLastPathSegment().trim();
    Uri partUri = Uri.parse("content://mms/" + messageId + "/part");
    Uri mmsPartUri = context.getContentResolver().insert(partUri, mmsPartValue);
  • Add data to part
    //mmsPartUri - uri to added mms part
    //uriToData - uri to content you want to add to mms part
    (uri of amedia file in the storage, mostly in the gallery).
    OutputStream os = context.getContentResolver().openOutputStream(mmsPartUri);
    InputStream is = context.getContentResolver().openInputStream(uriToData);
    byte[] buffer = new byte[256];
    for (int len = 0; (len = is.read(buffer)) != -1; ) {
        os.write(buffer, 0, len);
    }

Delete and update requests have absolutely the same principle.

MMS in Android. Part 1. Sending and receiving MMS

August 13, 2011 § 5 Comments

Judging by forums questions (and my own experience) sending mms programmatically is quite complicate issue. That is because there is no documented API for it. To start working with mms we will need to use some undocumented classes. Happily Android OS is open source project. So we can download some classes from http://android.git.kernel.org/ and use it in our code. I know that it is not the best solution (while in future version this code could be modified) but it is the only one if you want to work with mms from your code.

Before starting working with mms I would recommend get to touch with Multimedia Messaging Service Encapsulation Protocol documentation.

There are different Multimedia Message Types. Each of them has own purpose. Here is the most important ones that we will use below:

  • “m-send-req” – sending message
  • “m-notification-ind” – provide the MMS Client with information about a MM located at the recipient MMS Proxy-Relay and waiting for retrieval. Client after that should fetch MM. It doesn’t contain Message Body but only Header.
  • “m-delivery-ind” – delivery report of MM

Here are inner classes that we can use.

We will need (you can copy the whole file or “borrow part of them”):

  • android.provider.Telephony
  • com.google.android.mms.ContentType
Files from com.google.android.mms.pdu package:
  • PduHeaders – contains map of headers
  • PduBody – includes PduParts
  • PduPart – consists of part header, data uri, part data
  • GenericPdu – wraps PduHeader
  • MultimediaMessagePdu – extends GenericPdu, adds PduBody to it
  • SendReq – extends MultimediaMessagePdu, represents sending request – “m-send-req” type
  • DeliveryInd – extends GenericPdu , represents delivery report – “m-delivery-ind” type
  • NotificationInd –  extends GenericPdu , represents notification about incoming message (that is stored in MMBOX and should be retrieved from there) – “m-notification-ind” type
  • PduComposer – translate Pdu to byte[]
  • PduParser – translate byte[] to Pdu
  • PduPersister – stores MM in storage.

Ok, here are the tasks to implement comprehencive mms support for your application:

  • Sending mms
  • Receiving delivery/read report
  • Receiving incoming mms
  • Getting list of mms from storage
  • Inserting/updating/deleting mms data to/at/from storage

First of all you should understand what points from above list you are going to implement.

So, in order…

Sending mms

MMS unlike SMS is send through http connection. Actually it is just request to mmsc (Multimedia Message System Center).

First of all we have to request Connectivity Service to enable mms:

  ConnectivityManager mConnMgr = 
        (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
  int result = mConnMgr.startUsingNetworkFeature(
        ConnectivityManager.TYPE_MOBILE, "enableMMS");

If result is 0 (APN_ALREADY_ACTIVE) we can start sending MMS. But likely it is not. In that case we have to wait while it become ACTIVE. We can register broadcast receiver that listens “ConnectivityManager.CONNECTIVITY_ACTION” action. At onReceive() method of our receiver we check whether connectivity manager is ready to send mms:

    String action = intent.getAction();
    if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
        return;
    }

    NetworkInfo mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
        ConnectivityManager.EXTRA_NETWORK_INFO);

    // Check availability of the mobile network.
    if ((mNetworkInfo == null) ||
        (mNetworkInfo.getType() != ConnectivityManager.TYPE_MOBILE_MMS)) {
        return;
    }

    if (!mNetworkInfo.isConnected()) {
        return;
    } else {
	//send mms
    }

How to send mms when we are ready to do it? We can watch sources of standard messaging client that are open as almost everything in Android. To implement the same solution is not too complicated but quite intricate.

Or we can use API that was designed by Nokia that encapsulates all complexity. You can find more information and links here.

But none of the solutions works with Samsung (at list Galaxy S and Galaxy Tab). It throws exception during http request to mmsc. It seems that Samsung have changed some network properties. I have not yet figured out how to cope with it.

Receiving delivery/read report

We should implement BroadcastReceiver with follow intent filter:

    <intent-filter>
        <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
        <data android:mimeType="application/vnd.wap.mms-message" />
    </intent-filter>

In onReceive() we get pdu byte[] from intent and transform it in GenericPdu object via PduParser:

    byte[] pushData = intent.getByteArrayExtra("data");
    PduParser parser = new PduParser(pushData);
    GenericPdu pdu = parser.parse();

Than we get the pdu’s type and check whether it delivery/read report:

    int type = pdu.getMessageType();
    if(type == PduHeaders.MESSAGE_TYPE_DELIVERY_IND) {
        String messageId = new String(((DeliveryInd)pdu).getMessageId());
        //Notify app that mms with messageId was delivered
    }

Ok, here we can make a try to update data in storage. But it is not necessary. Standard messenger will do it for us. While device is not rooted it is impossible to delete or shut down standard client. And it makes our way a bit easier.

But if we want to make it anyway we get delivery status and make appropriate update of storage:

    int status = ((DeliveryInd)pdu).getStatus();
    if(status == PduHeaders.STATUS_RETRIEVED) {
        //message delivered. update storage
    }

There could be follow statuses:

  • PduHeaders.STATUS_EXPIRED
  • PduHeaders.STATUS_RETRIEVED
  • PduHeaders.STATUS_REJECTED
  • PduHeaders.STATUS_DEFERRED
  • PduHeaders.STATUS_UNRECOGNIZED
  • PduHeaders.STATUS_INDETERMINATE
  • PduHeaders.STATUS_FORWARDED
  • PduHeaders.STATUS_UNREACHABLE
The meaning is clear from it name. We can define how to act in each case. For example that’s how we can save update if the status ==  STATUS_RETRIEVED (delivered):
    ContentValues values = new ContentValues();
    values.put("msg_box", 2); //type 2 == MESSAGE_TYPE_SENT
    String where = "_id" + " = '" + messageId + "'";
    context.getContentResolver().update(
            Uri.parse("content://mms"), values, where, null);

Receiving incoming MMS

When we have new inbox MMS we receive (in our broadcast receiver that is described above) pdu that has “m-notification-ind” type. But this pdu doesn’t contain multimedia data but only location at MMBOX of our mmsc where the content is situated. And we have to download it from that location.

Actually standard message client will do it for us. I will not write how to do it by our own. It is complicated process that take a lot of code at dozen classes. You can follow the path of tasks starting from com.android.mms.transaction.PduReceiver onReceive() method. If you really need the solution you can always use the code from that package.

All the mess with Streams in Java

August 7, 2011 § 1 Comment

This post is like a summary for me to remember. I have always easily used I/O Streams realizing that there are plenty of them but didn’t know the differences. So I decided to clarify it for me.

First of all streams differ from “destination”. Input Streams are used to read data from local files, networks, other programs etc. And Output Streams are for writing the data to a destination. Ok, it is obvious.

Secondly there are byte and character streams. As follows from its name byte streams operates with 8-bit bytes. All byte streams are descendants of InputStream or OutputStream abstract classes. It is really easy to recognise them while they have names like FileInputStream, or ByteArrayOutputStream.

Character streams are intended to work with characters (16-bit code units). Character streams descent from Reader and Writer abstract classes. They are also easy recognizable by Reader/Writer suffix in classes names (FileReader, CharArrayWriter etc).

Character streams are based on byte streams. It is just high level solution to send/receive character data. All the data are transferred in bytes. But there should be something to translate character data to bytes. Here are “byte-to-character” bridges classes – InputStreamReader and OutputStreamReader. They read/write characters from/to bytes using specified charset that maps bytes to 16-bit Unicode units. How it is done?

You can notice that byte streams as well as character streams have method read/write that works with int. In case of byte stream int value include just 8 bit data. It could be 0-127 or -1 as end of file flag. Character stream works with 2-bytes data (so int data from read/write methods contains 2 bytes in it). And every time character stream read character data InputStreamReader request InputStream to read 2 bytes, then translate it to character code and pass to Character stream.

Each time you call read/write it request/send new chank of data. And it could be not so efficient. You can gain performance by reading to a buffer more data at a time and working with the buffer. Here are BufferedInputStream, BufferedOutputStream, BufferedReader and BufferedWriter classes for that.

So follow snippet

new BufferedReader(
    new InputStreamReader(
        socket.getInputStream()));

now looks quite logical. Yesterday I couldn’t explain why we should open 3 streams.

Thirdly streams could be differed by data they transfer. There are data streams that supports primitive data (boolean, char, short, int, long, float and double) and String values – DataInputStream and DataOutputStream. And there are object streams that use serialization and represented by ObjectInputStream and ObjectOutputStream. Such classes make work with data (primitive or object) easier.

More details you can find in Oracle tutorial I’ve used.

Primitive types in Maps (Android)

August 6, 2011 § 1 Comment

Maps are very useful data structures. But there is one shortcoming. Maps can’t handle with primitive types. It works with generics that must be some reference type (object).

Sure autoboxing works well and it is really easy to use as primitive type. But if int takes 4 bytes Integer allocation uses 16 bytes. And nobody wants to use 4 times more memory.

Happily in Android there are 3 classes in android.util package:

The only shortcoming I have faced is lack of Map’s keySet() method analog that returns set of the map’s keys. In the case of SparseArray you should iterate through it manually to retrieve key set.

Bitmaps in Android

August 3, 2011 § Leave a comment

If you work with Bitmaps in Android (pre Honeycomb) it is extremely easy to receive

OutofMemoryError: bitmap size exceeds VM budget

As you know all application have memory (heap size) limits. For some devices it is 16Mb, for others – 32 or 64Mb.

16Mb is not so much but in most cases (until you load 3264×2448 ARGB8888 bitmap) is enough for application. But why working with even small bitmaps OutOfMemory error occurs.

The reason of the error is Bitmap instances are stored not in managed heap as all other objects but in native heap. And memory limit includes the sum of managed and native heap sizes. And at least one reason why native memory is not called “managed” is a garbage collector can’t remove objects from it. You must do it by your own by calling recycle() method of your bitmap instance.

The recycle() method cleans the memory occupied by the object in native heap. It is done immediately after calling recycle(). And after that you shouldn’t use bitmap instance anymore. Overwise you will get

java.lang.RuntimeException: Canvas: trying to use a recycled bitmap

Here is snippet with example how to recycle bitmaps:

    Bitmap originalBitmap = BitmapFactory.decodeFile(path, options);
    Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap,
                                  width, height, true);
    originalBitmap.recycle();

In the example we decoded bitmap and then scaled it. But actually we have 2 bitmap objects in native heap. So we should recycle the firs on (originalBitmap).

But if you want to load really big image you can scale it during decoding and safe plenty of memory in the heap.
First of all you should know the real size of the image. You can do it by:

    BitmapFactory.Options preOptions = new BitmapFactory.Options();
    preOptions.inJustDecodeBounds = true;
    Bitmap originalBitmap = BitmapFactory.decodeFile(path, preOptions);
    int width = preOptions.outWidth;
    int height = preOptions.outHeight;

At this snippet we don’t actually create object in heap. We set inJustDecodeBounds flag for BitmapFactory.Options instance. This flag means that image data will be retrieved without creating the bitmap instance (and at this moment originalBitmap is null). After that we get actual width and height of the image.
Then you can set scale parameters to BitmapFactory.Options instance. But this scale parameter should be multiple of 2:

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inTempStorage = new byte[16 * 1024];
    options.inPreferredConfig = Config.RGB_565;

    int scale = preOptions.outHeight/height;
    int sizeSample = 2*(scale/2 + 1);
    options.inSampleSize = sizeSample; 

    originalBitmap = BitmapFactory.decodeFile(path, options);

Here we calculated the scale that is multiple of 2 and close to the size we want to have. Then we set it to options.inSampleSize and decode the file. Besides that we set temp storage for decoding (16K) as well as RGB565 config. The last reduces decoded bitmap size 2 times relative to ARGB8888 config.

Working with contacts

July 28, 2011 § Leave a comment

Someday I met a problem concerned retrieving data from Contact list in Android.

I had to get list of contacts comprising name and phone number without external apps. Sure there are plenty of tutorials and it is not hard to get the data. But the problem was all tutorials, answers in StackOverFlow, articles from developer.android.com gave solution that took 3-8 seconds to retrieve 100 contacts while it query Content Provider for every single contact to read its phone number. It was not an option for me. I couldn’t afford users to wait so long.

While I hadn’t coped to find solution in Internet I started to experiment with android.provider.ContactsContract. Hopefully I’ve found that I searched for.

But before the practise I will give a bunch of theory.

All the Contact data in Android have three level hierarchy (three-tier-model):

  • A row in the ContactsContract.Data table can store any kind of personal data, such as a phone number or email addresses. The set of data kinds that can be stored in this table is open-ended. There is a predefined set of common kinds, but any application can add its own data kinds.
  • A row in the ContactsContract.RawContacts table represents a set of data describing a person and associated with a single account (for example, one of the user’s Gmail accounts).
  • A row in the ContactsContract.Contacts table represents an aggregate of one or more RawContacts presumably describing the same person. When data in or associated with the RawContacts table is changed, the affected aggregate contacts are updated as necessary
Actually all the data is in Data layer. Other levels are abstraction that structures the way to that data.
So tutorials suggested:
  1. to get Contact list querying ContactsContract.Contacts.CONTENT_URI that is the most abstract level
  2. iterate through contacts and query ContactsContract.CommonDataKinds.Phone.CONTENT_URI to retrieve phone number list for each contact (it is a bit more specific abstraction layer)

All this two steps asks data from abstraction that based on third layer – Data (ContactsContract.Data). But the problem is the structure of the Data table is really confusing and there is no description of it. It is easy to explain while the table is universal and contain data about everything (names, emails, groups, phone numbers etc). And there are a lot of columns that in one case could contain group name but in another email or phone number.

It took a bit time to analyze the structure and I got the solution.

So to get cursor with names and phones you just should make such query:

public static Cursor getContactCursor(Context context) {
      String WHERE_CONDITION = ContactsContract.Data.MIMETYPE + " = '" + 
          ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'";
      String[] PROJECTION = {"_id", ContactsContract.Data.DISPLAY_NAME,
                                        ContactsContract.Data.DATA1};
      String SORT_ORDER = ContactsContract.Data.DISPLAY_NAME;

      return context.getContentResolver().query(
        	ContactsContract.Data.CONTENT_URI,
        	PROJECTION,
                WHERE_CONDITION,
                null,
                SORT_ORDER);
  }

The first column is id of the data row. The second is Contact name and the last on is its phone number. It is sorted by name. If contact has more than one phone number there would be several rows (one for each number). If you need to group them you can do it programmatically and it takes much less time than querying each contact separately.


									
Follow

Get every new post delivered to your Inbox.