FileDocCategorySizeDatePackage
ChatView.javaAPI DocAndroid 1.5 API50960Wed May 06 22:42:46 BST 2009com.android.im.app

ChatView

public class ChatView extends android.widget.LinearLayout

Fields Summary
static final String[]
CHAT_PROJECTION
static final int
CONTACT_ID_COLUMN
static final int
ACCOUNT_COLUMN
static final int
PROVIDER_COLUMN
static final int
USERNAME_COLUMN
static final int
NICKNAME_COLUMN
static final int
TYPE_COLUMN
static final int
PRESENCE_STATUS_COLUMN
static final int
LAST_UNREAD_MESSAGE_COLUMN
static final String[]
INVITATION_PROJECT
static final int
INVITATION_ID_COLUMN
static final int
INVITATION_PROVIDER_COLUMN
static final int
INVITATION_SENDER_COLUMN
static final android.text.style.StyleSpan
STYLE_BOLD
Markup
mMarkup
android.app.Activity
mScreen
ImApp
mApp
SimpleAlertHandler
mHandler
android.database.Cursor
mCursor
private android.widget.ImageView
mStatusIcon
private android.widget.TextView
mTitle
android.widget.ListView
mHistory
android.widget.EditText
mEdtInput
private android.widget.Button
mSendButton
private android.view.View
mStatusWarningView
private android.widget.ImageView
mWarningIcon
private android.widget.TextView
mWarningText
private MessageAdapter
mMessageAdapter
private com.android.im.IChatSessionManager
mChatSessionMgr
private com.android.im.IChatSessionListener
mChatSessionListener
private com.android.im.IChatSession
mChatSession
private long
mChatId
int
mType
String
mNickName
String
mUserName
long
mProviderId
long
mAccountId
long
mInvitationId
private int
mPresenceStatus
private int
mViewType
private static final int
VIEW_TYPE_CHAT
private static final int
VIEW_TYPE_INVITATION
private static final int
VIEW_TYPE_SUBSCRIPTION
private static final long
SHOW_TIME_STAMP_INTERVAL
private static final int
QUERY_TOKEN
private QueryHandler
mQueryHandler
private RequeryCallback
mRequeryCallback
private android.widget.AdapterView.OnItemClickListener
mOnItemClickListener
private com.android.im.IChatListener
mChatListener
private Runnable
mUpdateChatCallback
private com.android.im.IContactListListener
mContactListListener
Constructors Summary
public ChatView(android.content.Context context, android.util.AttributeSet attrs)

        super(context, attrs);
        mScreen = (Activity) context;
        mApp = ImApp.getApplication(mScreen);
        mHandler = new ChatViewHandler();
    
Methods Summary
voidacceptInvitation()

        try {

            IImConnection conn = mApp.getConnection(mProviderId);
            if (conn != null) {
                // register a chat session listener and wait for a group chat
                // session to be created after we accept the invitation.
                registerChatSessionListener();
                conn.acceptInvitation(mInvitationId);
            }
        } catch (RemoteException e) {
            mHandler.showServiceErrorAlert();
        }
    
voidapproveSubscription()

        IImConnection conn = mApp.getConnection(mProviderId);
        try {
            IContactListManager manager = conn.getContactListManager();
            manager.approveSubscription(mUserName);
        } catch (RemoteException ex) {
            mHandler.showServiceErrorAlert();
        }
        mScreen.finish();
    
public voidbindChat(long chatId)

        if (mCursor != null) {
            mCursor.deactivate();
        }
        Uri contactUri = ContentUris.withAppendedId(Im.Contacts.CONTENT_URI, chatId);
        mCursor = mScreen.managedQuery(contactUri, CHAT_PROJECTION, null, null);
        if (mCursor == null || !mCursor.moveToFirst()) {
            if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
                log("Failed to query chat: " + chatId);
            }
            mScreen.finish();
            return;
        } else {
            mChatSession = getChatSession(mCursor);
            updateChat();
            registerChatListener();
        }
    
