| /* |
| * Copyright (C) 2007-2008 Esmertec AG. |
| * Copyright (C) 2007-2008 The Android Open Source Project |
| * |
| * 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.android.im.app; |
| |
| import com.android.im.IImConnection; |
| import com.android.im.R; |
| import com.android.im.plugin.BrandingResourceIDs; |
| import com.android.im.provider.Imps; |
| import com.android.im.service.ImServiceConstants; |
| |
| import android.app.Activity; |
| import android.content.ContentResolver; |
| import android.content.ContentUris; |
| import android.content.ContentValues; |
| import android.content.Intent; |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Message; |
| import android.os.RemoteException; |
| import android.util.Log; |
| import android.view.ContextMenu; |
| import android.view.KeyEvent; |
| import android.view.LayoutInflater; |
| import android.view.Menu; |
| import android.view.MenuInflater; |
| import android.view.MenuItem; |
| import android.view.View; |
| import android.view.Window; |
| import android.view.ContextMenu.ContextMenuInfo; |
| import android.widget.AdapterView; |
| import android.widget.AdapterView.AdapterContextMenuInfo; |
| import android.widget.ExpandableListView.ExpandableListContextMenuInfo; |
| |
| import java.util.Observable; |
| import java.util.Observer; |
| |
| public class ContactListActivity extends Activity implements View.OnCreateContextMenuListener{ |
| |
| private static final int MENU_START_CONVERSATION = Menu.FIRST; |
| private static final int MENU_VIEW_PROFILE = Menu.FIRST + 1; |
| private static final int MENU_BLOCK_CONTACT = Menu.FIRST + 2; |
| private static final int MENU_DELETE_CONTACT = Menu.FIRST + 3; |
| private static final int MENU_END_CONVERSATION = Menu.FIRST + 4; |
| |
| private static final String FILTER_STATE_KEY = "Filtering"; |
| |
| ImApp mApp; |
| |
| long mProviderId; |
| long mAccountId; |
| IImConnection mConn; |
| ContactListView mContactListView; |
| ContactListFilterView mFilterView; |
| SimpleAlertHandler mHandler; |
| |
| ContextMenuHandler mContextMenuHandler; |
| |
| boolean mIsFiltering; |
| |
| Imps.ProviderSettings.QueryMap mSettingMap; |
| boolean mDestroyed; |
| |
| @Override |
| protected void onCreate(Bundle icicle) { |
| super.onCreate(icicle); |
| |
| getWindow().requestFeature(Window.FEATURE_LEFT_ICON); |
| |
| LayoutInflater inflate = getLayoutInflater(); |
| mContactListView = (ContactListView) inflate.inflate( |
| R.layout.contact_list_view, null); |
| |
| setContentView(mContactListView); |
| |
| Intent intent = getIntent(); |
| mAccountId = intent.getLongExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, -1); |
| if (mAccountId == -1) { |
| finish(); |
| return; |
| } |
| mApp = ImApp.getApplication(this); |
| |
| ContentResolver cr = getContentResolver(); |
| Cursor c = cr.query(ContentUris.withAppendedId(Imps.Account.CONTENT_URI, mAccountId), |
| null, null, null, null); |
| if (c == null) { |
| finish(); |
| return; |
| } |
| if (!c.moveToFirst()) { |
| c.close(); |
| finish(); |
| return; |
| } |
| |
| mProviderId = c.getLong(c.getColumnIndexOrThrow(Imps.Account.PROVIDER)); |
| mHandler = new MyHandler(this); |
| String username = c.getString(c.getColumnIndexOrThrow(Imps.Account.USERNAME)); |
| |
| BrandingResources brandingRes = mApp.getBrandingResource(mProviderId); |
| setTitle(brandingRes.getString( |
| BrandingResourceIDs.STRING_BUDDY_LIST_TITLE, username)); |
| getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, |
| brandingRes.getDrawable(BrandingResourceIDs.DRAWABLE_LOGO)); |
| |
| mSettingMap = new Imps.ProviderSettings.QueryMap( |
| getContentResolver(), mProviderId, true, null); |
| |
| mApp.callWhenServiceConnected(mHandler, new Runnable(){ |
| public void run() { |
| if (!mDestroyed) { |
| mApp.dismissNotifications(mProviderId); |
| mConn = mApp.getConnection(mProviderId); |
| if (mConn == null) { |
| Log.e(ImApp.LOG_TAG, "The connection has disappeared!"); |
| clearConnectionStatus(); |
| finish(); |
| } else { |
| mContactListView.setConnection(mConn); |
| mContactListView.setHideOfflineContacts( |
| mSettingMap.getHideOfflineContacts()); |
| } |
| } |
| } |
| }); |
| |
| mContextMenuHandler = new ContextMenuHandler(); |
| mContactListView.getListView().setOnCreateContextMenuListener(this); |
| |
| mSettingMap.addObserver(new Observer() { |
| public void update(Observable observed, Object updateData) { |
| if (!mDestroyed) { |
| mContactListView.setHideOfflineContacts( |
| mSettingMap.getHideOfflineContacts()); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| public boolean onCreateOptionsMenu(Menu menu) { |
| MenuInflater inflater = getMenuInflater(); |
| inflater.inflate(R.menu.contact_list_menu, menu); |
| |
| BrandingResources brandingRes = mApp.getBrandingResource(mProviderId); |
| menu.findItem(R.id.menu_invite_user).setTitle( |
| brandingRes.getString(BrandingResourceIDs.STRING_MENU_ADD_CONTACT)); |
| |
| return true; |
| } |
| |
| @Override |
| public boolean onOptionsItemSelected(MenuItem item) { |
| switch (item.getItemId()) { |
| case R.id.menu_invite_user: |
| Intent i = new Intent(ContactListActivity.this, AddContactActivity.class); |
| i.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, mProviderId); |
| i.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId); |
| i.putExtra(ImServiceConstants.EXTRA_INTENT_LIST_NAME, |
| mContactListView.getSelectedContactList()); |
| startActivity(i); |
| return true; |
| |
| case R.id.menu_blocked_contacts: |
| Uri.Builder builder = Imps.BlockedList.CONTENT_URI.buildUpon(); |
| ContentUris.appendId(builder, mProviderId); |
| ContentUris.appendId(builder, mAccountId); |
| startActivity(new Intent(Intent.ACTION_VIEW, builder.build())); |
| return true; |
| |
| case R.id.menu_view_accounts: |
| Intent intent = new Intent(Intent.ACTION_VIEW); |
| intent.setType(Imps.Provider.CONTENT_TYPE); |
| startActivity(intent); |
| finish(); |
| return true; |
| |
| case R.id.menu_settings: |
| intent = new Intent(this, SettingActivity.class); |
| intent.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, mProviderId); |
| startActivity(intent); |
| return true; |
| |
| case R.id.menu_sign_out: |
| try { |
| if (mConn != null) { |
| mConn.logout(); |
| } |
| } catch (RemoteException e) { |
| } |
| return true; |
| } |
| return super.onOptionsItemSelected(item); |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| outState.putBoolean(FILTER_STATE_KEY, mIsFiltering); |
| |
| } |
| |
| @Override |
| protected void onRestoreInstanceState(Bundle savedInstanceState) { |
| boolean isFiltering = savedInstanceState.getBoolean(FILTER_STATE_KEY); |
| if (isFiltering) { |
| showFilterView(); |
| } |
| super.onRestoreInstanceState(savedInstanceState); |
| } |
| |
| @Override |
| public boolean dispatchKeyEvent(KeyEvent event) { |
| int keyCode = event.getKeyCode(); |
| |
| boolean handled = false; |
| if (mIsFiltering) { |
| handled = mFilterView.dispatchKeyEvent(event); |
| if (!handled && (KeyEvent.KEYCODE_BACK == keyCode) |
| && (KeyEvent.ACTION_DOWN == event.getAction())) { |
| showContactListView(); |
| handled = true; |
| } |
| } else { |
| handled = mContactListView.dispatchKeyEvent(event); |
| if (!handled && isReadable(keyCode, event) |
| && (KeyEvent.ACTION_DOWN == event.getAction())) { |
| showFilterView(); |
| handled = mFilterView.dispatchKeyEvent(event); |
| } |
| } |
| |
| if (!handled) { |
| handled = super.dispatchKeyEvent(event); |
| } |
| |
| return handled; |
| } |
| |
| private static boolean isReadable(int keyCode, KeyEvent event) { |
| if (KeyEvent.isModifierKey(keyCode) || event.isSystem()) { |
| return false; |
| } |
| |
| switch (keyCode) { |
| case KeyEvent.KEYCODE_DPAD_CENTER: |
| case KeyEvent.KEYCODE_DPAD_DOWN: |
| case KeyEvent.KEYCODE_DPAD_LEFT: |
| case KeyEvent.KEYCODE_DPAD_RIGHT: |
| case KeyEvent.KEYCODE_DPAD_UP: |
| case KeyEvent.KEYCODE_ENTER: |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private void showFilterView() { |
| if (mFilterView == null ) { |
| mFilterView = (ContactListFilterView)getLayoutInflater().inflate( |
| R.layout.contact_list_filter_view, null); |
| mFilterView.getListView().setOnCreateContextMenuListener(this); |
| } |
| Uri uri = mSettingMap.getHideOfflineContacts() ? Imps.Contacts.CONTENT_URI_ONLINE_CONTACTS_BY |
| : Imps.Contacts.CONTENT_URI_CONTACTS_BY; |
| uri = ContentUris.withAppendedId(uri, mProviderId); |
| uri = ContentUris.withAppendedId(uri, mAccountId); |
| mFilterView.doFilter(uri, null); |
| |
| setContentView(mFilterView); |
| mFilterView.requestFocus(); |
| mIsFiltering = true; |
| } |
| |
| void showContactListView() { |
| if (mIsFiltering) { |
| setContentView(mContactListView); |
| mContactListView.requestFocus(); |
| mContactListView.invalidate(); |
| mIsFiltering = false; |
| } |
| } |
| |
| @Override |
| protected void onPause() { |
| super.onPause(); |
| mApp.unregisterForConnEvents(mHandler); |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| mApp.registerForConnEvents(mHandler); |
| mContactListView.setAutoRefreshContacts(true); |
| } |
| |
| @Override |
| protected void onDestroy() { |
| mDestroyed = true; |
| // set connection to null to unregister listeners. |
| mContactListView.setConnection(null); |
| if (mSettingMap != null) { |
| mSettingMap.close(); |
| } |
| super.onDestroy(); |
| } |
| |
| static void log(String msg) { |
| Log.d(ImApp.LOG_TAG, "<ContactListActivity> " +msg); |
| } |
| |
| @Override |
| public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { |
| boolean chatSelected = false; |
| boolean contactSelected = false; |
| Cursor contactCursor; |
| if (mIsFiltering) { |
| AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; |
| mContextMenuHandler.mPosition = info.position; |
| contactSelected = true; |
| contactCursor = mFilterView.getContactAtPosition(info.position); |
| } else { |
| ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo; |
| mContextMenuHandler.mPosition = info.packedPosition; |
| contactSelected = mContactListView.isContactAtPosition(info.packedPosition); |
| chatSelected = mContactListView.isConversationAtPosition(info.packedPosition); |
| contactCursor = mContactListView.getContactAtPosition(info.packedPosition); |
| } |
| |
| boolean allowBlock = true; |
| if (contactCursor != null) { |
| //XXX HACK: Yahoo! doesn't allow to block a friend. We can only block a temporary contact. |
| ProviderDef provider = mApp.getProvider(mProviderId); |
| if (Imps.ProviderNames.YAHOO.equals(provider.mName)) { |
| int type = contactCursor.getInt(contactCursor.getColumnIndexOrThrow(Imps.Contacts.TYPE)); |
| allowBlock = (type == Imps.Contacts.TYPE_TEMPORARY); |
| } |
| |
| int nickNameIndex = contactCursor.getColumnIndexOrThrow(Imps.Contacts.NICKNAME); |
| |
| menu.setHeaderTitle(contactCursor.getString(nickNameIndex)); |
| } |
| |
| BrandingResources brandingRes = mApp.getBrandingResource(mProviderId); |
| String menu_end_conversation = brandingRes.getString( |
| BrandingResourceIDs.STRING_MENU_END_CHAT); |
| String menu_view_profile = brandingRes.getString( |
| BrandingResourceIDs.STRING_MENU_VIEW_PROFILE); |
| String menu_block_contact = brandingRes.getString( |
| BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT); |
| String menu_start_conversation = brandingRes.getString( |
| BrandingResourceIDs.STRING_MENU_START_CHAT); |
| String menu_delete_contact = brandingRes.getString( |
| BrandingResourceIDs.STRING_MENU_DELETE_CONTACT); |
| |
| if (chatSelected) { |
| menu.add(0, MENU_END_CONVERSATION, 0, menu_end_conversation) |
| .setIcon(com.android.internal.R.drawable.ic_menu_end_conversation) |
| .setOnMenuItemClickListener(mContextMenuHandler); |
| menu.add(0, MENU_VIEW_PROFILE, 0, menu_view_profile) |
| .setIcon(R.drawable.ic_menu_my_profile) |
| .setOnMenuItemClickListener(mContextMenuHandler); |
| if (allowBlock) { |
| menu.add(0, MENU_BLOCK_CONTACT, 0, menu_block_contact) |
| .setIcon(com.android.internal.R.drawable.ic_menu_block) |
| .setOnMenuItemClickListener(mContextMenuHandler); |
| } |
| } else if (contactSelected) { |
| menu.add(0, MENU_START_CONVERSATION, 0, menu_start_conversation) |
| .setIcon(com.android.internal.R.drawable.ic_menu_start_conversation) |
| .setOnMenuItemClickListener(mContextMenuHandler); |
| menu.add(0, MENU_VIEW_PROFILE, 0, menu_view_profile) |
| .setIcon(R.drawable.ic_menu_view_profile) |
| .setOnMenuItemClickListener(mContextMenuHandler); |
| if (allowBlock) { |
| menu.add(0, MENU_BLOCK_CONTACT, 0, menu_block_contact) |
| .setIcon(com.android.internal.R.drawable.ic_menu_block) |
| .setOnMenuItemClickListener(mContextMenuHandler); |
| } |
| menu.add(0, MENU_DELETE_CONTACT, 0, menu_delete_contact) |
| .setIcon(android.R.drawable.ic_menu_delete) |
| .setOnMenuItemClickListener(mContextMenuHandler); |
| } |
| } |
| |
| void clearConnectionStatus() { |
| ContentResolver cr = getContentResolver(); |
| ContentValues values = new ContentValues(3); |
| |
| values.put(Imps.AccountStatus.ACCOUNT, mAccountId); |
| values.put(Imps.AccountStatus.PRESENCE_STATUS, Imps.Presence.OFFLINE); |
| values.put(Imps.AccountStatus.CONNECTION_STATUS, Imps.ConnectionStatus.OFFLINE); |
| // insert on the "account_status" uri actually replaces the existing value |
| cr.insert(Imps.AccountStatus.CONTENT_URI, values); |
| } |
| |
| final class ContextMenuHandler implements MenuItem.OnMenuItemClickListener { |
| long mPosition; |
| |
| public boolean onMenuItemClick(MenuItem item) { |
| Cursor c; |
| if (mIsFiltering) { |
| c = mFilterView.getContactAtPosition((int)mPosition); |
| } else { |
| c = mContactListView.getContactAtPosition(mPosition); |
| } |
| |
| switch (item.getItemId()) { |
| case MENU_START_CONVERSATION: |
| mContactListView.startChat(c); |
| break; |
| case MENU_VIEW_PROFILE: |
| mContactListView.viewContactPresence(c); |
| break; |
| case MENU_BLOCK_CONTACT: |
| mContactListView.blockContact(c); |
| break; |
| case MENU_DELETE_CONTACT: |
| mContactListView.removeContact(c); |
| break; |
| case MENU_END_CONVERSATION: |
| mContactListView.endChat(c); |
| break; |
| default: |
| return false; |
| } |
| |
| if (mIsFiltering) { |
| showContactListView(); |
| } |
| return true; |
| } |
| } |
| |
| final class MyHandler extends SimpleAlertHandler { |
| public MyHandler(Activity activity) { |
| super(activity); |
| } |
| |
| @Override |
| public void handleMessage(Message msg) { |
| if (msg.what == ImApp.EVENT_CONNECTION_DISCONNECTED) { |
| if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { |
| log("Handle event connection disconnected."); |
| } |
| promptDisconnectedEvent(msg); |
| long providerId = ((long)msg.arg1 << 32) | msg.arg2; |
| if (providerId == mProviderId) { |
| if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { |
| log("Current connection disconnected, finish"); |
| } |
| finish(); |
| } |
| return; |
| } |
| super.handleMessage(msg); |
| } |
| } |
| } |