Java tutorial
/******************************************************************************* * Software Name : RCS IMS Stack * * Copyright (C) 2010 France Telecom S.A. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.orangelabs.rcs.ri.messaging.chat.single; import com.gsma.services.rcs.Geoloc; import com.gsma.services.rcs.RcsServiceException; import com.gsma.services.rcs.chat.ChatLog.Message; import com.gsma.services.rcs.chat.ChatLog.Message.Content; import com.gsma.services.rcs.chat.ChatService; import com.gsma.services.rcs.chat.OneToOneChatListener; import com.gsma.services.rcs.contact.ContactId; import com.orangelabs.rcs.api.connection.ConnectionManager.RcsServiceName; import com.orangelabs.rcs.api.connection.utils.ExceptionUtil; import com.orangelabs.rcs.api.connection.utils.RcsFragmentActivity; import com.orangelabs.rcs.ri.R; import com.orangelabs.rcs.ri.utils.ContactUtil; import com.orangelabs.rcs.ri.utils.LogUtils; import com.orangelabs.rcs.ri.utils.RcsContactUtil; import com.orangelabs.rcs.ri.utils.Utils; import android.content.Context; import android.content.pm.ActivityInfo; import android.database.Cursor; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.text.format.DateUtils; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.CursorAdapter; import android.widget.ListView; import android.widget.TextView; import java.util.Arrays; import java.util.Set; /** * List chats from the content provider * * @author YPLO6403 */ public class SingleChatList extends RcsFragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> { // @formatter:off private static final String[] PROJECTION = new String[] { Message.BASECOLUMN_ID, Message.CONTACT, Message.CHAT_ID, Message.CONTENT, Message.MIME_TYPE, Message.TIMESTAMP }; // @formatter:on /** * One to one chat are raws where chat_id equals contact. */ private static final String WHERE_CLAUSE_GROUPED = Message.CHAT_ID + "=" + Message.CONTACT + " GROUP BY " + Message.CONTACT; private static final String SORT_ORDER = Message.TIMESTAMP + " DESC"; private ListView mListView; private ChatService mChatService; private boolean mOneToOneChatListenerSet = false; private ChatListAdapter mAdapter; private Handler mHandler = new Handler(); private static final String LOGTAG = LogUtils.getTag(SingleChatList.class.getSimpleName()); /** * The loader's unique ID. Loader IDs are specific to the Activity in which they reside. */ private static final int LOADER_ID = 1; /** * List of items for contextual menu */ private static final int CHAT_MENU_ITEM_DELETE = 1; private static final int CHAT_MENU_ITEM_OPEN = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* Set layout */ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); setContentView(R.layout.chat_list); mChatService = getChatApi(); mListView = (ListView) findViewById(android.R.id.list); TextView emptyView = (TextView) findViewById(android.R.id.empty); mListView.setEmptyView(emptyView); registerForContextMenu(mListView); mAdapter = new ChatListAdapter(this); mListView.setAdapter(mAdapter); /* * Initialize the Loader with id '1' and callbacks 'mCallbacks'. */ getSupportLoaderManager().initLoader(LOADER_ID, null, this); } @Override protected void onDestroy() { super.onDestroy(); if (mChatService == null || !mOneToOneChatListenerSet) { return; } try { mChatService.removeEventListener(mOneChatListener); } catch (RcsServiceException e) { Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e)); } } /** * Single chat list adapter */ private class ChatListAdapter extends CursorAdapter { private LayoutInflater mInflater; /** * Constructor * * @param context Context */ public ChatListAdapter(Context context) { super(context, null, 0); mInflater = LayoutInflater.from(context); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final View view = mInflater.inflate(R.layout.chat_one2one_list_item, parent, false); view.setTag(new SingleChatListItemViewHolder(view, cursor)); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { final SingleChatListItemViewHolder holder = (SingleChatListItemViewHolder) view.getTag(); long date = cursor.getLong(holder.columnTimestamp); holder.dateText.setText(DateUtils.getRelativeTimeSpanString(date, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE)); String number = cursor.getString(holder.columnContact); String displayName = RcsContactUtil.getInstance(context).getDisplayName(number); holder.contactText.setText(getString(R.string.title_chat, displayName)); String content = cursor.getString(holder.columnContent); String mimetype = cursor.getString(holder.columnMimetype); String text = ""; if (Message.MimeType.GEOLOC_MESSAGE.equals(mimetype)) { Geoloc geoloc = new Geoloc(content); String label = geoloc.getLabel(); if (label == null) { text = geoloc.getLatitude() + "," + geoloc.getLongitude(); } else { text = label + "," + geoloc.getLatitude() + "," + geoloc.getLongitude(); } } else { if (Message.MimeType.TEXT_MESSAGE.equals(mimetype)) { text = content; } } holder.contentText.setText(text); holder.contentText.setVisibility(View.VISIBLE); } } /** * A ViewHolder class keeps references to children views to avoid unnecessary calls to * findViewById() or getColumnIndex() on each row. */ private class SingleChatListItemViewHolder { int columnContact; int columnContent; int columnMimetype; int columnTimestamp; TextView contactText; TextView contentText; TextView dateText; SingleChatListItemViewHolder(View base, Cursor cursor) { columnContact = cursor.getColumnIndexOrThrow(Message.CONTACT); columnContent = cursor.getColumnIndexOrThrow(Message.CONTENT); columnMimetype = cursor.getColumnIndexOrThrow(Message.MIME_TYPE); columnTimestamp = cursor.getColumnIndexOrThrow(Message.TIMESTAMP); contactText = (TextView) base.findViewById(R.id.line1); contentText = (TextView) base.findViewById(R.id.line2); dateText = (TextView) base.findViewById(R.id.date); } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = new MenuInflater(getApplicationContext()); inflater.inflate(R.menu.menu_log, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_clear_log: /* Delete all one-to-one chat messages */ if (!isServiceConnected(RcsServiceName.CHAT)) { showMessage(R.string.label_service_not_available); break; } if (LogUtils.isActive) { Log.d(LOGTAG, "delete all one-to-one chat sessions"); } try { if (!mOneToOneChatListenerSet) { mChatService.addEventListener(mOneChatListener); mOneToOneChatListenerSet = true; } mChatService.deleteOneToOneChats(); } catch (RcsServiceException e) { showExceptionThenExit(e); } break; } return true; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); /* Check file transfer API is connected */ if (!isServiceConnected(RcsServiceName.CHAT)) { showMessage(R.string.label_service_not_available); return; } menu.add(0, CHAT_MENU_ITEM_OPEN, CHAT_MENU_ITEM_OPEN, R.string.menu_open_chat_session); menu.add(0, CHAT_MENU_ITEM_DELETE, CHAT_MENU_ITEM_DELETE, R.string.menu_delete_chat_session); } @Override public boolean onContextItemSelected(MenuItem item) { /* Get selected item */ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); Cursor cursor = (Cursor) (mListView.getAdapter()).getItem(info.position); String number = cursor.getString(cursor.getColumnIndexOrThrow(Message.CONTACT)); ContactId contact = ContactUtil.formatContact(number); if (LogUtils.isActive) { Log.d(LOGTAG, "onContextItemSelected contact=".concat(contact.toString())); } switch (item.getItemId()) { case CHAT_MENU_ITEM_OPEN: if (isServiceConnected(RcsServiceName.CHAT)) { /* Open one-to-one chat view */ startActivity(SingleChatView.forgeIntentToOpenConversation(this, contact)); } else { showMessage(R.string.label_continue_chat_failed); } return true; case CHAT_MENU_ITEM_DELETE: if (!isServiceConnected(RcsServiceName.CHAT)) { showMessage(R.string.label_delete_chat_failed); return true; } /* Delete messages for contact */ if (LogUtils.isActive) { Log.d(LOGTAG, "Delete messages for contact=".concat(contact.toString())); } try { if (!mOneToOneChatListenerSet) { mChatService.addEventListener(mOneChatListener); mOneToOneChatListenerSet = true; } mChatService.deleteOneToOneChat(contact); } catch (RcsServiceException e) { showExceptionThenExit(e); } return true; default: return super.onContextItemSelected(item); } } private OneToOneChatListener mOneChatListener = new OneToOneChatListener() { @Override public void onMessagesDeleted(final ContactId contact, Set<String> msgIds) { if (LogUtils.isActive) { Log.d(LOGTAG, "onMessagesDeleted contact=" + contact + " for message IDs=" + Arrays.toString(msgIds.toArray())); } mHandler.post(new Runnable() { public void run() { Utils.displayLongToast(SingleChatList.this, getString(R.string.label_delete_chat_success, contact.toString())); } }); } @Override public void onMessageStatusChanged(ContactId contact, String mimeType, String msgId, Content.Status status, Content.ReasonCode reasonCode) { } @Override public void onComposingEvent(ContactId contact, boolean status) { } }; @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { /* Create a new CursorLoader with the following query parameters. */ return new CursorLoader(this, Message.CONTENT_URI, PROJECTION, WHERE_CLAUSE_GROUPED, null, SORT_ORDER); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { /* A switch-case is useful when dealing with multiple Loaders/IDs */ switch (loader.getId()) { case LOADER_ID: /* * The asynchronous load is complete and the data is now available for use. Only now * can we associate the queried Cursor with the CursorAdapter. */ mAdapter.swapCursor(cursor); break; } /* The listview now displays the queried data. */ } @Override public void onLoaderReset(Loader<Cursor> loader) { /* * For whatever reason, the Loader's data is now unavailable. Remove any references to the * old data by replacing it with a null Cursor. */ mAdapter.swapCursor(null); } }