Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2007-2008 Esmertec AG.
      3  * Copyright (C) 2007-2008 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 package com.android.im.app;
     18 
     19 import com.android.im.IChatSession;
     20 import com.android.im.IChatSessionManager;
     21 import com.android.im.IContactListListener;
     22 import com.android.im.IContactListManager;
     23 import com.android.im.IImConnection;
     24 import com.android.im.ISubscriptionListener;
     25 import com.android.im.R;
     26 import com.android.im.app.adapter.ContactListListenerAdapter;
     27 import com.android.im.engine.Contact;
     28 import com.android.im.engine.ContactListManager;
     29 import com.android.im.engine.ImErrorInfo;
     30 import com.android.im.provider.Imps;
     31 import com.android.im.service.ImServiceConstants;
     32 
     33 import android.app.Activity;
     34 import android.app.AlertDialog;
     35 import android.content.ContentUris;
     36 import android.content.Context;
     37 import android.content.DialogInterface;
     38 import android.content.Intent;
     39 import android.content.res.Resources;
     40 import android.database.Cursor;
     41 import android.graphics.Canvas;
     42 import android.net.Uri;
     43 import android.os.Parcel;
     44 import android.os.Parcelable;
     45 import android.os.RemoteException;
     46 import android.util.AttributeSet;
     47 import android.util.Log;
     48 import android.view.View;
     49 import android.widget.ExpandableListView;
     50 import android.widget.LinearLayout;
     51 import android.widget.ExpandableListView.OnChildClickListener;
     52 
     53 public class ContactListView extends LinearLayout {
     54 
     55     Activity mScreen;
     56     IImConnection mConn;
     57     SimpleAlertHandler mHandler;
     58     private final IContactListListener mContactListListener;
     59 
     60     UserPresenceView mPresenceView;
     61     ExpandableListView mContactsList;
     62     private ContactListTreeAdapter mAdapter;
     63     private boolean mHideOfflineContacts;
     64     private SavedState mSavedState;
     65     private boolean mAutoRefresh = true;
     66 
     67     public ContactListView(Context screen, AttributeSet attrs) {
     68         super(screen, attrs);
     69         mScreen = (Activity)screen;
     70         mHandler = new SimpleAlertHandler(mScreen);
     71         mContactListListener = new MyContactListListener(mHandler);
     72     }
     73 
     74     private class MyContactListListener extends ContactListListenerAdapter {
     75         public MyContactListListener(SimpleAlertHandler handler) {
     76             super(handler);
     77         }
     78 
     79         @Override
     80         public void onAllContactListsLoaded() {
     81             if (mAdapter != null) {
     82                 mAdapter.startAutoRequery();
     83             }
     84         }
     85     }
     86 
     87     private final ISubscriptionListener.Stub mSubscriptionListener = new ISubscriptionListener.Stub() {
     88 
     89         public void onSubScriptionRequest(Contact from) {
     90             querySubscription();
     91         }
     92 
     93         public void onSubscriptionApproved(String contact) {
     94             querySubscription();
     95         }
     96 
     97         public void onSubscriptionDeclined(String contact) {
     98             querySubscription();
     99         }
    100 
    101         private void querySubscription() {
    102             if (mAdapter != null) {
    103                 mAdapter.startQuerySubscriptions();
    104             }
    105         }
    106      };
    107 
    108     @Override
    109     protected void onFinishInflate() {
    110         super.onFinishInflate();
    111         mPresenceView = (UserPresenceView)findViewById(R.id.userPresence);
    112         mContactsList = (ExpandableListView) findViewById(R.id.contactsList);
    113         mContactsList.setOnChildClickListener(mOnChildClickListener);
    114     }
    115 
    116     public ExpandableListView getListView() {
    117         return mContactsList;
    118     }
    119 
    120     public void setConnection(IImConnection conn) {
    121         if (mConn != conn) {
    122             if (mConn != null) {
    123                 unregisterListeners();
    124             }
    125             mConn = conn;
    126 
    127             if (conn != null) {
    128                 registerListeners();
    129                 mPresenceView.setConnection(conn);
    130 
    131                 if (mAdapter == null) {
    132                     mAdapter = new ContactListTreeAdapter(conn, mScreen);
    133                     mAdapter.setHideOfflineContacts(mHideOfflineContacts);
    134                     mContactsList.setAdapter(mAdapter);
    135                     mContactsList.setOnScrollListener(mAdapter);
    136                     if (mSavedState != null) {
    137                         int[] expandedGroups = mSavedState.mExpandedGroups;
    138                         if(expandedGroups != null) {
    139                             for (int group : expandedGroups) {
    140                                 mContactsList.expandGroup(group);
    141                             }
    142                         }
    143                     }
    144                 } else {
    145                     mAdapter.changeConnection(conn);
    146                 }
    147                 try {
    148                     IContactListManager listMgr = conn.getContactListManager();
    149                     if (listMgr.getState() == ContactListManager.LISTS_LOADED) {
    150                         mAdapter.startAutoRequery();
    151                     }
    152                 } catch (RemoteException e) {
    153                     Log.e(ImApp.LOG_TAG, "Service died!");
    154                 }
    155             }
    156         } else {
    157             mContactsList.invalidateViews();
    158         }
    159     }
    160 
    161     public void setHideOfflineContacts(boolean hide) {
    162         if (mAdapter != null) {
    163             mAdapter.setHideOfflineContacts(hide);
    164         } else {
    165             mHideOfflineContacts = hide;
    166         }
    167     }
    168 
    169     public void startChat() {
    170         startChat(getSelectedContact());
    171     }
    172 
    173     public void startChatAtPosition(long packedPosition) {
    174         startChat(getContactAtPosition(packedPosition));
    175     }
    176 
    177     void startChat(Cursor c) {
    178         if (c != null) {
    179             long id = c.getLong(c.getColumnIndexOrThrow(Imps.Contacts._ID));
    180             String username = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.USERNAME));
    181             try {
    182                 IChatSessionManager manager = mConn.getChatSessionManager();
    183                 IChatSession session = manager.getChatSession(username);
    184                 if(session == null) {
    185                     manager.createChatSession(username);
    186                 }
    187 
    188                 Uri data = ContentUris.withAppendedId(Imps.Chats.CONTENT_URI, id);
    189                 Intent i = new Intent(Intent.ACTION_VIEW, data);
    190                 i.addCategory(ImApp.IMPS_CATEGORY);
    191                 mScreen.startActivity(i);
    192                 setAutoRefreshContacts(false);
    193             } catch (RemoteException e) {
    194                 mHandler.showServiceErrorAlert();
    195             }
    196             clearFocusIfEmpty(c);
    197         }
    198     }
    199 
    200     private void clearFocusIfEmpty(Cursor c) {
    201         // clear focus if there's only one item so that it would focus on the
    202         // "empty" item after the contact removed.
    203         if (c.getCount() == 1) {
    204             clearFocus();
    205         }
    206     }
    207 
    208     public void endChat() {
    209         endChat(getSelectedContact());
    210     }
    211 
    212     public void endChatAtPosition(long packedPosition) {
    213         endChat(getContactAtPosition(packedPosition));
    214     }
    215 
    216     void endChat(Cursor c) {
    217         if(c != null) {
    218             String username = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.USERNAME));
    219             try {
    220                 IChatSessionManager manager = mConn.getChatSessionManager();
    221                 IChatSession session = manager.getChatSession(username);
    222                 if(session != null) {
    223                     session.leave();
    224                 }
    225             } catch (RemoteException e) {
    226                 mHandler.showServiceErrorAlert();
    227             }
    228             clearFocusIfEmpty(c);
    229         }
    230     }
    231 
    232     public void viewContactPresence() {
    233         viewContactPresence(getSelectedContact());
    234     }
    235 
    236     public void viewContactPresenceAtPostion(long packedPosition) {
    237         viewContactPresence(getContactAtPosition(packedPosition));
    238     }
    239 
    240     public void viewContactPresence(Cursor c) {
    241         if (c != null) {
    242             long id = c.getLong(c.getColumnIndexOrThrow(Imps.Contacts._ID));
    243             Uri data = ContentUris.withAppendedId(Imps.Contacts.CONTENT_URI, id);
    244             Intent i = new Intent(Intent.ACTION_VIEW, data);
    245             mScreen.startActivity(i);
    246         }
    247     }
    248 
    249     public boolean isContactAtPosition(long packedPosition) {
    250         int type = ExpandableListView.getPackedPositionType(packedPosition);
    251         int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition);
    252         return (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD)
    253                 && !mAdapter.isPosForSubscription(groupPosition);
    254     }
    255 
    256     public boolean isContactSelected() {
    257         long pos = mContactsList.getSelectedPosition();
    258         return isContactAtPosition(pos);
    259     }
    260 
    261     public boolean isConversationAtPosition(long packedPosition) {
    262         int type = ExpandableListView.getPackedPositionType(packedPosition);
    263         int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition);
    264         return (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD)
    265                 && mAdapter.isPosForOngoingConversation(groupPosition);
    266     }
    267 
    268     public boolean isConversationSelected () {
    269         long pos = mContactsList.getSelectedPosition();
    270         return isConversationAtPosition(pos);
    271     }
    272 
    273     public boolean isContactsLoaded() {
    274         try {
    275             IContactListManager manager = mConn.getContactListManager();
    276             return (manager.getState() == ContactListManager.LISTS_LOADED);
    277         } catch (RemoteException e) {
    278             mHandler.showServiceErrorAlert();
    279             return false;
    280         }
    281     }
    282 
    283     public void removeContact() {
    284         removeContact(getSelectedContact());
    285     }
    286 
    287     public void removeContactAtPosition(long packedPosition) {
    288         removeContact(getContactAtPosition(packedPosition));
    289     }
    290 
    291     void removeContact(Cursor c) {
    292         if (c == null) {
    293             mHandler.showAlert(R.string.error, R.string.select_contact);
    294         } else {
    295             String nickname = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.NICKNAME));
    296             final String address = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.USERNAME));
    297             DialogInterface.OnClickListener confirmListener = new DialogInterface.OnClickListener(){
    298                 public void onClick(DialogInterface dialog, int whichButton) {
    299                     try {
    300                         IContactListManager manager = mConn.getContactListManager();
    301                         int res = manager.removeContact(address);
    302                         if (res != ImErrorInfo.NO_ERROR) {
    303                             mHandler.showAlert(R.string.error,
    304                                     ErrorResUtils.getErrorRes(getResources(), res, address));
    305                         }
    306                     } catch (RemoteException e) {
    307                         mHandler.showServiceErrorAlert();
    308                     }
    309                 }
    310             };
    311             Resources r = getResources();
    312 
    313             new AlertDialog.Builder(mContext)
    314                 .setTitle(R.string.confirm)
    315                 .setMessage(r.getString(R.string.confirm_delete_contact, nickname))
    316                 .setPositiveButton(R.string.yes, confirmListener) // default button
    317                 .setNegativeButton(R.string.no, null)
    318                 .setCancelable(false)
    319                 .show();
    320 
    321             clearFocusIfEmpty(c);
    322         }
    323     }
    324 
    325     public void blockContact() {
    326         blockContact(getSelectedContact());
    327     }
    328 
    329     public void blockContactAtPosition(long packedPosition) {
    330         blockContact(getContactAtPosition(packedPosition));
    331     }
    332 
    333     void blockContact(Cursor c) {
    334         if (c == null) {
    335             mHandler.showAlert(R.string.error, R.string.select_contact);
    336         } else {
    337             String nickname = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.NICKNAME));
    338             final String address = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.USERNAME));
    339             DialogInterface.OnClickListener confirmListener = new DialogInterface.OnClickListener(){
    340                 public void onClick(DialogInterface dialog, int whichButton) {
    341                     try {
    342                         IContactListManager manager = mConn.getContactListManager();
    343                         int res = manager.blockContact(address);
    344                         if (res != ImErrorInfo.NO_ERROR) {
    345                             mHandler.showAlert(R.string.error,
    346                                     ErrorResUtils.getErrorRes(getResources(), res, address));
    347                         }
    348                     } catch (RemoteException e) {
    349                         mHandler.showServiceErrorAlert();
    350                     }
    351                 }
    352             };
    353 
    354             Resources r = getResources();
    355 
    356             new AlertDialog.Builder(mContext)
    357                 .setTitle(R.string.confirm)
    358                 .setMessage(r.getString(R.string.confirm_block_contact, nickname))
    359                 .setPositiveButton(R.string.yes, confirmListener) // default button
    360                 .setNegativeButton(R.string.no, null)
    361                 .setCancelable(false)
    362                 .show();
    363             clearFocusIfEmpty(c);
    364         }
    365     }
    366 
    367     public Cursor getContactAtPosition(long packedPosition) {
    368         int type = ExpandableListView.getPackedPositionType(packedPosition);
    369         if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
    370             int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition);
    371             int childPosition = ExpandableListView.getPackedPositionChild(packedPosition);
    372             return (Cursor) mAdapter.getChild(groupPosition, childPosition);
    373         }
    374         return null;
    375     }
    376 
    377     public Cursor getSelectedContact() {
    378         long pos = mContactsList.getSelectedPosition();
    379         if (ExpandableListView.getPackedPositionType(pos)
    380                 == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
    381             return (Cursor)mContactsList.getSelectedItem();
    382         }
    383         return null;
    384     }
    385 
    386     public String getSelectedContactList() {
    387         long pos = mContactsList.getSelectedPosition();
    388         int groupPos = ExpandableListView.getPackedPositionGroup(pos);
    389         if (groupPos == -1) {
    390             return null;
    391         }
    392 
    393         Cursor cursor = (Cursor)mAdapter.getGroup(groupPos);
    394         if (cursor == null) {
    395             return null;
    396         }
    397         return cursor.getString(cursor.getColumnIndexOrThrow(Imps.ContactList.NAME));
    398     }
    399 
    400     private void registerListeners() {
    401         try{
    402             IContactListManager listManager = mConn.getContactListManager();
    403             listManager.registerContactListListener(mContactListListener);
    404             listManager.registerSubscriptionListener(mSubscriptionListener);
    405         }catch(RemoteException e) {
    406             mHandler.showServiceErrorAlert();
    407         }
    408     }
    409 
    410     private void unregisterListeners() {
    411         try{
    412             IContactListManager listManager = mConn.getContactListManager();
    413             listManager.unregisterContactListListener(mContactListListener);
    414             listManager.unregisterSubscriptionListener(mSubscriptionListener);
    415         }catch(RemoteException e) {
    416             mHandler.showServiceErrorAlert();
    417         }
    418     }
    419 
    420     private final OnChildClickListener mOnChildClickListener = new OnChildClickListener() {
    421         public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
    422                 int childPosition, long id) {
    423             Cursor cursor = (Cursor)parent.getExpandableListAdapter().getChild(
    424                     groupPosition, childPosition);
    425             if (cursor == null) {
    426                 Log.w(ImApp.LOG_TAG,
    427                         "[ContactListView.OnChildClickListener.onChildClick] cursor null! groupPos="
    428                                 + groupPosition + ", childPos=" + childPosition,
    429                         new RuntimeException());
    430                 return false;
    431             }
    432 
    433             int subscriptionType = cursor.getInt(ContactView.COLUMN_SUBSCRIPTION_TYPE);
    434             int subscriptionStatus = cursor.getInt(ContactView.COLUMN_SUBSCRIPTION_STATUS);
    435             if ((subscriptionType == Imps.Contacts.SUBSCRIPTION_TYPE_FROM)
    436                     && (subscriptionStatus == Imps.Contacts.SUBSCRIPTION_STATUS_SUBSCRIBE_PENDING)){
    437                 long providerId = cursor.getLong(ContactView.COLUMN_CONTACT_PROVIDER);
    438                 String username = cursor.getString(ContactView.COLUMN_CONTACT_USERNAME);
    439                 Intent intent = new Intent(ImServiceConstants.ACTION_MANAGE_SUBSCRIPTION,
    440                         ContentUris.withAppendedId(Imps.Contacts.CONTENT_URI, id));
    441                 intent.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, providerId);
    442                 intent.putExtra(ImServiceConstants.EXTRA_INTENT_FROM_ADDRESS, username);
    443                 mScreen.startActivity(intent);
    444             } else {
    445                 startChat(cursor);
    446             }
    447             return true;
    448         }
    449     };
    450 
    451     static class SavedState extends BaseSavedState {
    452         int[] mExpandedGroups;
    453 
    454         SavedState(Parcelable superState, int[] expandedGroups) {
    455             super(superState);
    456             mExpandedGroups = expandedGroups;
    457         }
    458 
    459         private SavedState(Parcel in) {
    460             super(in);
    461             mExpandedGroups = in.createIntArray();
    462         }
    463 
    464         @Override
    465         public void writeToParcel(Parcel out, int flags) {
    466             super.writeToParcel(out, flags);
    467             out.writeIntArray(mExpandedGroups);
    468         }
    469 
    470         public static final Parcelable.Creator<SavedState> CREATOR
    471                 = new Parcelable.Creator<SavedState>() {
    472             public SavedState createFromParcel(Parcel in) {
    473                 return new SavedState(in);
    474             }
    475 
    476             public SavedState[] newArray(int size) {
    477                 return new SavedState[size];
    478             }
    479         };
    480     }
    481 
    482     @Override
    483     public Parcelable onSaveInstanceState() {
    484         Parcelable superState = super.onSaveInstanceState();
    485         int[] expandedGroups = mAdapter == null ? null
    486                 : mAdapter.getExpandedGroups();
    487         return new SavedState(superState, expandedGroups);
    488     }
    489 
    490     @Override
    491     public void onRestoreInstanceState(Parcelable state) {
    492         SavedState ss = (SavedState) state;
    493 
    494         super.onRestoreInstanceState(ss.getSuperState());
    495 
    496         mSavedState = ss;
    497     }
    498 
    499     protected void setAutoRefreshContacts(boolean isRefresh) {
    500         mAutoRefresh = isRefresh;
    501     }
    502 
    503     @Override
    504     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    505         if (mAutoRefresh) {
    506             super.onLayout(changed, l, t, r, b);
    507         }
    508     }
    509 }
    510