public voidbindInvitation(long invitationId)

        Uri uri = ContentUris.withAppendedId(Im.Invitation.CONTENT_URI, invitationId);
        ContentResolver cr = mScreen.getContentResolver();
        Cursor cursor = cr.query(uri, INVITATION_PROJECT, null, null, null);
        if (cursor == null || !cursor.moveToFirst()) {
            if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
                log("Failed to query invitation: " + invitationId);
            }
            mScreen.finish();
        } else {
            setViewType(VIEW_TYPE_INVITATION);

            mInvitationId = cursor.getLong(INVITATION_ID_COLUMN);
            mProviderId = cursor.getLong(INVITATION_PROVIDER_COLUMN);
            String sender = cursor.getString(INVITATION_SENDER_COLUMN);

            TextView mInvitationText = (TextView)findViewById(R.id.txtInvitation);
            mInvitationText.setText(mContext.getString(R.string.invitation_prompt, sender));
            mTitle.setText(mContext.getString(R.string.chat_with, sender));
        }

        if (cursor != null) {
            cursor.close();
        }
    
public voidbindSubscription(long providerId, java.lang.String from)

        mProviderId = providerId;
        mUserName = from;

        setViewType(VIEW_TYPE_SUBSCRIPTION);

        TextView text =  (TextView)findViewById(R.id.txtSubscription);
        String displayableAddr = ImpsAddressUtils.getDisplayableAddress(from);
        text.setText(mContext.getString(R.string.subscription_prompt, displayableAddr));
        mTitle.setText(mContext.getString(R.string.chat_with, displayableAddr));

        mApp.dismissChatNotification(providerId, from);
    
public voidblockContact()

        // TODO: unify with codes in ContactListView
        DialogInterface.OnClickListener confirmListener = new DialogInterface.OnClickListener(){
            public void onClick(DialogInterface dialog, int whichButton) {
                try {
                    IImConnection conn = mApp.getConnection(mProviderId);
                    IContactListManager manager = conn.getContactListManager();
                    manager.blockContact(mUserName);
                    mScreen.finish();
                } catch (RemoteException e) {
                    mHandler.showServiceErrorAlert();
                }
            }
        };

        Resources r = getResources();

        // The positive button is deliberately set as no so that
        // the no is the default value
        new AlertDialog.Builder(mContext)
            .setTitle(R.string.confirm)
            .setMessage(r.getString(R.string.confirm_block_contact, mNickName))
            .setPositiveButton(R.string.yes, confirmListener) // default button
            .setNegativeButton(R.string.no, null)
            .setCancelable(false)
            .show();
    
voidcancelRequery()

        if (mRequeryCallback != null) {
            if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
                log("cancelRequery");
            }
            mHandler.removeCallbacks(mRequeryCallback);
            mRequeryCallback = null;
        }
    
