OSDN Git Service

auto import from //branches/cupcake/...@130745
[android-x86/packages-apps-IM.git] / src / com / android / im / app / ContactListActivity.java
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.IImConnection;
20 import com.android.im.R;
21 import com.android.im.plugin.BrandingResourceIDs;
22 import com.android.im.service.ImServiceConstants;
23
24 import android.app.Activity;
25 import android.content.ContentResolver;
26 import android.content.ContentUris;
27 import android.content.ContentValues;
28 import android.content.Intent;
29 import android.database.Cursor;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.os.Message;
33 import android.os.RemoteException;
34 import android.provider.Im;
35 import android.util.Log;
36 import android.view.ContextMenu;
37 import android.view.KeyEvent;
38 import android.view.LayoutInflater;
39 import android.view.Menu;
40 import android.view.MenuInflater;
41 import android.view.MenuItem;
42 import android.view.View;
43 import android.view.Window;
44 import android.view.ContextMenu.ContextMenuInfo;
45 import android.widget.AdapterView;
46 import android.widget.AdapterView.AdapterContextMenuInfo;
47 import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
48
49 import java.util.Observable;
50 import java.util.Observer;
51
52 public class ContactListActivity extends Activity implements View.OnCreateContextMenuListener{
53
54     private static final int MENU_START_CONVERSATION = Menu.FIRST;
55     private static final int MENU_VIEW_PROFILE       = Menu.FIRST + 1;
56     private static final int MENU_BLOCK_CONTACT      = Menu.FIRST + 2;
57     private static final int MENU_DELETE_CONTACT     = Menu.FIRST + 3;
58     private static final int MENU_END_CONVERSATION   = Menu.FIRST + 4;
59
60     private static final String FILTER_STATE_KEY = "Filtering";
61
62     ImApp mApp;
63
64     long mProviderId;
65     long mAccountId;
66     IImConnection mConn;
67     ContactListView mContactListView;
68     ContactListFilterView mFilterView;
69     SimpleAlertHandler mHandler;
70
71     ContextMenuHandler mContextMenuHandler;
72
73     boolean mIsFiltering;
74
75     Im.ProviderSettings.QueryMap mSettingMap;
76     boolean mDestroyed;
77
78     @Override
79     protected void onCreate(Bundle icicle) {
80         super.onCreate(icicle);
81
82         getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
83
84         LayoutInflater inflate = getLayoutInflater();
85         mContactListView = (ContactListView) inflate.inflate(
86                 R.layout.contact_list_view, null);
87
88         setContentView(mContactListView);
89
90         Intent intent = getIntent();
91         mAccountId = intent.getLongExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, -1);
92         if (mAccountId == -1) {
93             finish();
94             return;
95         }
96         mApp = ImApp.getApplication(this);
97
98         ContentResolver cr = getContentResolver();
99         Cursor c = cr.query(ContentUris.withAppendedId(Im.Account.CONTENT_URI, mAccountId),
100                 null, null, null, null);
101         if (c == null) {
102             finish();
103             return;
104         }
105         if (!c.moveToFirst()) {
106             c.close();
107             finish();
108             return;
109         }
110
111         mProviderId = c.getLong(c.getColumnIndexOrThrow(Im.Account.PROVIDER));
112         mHandler = new MyHandler(this);
113         String username = c.getString(c.getColumnIndexOrThrow(Im.Account.USERNAME));
114
115         BrandingResources brandingRes = mApp.getBrandingResource(mProviderId);
116         setTitle(brandingRes.getString(
117                 BrandingResourceIDs.STRING_BUDDY_LIST_TITLE, username));
118         getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON,
119                 brandingRes.getDrawable(BrandingResourceIDs.DRAWABLE_LOGO));
120
121         mSettingMap = new Im.ProviderSettings.QueryMap(
122                 getContentResolver(), mProviderId, true, null);
123
124         mApp.callWhenServiceConnected(mHandler, new Runnable(){
125             public void run() {
126                 if (!mDestroyed) {
127                     mApp.dismissNotifications(mProviderId);
128                     mConn = mApp.getConnection(mProviderId);
129                     if (mConn == null) {
130                         Log.e(ImApp.LOG_TAG, "The connection has disappeared!");
131                         clearConnectionStatus();
132                         finish();
133                     } else {
134                         mContactListView.setConnection(mConn);
135                         mContactListView.setHideOfflineContacts(
136                                 mSettingMap.getHideOfflineContacts());
137                     }
138                 }
139             }
140         });
141
142         mContextMenuHandler = new ContextMenuHandler();
143         mContactListView.getListView().setOnCreateContextMenuListener(this);
144
145         mSettingMap.addObserver(new Observer() {
146             public void update(Observable observed, Object updateData) {
147                 if (!mDestroyed) {
148                     mContactListView.setHideOfflineContacts(
149                             mSettingMap.getHideOfflineContacts());
150                 }
151             }
152         });
153     }
154
155     @Override
156     public boolean onCreateOptionsMenu(Menu menu) {
157         MenuInflater inflater = getMenuInflater();
158         inflater.inflate(R.menu.contact_list_menu, menu);
159
160         BrandingResources brandingRes = mApp.getBrandingResource(mProviderId);
161         menu.findItem(R.id.menu_invite_user).setTitle(
162             brandingRes.getString(BrandingResourceIDs.STRING_MENU_ADD_CONTACT));
163
164         return true;
165     }
166
167     @Override
168     public boolean onOptionsItemSelected(MenuItem item) {
169         switch (item.getItemId()) {
170             case R.id.menu_invite_user:
171                 Intent i = new Intent(ContactListActivity.this, AddContactActivity.class);
172                 i.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, mProviderId);
173                 i.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId);
174                 i.putExtra(ImServiceConstants.EXTRA_INTENT_LIST_NAME,
175                         mContactListView.getSelectedContactList());
176                 startActivity(i);
177                 return true;
178
179             case R.id.menu_blocked_contacts:
180                 Uri.Builder builder = Im.BlockedList.CONTENT_URI.buildUpon();
181                 ContentUris.appendId(builder, mProviderId);
182                 ContentUris.appendId(builder, mAccountId);
183                 startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
184                 return true;
185
186             case R.id.menu_view_accounts:
187                 Intent intent = new Intent(Intent.ACTION_VIEW);
188                 intent.setType(Im.Provider.CONTENT_TYPE);
189                 startActivity(intent);
190                 finish();
191                 return true;
192
193             case R.id.menu_settings:
194                 intent = new Intent(this, SettingActivity.class);
195                 intent.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, mProviderId);
196                 startActivity(intent);
197                 return true;
198
199             case R.id.menu_sign_out:
200                 try {
201                     if (mConn != null) {
202                         mConn.logout();
203                     }
204                 } catch (RemoteException e) {
205                 }
206                 return true;
207         }
208         return super.onOptionsItemSelected(item);
209     }
210
211     @Override
212     protected void onSaveInstanceState(Bundle outState) {
213         super.onSaveInstanceState(outState);
214         outState.putBoolean(FILTER_STATE_KEY, mIsFiltering);
215
216     }
217
218     @Override
219     protected void onRestoreInstanceState(Bundle savedInstanceState) {
220         boolean isFiltering = savedInstanceState.getBoolean(FILTER_STATE_KEY);
221         if (isFiltering) {
222             showFilterView();
223         }
224         super.onRestoreInstanceState(savedInstanceState);
225     }
226
227     @Override
228     public boolean dispatchKeyEvent(KeyEvent event) {
229         int keyCode = event.getKeyCode();
230
231         boolean handled = false;
232         if (mIsFiltering) {
233             handled = mFilterView.dispatchKeyEvent(event);
234             if (!handled && (KeyEvent.KEYCODE_BACK == keyCode)
235                     && (KeyEvent.ACTION_DOWN == event.getAction())) {
236                 showContactListView();
237                 handled = true;
238             }
239         } else {
240             handled = mContactListView.dispatchKeyEvent(event);
241             if (!handled && isReadable(keyCode, event)
242                     && (KeyEvent.ACTION_DOWN == event.getAction())) {
243                 showFilterView();
244                 handled = mFilterView.dispatchKeyEvent(event);
245             }
246         }
247
248         if (!handled) {
249             handled = super.dispatchKeyEvent(event);
250         }
251
252         return handled;
253     }
254
255     private static boolean isReadable(int keyCode, KeyEvent event) {
256         if (KeyEvent.isModifierKey(keyCode) || event.isSystem()) {
257             return false;
258         }
259
260         switch (keyCode) {
261         case KeyEvent.KEYCODE_DPAD_CENTER:
262         case KeyEvent.KEYCODE_DPAD_DOWN:
263         case KeyEvent.KEYCODE_DPAD_LEFT:
264         case KeyEvent.KEYCODE_DPAD_RIGHT:
265         case KeyEvent.KEYCODE_DPAD_UP:
266         case KeyEvent.KEYCODE_ENTER:
267             return false;
268         }
269
270         return true;
271     }
272
273     private void showFilterView() {
274         if (mFilterView == null ) {
275             mFilterView = (ContactListFilterView)getLayoutInflater().inflate(
276                     R.layout.contact_list_filter_view, null);
277             mFilterView.getListView().setOnCreateContextMenuListener(this);
278         }
279         Uri uri = mSettingMap.getHideOfflineContacts() ? Im.Contacts.CONTENT_URI_ONLINE_CONTACTS_BY
280                 : Im.Contacts.CONTENT_URI_CONTACTS_BY;
281         uri = ContentUris.withAppendedId(uri, mProviderId);
282         uri = ContentUris.withAppendedId(uri, mAccountId);
283         mFilterView.doFilter(uri, null);
284
285         setContentView(mFilterView);
286         mFilterView.requestFocus();
287         mIsFiltering = true;
288     }
289
290     void showContactListView() {
291         if (mIsFiltering) {
292             setContentView(mContactListView);
293             mContactListView.requestFocus();
294             mContactListView.invalidate();
295             mIsFiltering = false;
296         }
297     }
298
299     @Override
300     protected void onPause() {
301         super.onPause();
302         mApp.unregisterForConnEvents(mHandler);
303     }
304
305     @Override
306     protected void onResume() {
307         super.onResume();
308         mApp.registerForConnEvents(mHandler);
309     }
310
311     @Override
312     protected void onDestroy() {
313         mDestroyed = true;
314         // set connection to null to unregister listeners.
315         mContactListView.setConnection(null);
316         if (mSettingMap != null) {
317             mSettingMap.close();
318         }
319         super.onDestroy();
320     }
321
322     static void log(String msg) {
323         Log.d(ImApp.LOG_TAG, "<ContactListActivity> " +msg);
324     }
325
326     @Override
327     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
328         boolean chatSelected = false;
329         boolean contactSelected = false;
330         Cursor contactCursor;
331         if (mIsFiltering) {
332             AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
333             mContextMenuHandler.mPosition = info.position;
334             contactSelected = true;
335             contactCursor = mFilterView.getContactAtPosition(info.position);
336         } else {
337             ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo;
338             mContextMenuHandler.mPosition = info.packedPosition;
339             contactSelected = mContactListView.isContactAtPosition(info.packedPosition);
340             chatSelected = mContactListView.isConversationAtPosition(info.packedPosition);
341             contactCursor = mContactListView.getContactAtPosition(info.packedPosition);
342         }
343
344         boolean allowBlock = true;
345         if (contactCursor != null) {
346             //XXX HACK: Yahoo! doesn't allow to block a friend. We can only block a temporary contact.
347             ProviderDef provider = mApp.getProvider(mProviderId);
348             if (Im.ProviderNames.YAHOO.equals(provider.mName)) {
349                 int type = contactCursor.getInt(contactCursor.getColumnIndexOrThrow(Im.Contacts.TYPE));
350                 allowBlock = (type == Im.Contacts.TYPE_TEMPORARY);
351             }
352
353             int nickNameIndex = contactCursor.getColumnIndexOrThrow(Im.Contacts.NICKNAME);
354
355             menu.setHeaderTitle(contactCursor.getString(nickNameIndex));
356         }
357
358         BrandingResources brandingRes = mApp.getBrandingResource(mProviderId);
359         String menu_end_conversation = brandingRes.getString(
360                 BrandingResourceIDs.STRING_MENU_END_CHAT);
361         String menu_view_profile = brandingRes.getString(
362                 BrandingResourceIDs.STRING_MENU_VIEW_PROFILE);
363         String menu_block_contact = brandingRes.getString(
364                 BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT);
365         String menu_start_conversation = brandingRes.getString(
366                 BrandingResourceIDs.STRING_MENU_START_CHAT);
367         String menu_delete_contact = brandingRes.getString(
368                 BrandingResourceIDs.STRING_MENU_DELETE_CONTACT);
369
370         if (chatSelected) {
371             menu.add(0, MENU_END_CONVERSATION, 0, menu_end_conversation)
372                     .setIcon(com.android.internal.R.drawable.ic_menu_end_conversation)
373                     .setOnMenuItemClickListener(mContextMenuHandler);
374             menu.add(0, MENU_VIEW_PROFILE, 0, menu_view_profile)
375                     .setIcon(R.drawable.ic_menu_my_profile)
376                     .setOnMenuItemClickListener(mContextMenuHandler);
377             if (allowBlock) {
378                 menu.add(0, MENU_BLOCK_CONTACT, 0, menu_block_contact)
379                         .setIcon(com.android.internal.R.drawable.ic_menu_block)
380                         .setOnMenuItemClickListener(mContextMenuHandler);
381             }
382         } else if (contactSelected) {
383             menu.add(0, MENU_START_CONVERSATION, 0, menu_start_conversation)
384                     .setIcon(com.android.internal.R.drawable.ic_menu_start_conversation)
385                     .setOnMenuItemClickListener(mContextMenuHandler);
386             menu.add(0, MENU_VIEW_PROFILE, 0, menu_view_profile)
387                     .setIcon(R.drawable.ic_menu_view_profile)
388                     .setOnMenuItemClickListener(mContextMenuHandler);
389             if (allowBlock) {
390                 menu.add(0, MENU_BLOCK_CONTACT, 0, menu_block_contact)
391                         .setIcon(com.android.internal.R.drawable.ic_menu_block)
392                         .setOnMenuItemClickListener(mContextMenuHandler);
393             }
394             menu.add(0, MENU_DELETE_CONTACT, 0, menu_delete_contact)
395                     .setIcon(android.R.drawable.ic_menu_delete)
396                     .setOnMenuItemClickListener(mContextMenuHandler);
397         }
398     }
399
400     void clearConnectionStatus() {
401         ContentResolver cr = getContentResolver();
402         ContentValues values = new ContentValues(3);
403
404         values.put(Im.AccountStatus.ACCOUNT, mAccountId);
405         values.put(Im.AccountStatus.PRESENCE_STATUS, Im.Presence.OFFLINE);
406         values.put(Im.AccountStatus.CONNECTION_STATUS, Im.ConnectionStatus.OFFLINE);
407         // insert on the "account_status" uri actually replaces the existing value 
408         cr.insert(Im.AccountStatus.CONTENT_URI, values);
409     }
410
411     final class ContextMenuHandler implements MenuItem.OnMenuItemClickListener {
412         long mPosition;
413
414         public boolean onMenuItemClick(MenuItem item) {
415             Cursor c;
416             if (mIsFiltering) {
417                 c = mFilterView.getContactAtPosition((int)mPosition);
418             } else {
419                 c = mContactListView.getContactAtPosition(mPosition);
420             }
421
422             switch (item.getItemId()) {
423             case MENU_START_CONVERSATION:
424                 mContactListView.startChat(c);
425                 break;
426             case MENU_VIEW_PROFILE:
427                 mContactListView.viewContactPresence(c);
428                 break;
429             case MENU_BLOCK_CONTACT:
430                 mContactListView.blockContact(c);
431                 break;
432             case MENU_DELETE_CONTACT:
433                 mContactListView.removeContact(c);
434                 break;
435             case MENU_END_CONVERSATION:
436                 mContactListView.endChat(c);
437                 break;
438             default:
439                 return false;
440             }
441
442             if (mIsFiltering) {
443                 showContactListView();
444             }
445             return true;
446         }
447     }
448
449     final class MyHandler extends SimpleAlertHandler {
450         public MyHandler(Activity activity) {
451             super(activity);
452         }
453
454         @Override
455         public void handleMessage(Message msg) {
456             if (msg.what == ImApp.EVENT_CONNECTION_DISCONNECTED) {
457                 if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) {
458                     log("Handle event connection disconnected.");
459                 }
460                 promptDisconnectedEvent(msg);
461                 long providerId = ((long)msg.arg1 << 32) | msg.arg2;
462                 if (providerId == mProviderId) {
463                     if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) {
464                         log("Current connection disconnected, finish");
465                     }
466                     finish();
467                 }
468                 return;
469             }
470             super.handleMessage(msg);
471         }
472     }
473 }