public voidcloseChatSession()

        if (mChatSession != null) {
            try {
                mChatSession.leave();
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        } else {
            // the conversation is already closed, clear data in database
            ContentResolver cr = mContext.getContentResolver();
            cr.delete(ContentUris.withAppendedId(Im.Chats.CONTENT_URI, mChatId),
                    null, null);
        }
        mScreen.finish();
    
public voidcloseChatSessionIfInactive()

        if (mChatSession != null) {
            try {
                mChatSession.leaveIfInactive();
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        }
    
private voidcloseSoftKeyboard()

        InputMethodManager inputMethodManager =
            (InputMethodManager)mApp.getSystemService(Context.INPUT_METHOD_SERVICE);

        inputMethodManager.hideSoftInputFromWindow(mEdtInput.getWindowToken(), 0);
    
voiddeclineInvitation()

        try {
            IImConnection conn = mApp.getConnection(mProviderId);
            if (conn != null) {
                conn.rejectInvitation(mInvitationId);
            }
            mScreen.finish();
        } catch (RemoteException e) {
            mHandler.showServiceErrorAlert();
        }
    
voiddeclineSubscription()

        IImConnection conn = mApp.getConnection(mProviderId);
        try {
            IContactListManager manager = conn.getContactListManager();
            manager.declineSubscription(mUserName);
        } catch (RemoteException ex) {
            mHandler.showServiceErrorAlert();
        }
        mScreen.finish();
    
public booleandispatchKeyEvent(android.view.KeyEvent event)

        userActionDetected();
        return super.dispatchKeyEvent(event);
    
public booleandispatchTouchEvent(android.view.MotionEvent ev)

        userActionDetected();
        return super.dispatchTouchEvent(ev);
    
public booleandispatchTrackballEvent(android.view.MotionEvent ev)

        userActionDetected();
        return super.dispatchTrackballEvent(ev);
    
public longgetAccountId()

        return mAccountId;
    
public longgetChatId()

        try {
            return mChatSession == null ? -1 : mChatSession.getId();
        } catch (RemoteException e) {
            mHandler.showServiceErrorAlert();
            return -1;
        }
    
private com.android.im.IChatSessiongetChatSession(android.database.Cursor cursor)

        long providerId = cursor.getLong(PROVIDER_COLUMN);
        String username = cursor.getString(USERNAME_COLUMN);

        IChatSessionManager sessionMgr = getChatSessionManager(providerId);
        if (sessionMgr != null) {
            try {
                return sessionMgr.getChatSession(username);
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        }
        return null;
    
private com.android.im.IChatSessionManagergetChatSessionManager(long providerId)

        if (mChatSessionMgr == null) {
            IImConnection conn = mApp.getConnection(providerId);
            if (conn != null) {
                try {
                    mChatSessionMgr = conn.getChatSessionManager();
                } catch (RemoteException e) {
                    mHandler.showServiceErrorAlert();
                }
            }
        }
        return mChatSessionMgr;
    
public com.android.im.IChatSessiongetCurrentChatSession()

        return mChatSession;
    
private android.database.CursorgetMessageCursor()

        return mMessageAdapter == null ? null : mMessageAdapter.getCursor();
    
public longgetProviderId()

        return mProviderId;
    
public java.lang.StringgetUserName()

        return mUserName;
    
public voidinsertSmiley(java.lang.String smiley)

        mEdtInput.append(mMarkup.applyEmoticons(smiley));
    
booleanisGroupChat()

        return Im.Contacts.TYPE_GROUP == mType;
    
static final voidlog(java.lang.String msg)


         
        Log.d(ImApp.LOG_TAG, "<ChatView> " +msg);
    
protected voidonFinishInflate()

        mStatusIcon     = (ImageView) findViewById(R.id.statusIcon);
        mTitle          = (TextView) findViewById(R.id.title);
        mHistory        = (ListView) findViewById(R.id.history);
        mEdtInput       = (EditText) findViewById(R.id.edtInput);
        mSendButton     = (Button)findViewById(R.id.btnSend);
        mHistory.setOnItemClickListener(mOnItemClickListener);

        mStatusWarningView = findViewById(R.id.warning);
        mWarningIcon = (ImageView)findViewById(R.id.warningIcon);
        mWarningText = (TextView)findViewById(R.id.warningText);

        Button acceptInvitation = (Button)findViewById(R.id.btnAccept);
        Button declineInvitation= (Button)findViewById(R.id.btnDecline);

        Button approveSubscription = (Button)findViewById(R.id.btnApproveSubscription);
        Button declineSubscription = (Button)findViewById(R.id.btnDeclineSubscription);

        acceptInvitation.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                acceptInvitation();
            }
        });
        declineInvitation.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                declineInvitation();
            }
        });

        approveSubscription.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                approveSubscription();
            }
        });
        declineSubscription.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                declineSubscription();
            }
        });

        mEdtInput.setOnKeyListener(new OnKeyListener(){
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    switch (keyCode) {
                        case KeyEvent.KEYCODE_DPAD_CENTER:
                            sendMessage();
                            return true;

                        case KeyEvent.KEYCODE_ENTER:
                            if (event.isAltPressed()) {
                                mEdtInput.append("\n");
                                return true;
                            }
                    }
                }
                return false;
            }
        });

        mEdtInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (event != null) {
                    if (event.isAltPressed()) {
                        return false;
                    }
                }

                sendMessage();
                return true;
            }
        });

        // TODO: this is a hack to implement BUG #1611278, when dispatchKeyEvent() works with
        // the soft keyboard, we should remove this hack.
        mEdtInput.addTextChangedListener(new TextWatcher() {
            public void beforeTextChanged(CharSequence s, int start, int before, int after) {
            }

            public void onTextChanged(CharSequence s, int start, int before, int after) {
                //log("TextWatcher: " + s);
                userActionDetected();
            }

            public void afterTextChanged(Editable s) {
            }
        });

        mSendButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                sendMessage();
            }
        });
    
public voidonPause()

        Cursor cursor = getMessageCursor();
        if (cursor != null) {
            cursor.deactivate();
        }
        cancelRequery();
        if (mViewType == VIEW_TYPE_CHAT && mChatSession != null) {
            try {
                mChatSession.markAsRead();
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        }
        unregisterChatListener();
        unregisterForConnEvents();
        unregisterChatSessionListener();
    
public voidonResume()

        if (mViewType == VIEW_TYPE_CHAT) {
            Cursor cursor = getMessageCursor();
            if (cursor == null) {
                startQuery();
            } else {
                requeryCursor();
            }
            updateWarningView();
        }
        registerChatListener();
        registerForConnEvents();
    
voidregisterChatListener()

        if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
            log("registerChatListener");
        }
        try {
            if (mChatSession != null) {
                mChatSession.registerChatListener(mChatListener);
            }
            IImConnection conn = mApp.getConnection(mProviderId);
            if (conn != null) {
                IContactListManager listMgr = conn.getContactListManager();
                listMgr.registerContactListListener(mContactListListener);
            }
            mApp.dismissChatNotification(mProviderId, mUserName);
        } catch (RemoteException e) {
            Log.w(ImApp.LOG_TAG, "<ChatView> registerChatListener fail:" + e.getMessage());
        }
    
voidregisterChatSessionListener()

        IChatSessionManager sessionMgr = getChatSessionManager(mProviderId);
        if (sessionMgr != null) {
            mChatSessionListener = new ChatSessionListener();
            try {
                sessionMgr.registerChatSessionListener(mChatSessionListener);
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        }
    
voidregisterForConnEvents()

        mApp.registerForConnEvents(mHandler);
    
voidrequeryCursor()

        if (mMessageAdapter.isScrolling()) {
            mMessageAdapter.setNeedRequeryCursor(true);
            return;
        }
        // TODO: async query?
        Cursor cursor = getMessageCursor();
        if (cursor != null) {
            cursor.requery();
        }
    
voidscheduleRequery(long interval)

        if (mRequeryCallback == null) {
            mRequeryCallback = new RequeryCallback();
        } else {
            mHandler.removeCallbacks(mRequeryCallback);
        }

        if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
            log("scheduleRequery");
        }
        mHandler.postDelayed(mRequeryCallback, interval);
    
voidsendMessage()

        String msg = mEdtInput.getText().toString();

        if (TextUtils.isEmpty(msg.trim())) {
            return;
        }

        if (mChatSession != null) {
            try {
                mChatSession.sendMessage(msg);
                mEdtInput.setText("");
                mEdtInput.requestFocus();
                requeryCursor();
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        }

        // Close the soft on-screen keyboard if we're in landscape mode so the user can see the
        // conversation.
        Configuration config = getResources().getConfiguration();
        if (config.orientation == config.ORIENTATION_LANDSCAPE) {
            closeSoftKeyboard();
        }
    
private voidsetChatViewEnabled(boolean enabled)

        mEdtInput.setEnabled(enabled);
        mSendButton.setEnabled(enabled);
        if (enabled) {
            mEdtInput.requestFocus();
        } else {
            mHistory.setAdapter(null);
        }
    
private voidsetStatusIcon()

        if (mType == Im.Contacts.TYPE_GROUP) {
            // hide the status icon for group chat.
            mStatusIcon.setVisibility(GONE);
        } else {
            mStatusIcon.setVisibility(VISIBLE);
            BrandingResources brandingRes = mApp.getBrandingResource(mProviderId);
            int presenceResId = PresenceUtils.getStatusIconId(mPresenceStatus);
            mStatusIcon.setImageDrawable(brandingRes.getDrawable(presenceResId));
        }
    
private voidsetTitle()

        if (mType == Im.Contacts.TYPE_GROUP) {
            final String[] projection = {Im.GroupMembers.NICKNAME};
            Uri memberUri = ContentUris.withAppendedId(Im.GroupMembers.CONTENT_URI, mChatId);
            ContentResolver cr = mScreen.getContentResolver();
            Cursor c = cr.query(memberUri, projection, null, null, null);
            StringBuilder buf = new StringBuilder();
            if(c != null) {
                while(c.moveToNext()) {
                    buf.append(c.getString(0));
                    if(!c.isLast()) {
                        buf.append(',");
                    }
                }
                c.close();
            }
            mTitle.setText(mContext.getString(R.string.chat_with, buf.toString()));
        } else {
            mTitle.setText(mContext.getString(R.string.chat_with, mNickName));
        }
    
private voidsetViewType(int type)

        mViewType = type;
        if (type == VIEW_TYPE_CHAT) {
            findViewById(R.id.invitationPanel).setVisibility(GONE);
            findViewById(R.id.subscription).setVisibility(GONE);
            setChatViewEnabled(true);
        }  else if (type == VIEW_TYPE_INVITATION) {
            setChatViewEnabled(false);
            findViewById(R.id.invitationPanel).setVisibility(VISIBLE);
            findViewById(R.id.btnAccept).requestFocus();
        } else if (type == VIEW_TYPE_SUBSCRIPTION) {
            setChatViewEnabled(false);
            findViewById(R.id.subscription).setVisibility(VISIBLE);
            findViewById(R.id.btnApproveSubscription).requestFocus();
        }
    
private voidstartQuery()

        if (mQueryHandler == null) {
            mQueryHandler = new QueryHandler(mContext);
        } else {
            // Cancel any pending queries
            mQueryHandler.cancelOperation(QUERY_TOKEN);
        }

        Uri uri;
        if (Im.Contacts.TYPE_GROUP == mType) {
            uri = ContentUris.withAppendedId(Im.GroupMessages.CONTENT_URI_GROUP_MESSAGES_BY, mChatId);
        } else {
            uri = Im.Messages.getContentUriByContact(mProviderId, mAccountId, mUserName);
        }

        if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
            log("queryCursor: uri=" + uri);
        }

        mQueryHandler.startQuery(QUERY_TOKEN, null,
                uri,
                null,
                null /* selection */,
                null /* selection args */,
                null);
    
voidunregisterChatListener()

        if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
            log("unregisterChatListener");
        }
        try {
            if (mChatSession != null) {
                mChatSession.unregisterChatListener(mChatListener);
            }
            IImConnection conn = mApp.getConnection(mProviderId);
            if (conn != null) {
                IContactListManager listMgr = conn.getContactListManager();
                listMgr.unregisterContactListListener(mContactListListener);
            }
        } catch (RemoteException e) {
            Log.w(ImApp.LOG_TAG, "<ChatView> unregisterChatListener fail:" + e.getMessage());
        }
    
voidunregisterChatSessionListener()

        if (mChatSessionListener != null) {
            try {
                IChatSessionManager sessionMgr = getChatSessionManager(mProviderId);
                sessionMgr.unregisterChatSessionListener(mChatSessionListener);
                // We unregister the listener when the chat session we are
                // waiting for has been created or the activity is stopped.
                // Clear the listener so that we won't unregister the listener
                // twice.
                mChatSessionListener = null;
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        }
    
voidunregisterForConnEvents()

        mApp.unregisterForConnEvents(mHandler);
    
voidupdateChat()

        setViewType(VIEW_TYPE_CHAT);

        long oldChatId = mChatId;

        updateContactInfo();

        setStatusIcon();
        setTitle();

        IImConnection conn = mApp.getConnection(mProviderId);
        if (conn == null) {
            if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) log("Connection has been signed out");
            mScreen.finish();
            return;
        }

        BrandingResources brandingRes = mApp.getBrandingResource(mProviderId);
        mHistory.setBackgroundDrawable(
                brandingRes.getDrawable(BrandingResourceIDs.DRAWABLE_CHAT_WATERMARK));

        if (mMarkup == null) {
            mMarkup = new Markup(brandingRes);
        }

        if (mMessageAdapter == null) {
            mMessageAdapter = new MessageAdapter(mScreen, null);
            mHistory.setAdapter(mMessageAdapter);
        }

        // only change the message adapter when we switch to another chat
        if (mChatId != oldChatId) {
            startQuery();
            mEdtInput.setText("");
        }

        updateWarningView();
    
private voidupdateContactInfo()

        mChatId = mCursor.getLong(CONTACT_ID_COLUMN);
        mProviderId = mCursor.getLong(PROVIDER_COLUMN);
        mAccountId = mCursor.getLong(ACCOUNT_COLUMN);
        mPresenceStatus = mCursor.getInt(PRESENCE_STATUS_COLUMN);
        mType = mCursor.getInt(TYPE_COLUMN);
        mUserName = mCursor.getString(USERNAME_COLUMN);
        mNickName = mCursor.getString(NICKNAME_COLUMN);
    
voidupdateWarningView()

        int visibility = View.GONE;
        int iconVisibility = View.GONE;
        String message = null;
        boolean isConnected;

        try {
            IImConnection conn = mApp.getConnection(mProviderId);
            isConnected = (conn == null) ? false
                    : conn.getState() != ImConnection.SUSPENDED;
        } catch (RemoteException e) {
            // do nothing
            return;
        }

        if (isConnected) {
            if (mType == Im.Contacts.TYPE_TEMPORARY) {
                visibility = View.VISIBLE;
                message = mContext.getString(R.string.contact_not_in_list_warning, mNickName);
            } else if (mPresenceStatus == Im.Presence.OFFLINE) {
                visibility = View.VISIBLE;
                message = mContext.getString(R.string.contact_offline_warning, mNickName);
            }
        } else {
            visibility = View.VISIBLE;
            iconVisibility = View.VISIBLE;
            message = mContext.getString(R.string.disconnected_warning);
        }

        mStatusWarningView.setVisibility(visibility);
        if (visibility == View.VISIBLE) {
            mWarningIcon.setVisibility(iconVisibility);
            mWarningText.setText(message);
        }
    
private voiduserActionDetected()

        if (mChatSession != null) {
            try {
                mChatSession.markAsRead();
            } catch (RemoteException e) {
                mHandler.showServiceErrorAlert();
            }
        }
    
public voidviewProfile()

        Uri data = ContentUris.withAppendedId(Im.Contacts.CONTENT_URI, mChatId);
        Intent intent = new Intent(Intent.ACTION_VIEW, data);
        mScreen.startActivity(intent);