ContactListTreeAdapter.java
上传用户:szyujian
上传日期:2016-09-20
资源大小:320k
文件大小:26k
源码类别:
android开发
开发平台:
C/C++
- /*
- * Copyright (C) 2008 Esmertec AG.
- * Copyright (C) 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 android.app.Activity;
- import android.content.AsyncQueryHandler;
- import android.content.ContentQueryMap;
- import android.content.ContentResolver;
- import android.content.ContentUris;
- import android.content.ContentValues;
- import android.content.Context;
- import android.content.res.Resources;
- import android.database.ContentObserver;
- import android.database.Cursor;
- import android.database.DataSetObserver;
- import android.net.Uri;
- import android.os.RemoteException;
- import android.provider.Im;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseExpandableListAdapter;
- import android.widget.CursorTreeAdapter;
- import android.widget.TextView;
- import android.widget.AbsListView;
- import android.widget.AbsListView.OnScrollListener;
- import com.android.im.IImConnection;
- import com.android.im.R;
- import com.android.im.plugin.BrandingResourceIDs;
- import java.util.ArrayList;
- import java.util.Observable;
- import java.util.Observer;
- public class ContactListTreeAdapter extends BaseExpandableListAdapter
- implements AbsListView.OnScrollListener{
- private static final String[] CONTACT_LIST_PROJECTION = {
- Im.ContactList._ID,
- Im.ContactList.NAME,
- };
- private static final int COLUMN_CONTACT_LIST_ID = 0;
- private static final int COLUMN_CONTACT_LIST_NAME = 1;
- Activity mActivity;
- SimpleAlertHandler mHandler;
- private LayoutInflater mInflate;
- private long mProviderId;
- long mAccountId;
- Cursor mOngoingConversations;
- Cursor mSubscriptions;
- boolean mDataValid;
- ListTreeAdapter mAdapter;
- private boolean mHideOfflineContacts;
- final MyContentObserver mContentObserver;
- final MyDataSetObserver mDataSetObserver;
- private ArrayList<Integer> mExpandedGroups;
- private static final int TOKEN_CONTACT_LISTS = -1;
- private static final int TOKEN_ONGOING_CONVERSATION = -2;
- private static final int TOKEN_SUBSCRITPTION = -3;
- private static final String NON_CHAT_AND_BLOCKED_CONTACTS = "("
- + Im.Contacts.LAST_MESSAGE_DATE + " IS NULL) AND ("
- + Im.Contacts.TYPE + "!=" + Im.Contacts.TYPE_BLOCKED + ")";
- private static final String CONTACTS_SELECTION = Im.Contacts.CONTACTLIST
- + "=? AND " + NON_CHAT_AND_BLOCKED_CONTACTS;
- private static final String ONLINE_CONTACT_SELECTION = CONTACTS_SELECTION
- + " AND "+ Im.Contacts.PRESENCE_STATUS + " != " + Im.Presence.OFFLINE;
- static final void log(String msg) {
- Log.d(ImApp.LOG_TAG, "<ContactListAdapter>" + msg);
- }
- static final String[] CONTACT_COUNT_PROJECTION = {
- Im.Contacts.CONTACTLIST,
- Im.Contacts._COUNT,
- };
- ContentQueryMap mOnlineContactsCountMap;
- // Async QueryHandler
- private final class QueryHandler extends AsyncQueryHandler {
- public QueryHandler(Context context) {
- super(context.getContentResolver());
- }
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor c) {
- if(Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("onQueryComplete:token=" + token);
- }
- if (token == TOKEN_CONTACT_LISTS) {
- mDataValid = true;
- mAdapter.setGroupCursor(c);
- } else if (token == TOKEN_ONGOING_CONVERSATION) {
- setOngoingConversations(c);
- notifyDataSetChanged();
- } else if (token == TOKEN_SUBSCRITPTION) {
- setSubscriptions(c);
- notifyDataSetChanged();
- } else {
- int count = mAdapter.getGroupCount();
- for (int pos = 0; pos < count; pos++) {
- long listId = mAdapter.getGroupId(pos);
- if (listId == token) {
- mAdapter.setChildrenCursor(pos, c);
- break;
- }
- }
- }
- }
- }
- private QueryHandler mQueryHandler;
- private int mScrollState;
- private boolean mAutoRequery;
- private boolean mRequeryPending;
- public ContactListTreeAdapter(IImConnection conn, Activity activity) {
- mActivity = activity;
- mInflate = activity.getLayoutInflater();
- mHandler = new SimpleAlertHandler(activity);
- mAdapter = new ListTreeAdapter(null);
- mContentObserver = new MyContentObserver();
- mDataSetObserver = new MyDataSetObserver();
- mExpandedGroups = new ArrayList<Integer>();
- mQueryHandler = new QueryHandler(activity);
- changeConnection(conn);
- }
- public void changeConnection(IImConnection conn) {
- mQueryHandler.cancelOperation(TOKEN_ONGOING_CONVERSATION);
- mQueryHandler.cancelOperation(TOKEN_SUBSCRITPTION);
- mQueryHandler.cancelOperation(TOKEN_CONTACT_LISTS);
- synchronized (this) {
- if (mOngoingConversations != null) {
- mOngoingConversations.close();
- mOngoingConversations = null;
- }
- if (mSubscriptions != null) {
- mSubscriptions.close();
- mSubscriptions = null;
- }
- if (mOnlineContactsCountMap != null) {
- mOnlineContactsCountMap.close();
- }
- }
- mAdapter.notifyDataSetChanged();
- if (conn != null) {
- try {
- mProviderId = conn.getProviderId();
- mAccountId = conn.getAccountId();
- startQueryOngoingConversations();
- startQueryContactLists();
- startQuerySubscriptions();
- } catch (RemoteException e) {
- // Service died!
- }
- }
- }
- public void setHideOfflineContacts(boolean hide) {
- if (mHideOfflineContacts != hide) {
- mHideOfflineContacts = hide;
- mAdapter.notifyDataSetChanged();
- }
- }
- public void startAutoRequery() {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("startAutoRequery()");
- }
- mAutoRequery = true;
- if (mRequeryPending) {
- mRequeryPending = false;
- startQueryOngoingConversations();
- }
- }
- private void startQueryContactLists() {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("startQueryContactLists()");
- }
- Uri uri = Im.ContactList.CONTENT_URI;
- uri = ContentUris.withAppendedId(uri, mProviderId);
- uri = ContentUris.withAppendedId(uri, mAccountId);
- mQueryHandler.startQuery(TOKEN_CONTACT_LISTS, null, uri, CONTACT_LIST_PROJECTION,
- null, null, Im.ContactList.DEFAULT_SORT_ORDER);
- }
- void startQueryOngoingConversations() {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("startQueryOngoingConversations()");
- }
- Uri uri = Im.Contacts.CONTENT_URI_CHAT_CONTACTS_BY;
- uri = ContentUris.withAppendedId(uri, mProviderId);
- uri = ContentUris.withAppendedId(uri, mAccountId);
- mQueryHandler.startQuery(TOKEN_ONGOING_CONVERSATION, null, uri,
- ContactView.CONTACT_PROJECTION, null, null, Im.Contacts.DEFAULT_SORT_ORDER);
- }
- void startQuerySubscriptions() {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("startQuerySubscriptions()");
- }
- Uri uri = Im.Contacts.CONTENT_URI_CONTACTS_BY;
- uri = ContentUris.withAppendedId(uri, mProviderId);
- uri = ContentUris.withAppendedId(uri, mAccountId);
- mQueryHandler.startQuery(TOKEN_SUBSCRITPTION, null, uri,
- ContactView.CONTACT_PROJECTION,
- String.format("%s=%d AND %s=%d",
- Im.Contacts.SUBSCRIPTION_STATUS, Im.Contacts.SUBSCRIPTION_STATUS_SUBSCRIBE_PENDING,
- Im.Contacts.SUBSCRIPTION_TYPE, Im.Contacts.SUBSCRIPTION_TYPE_FROM),
- null,Im.Contacts.DEFAULT_SORT_ORDER);
- }
- void startQueryContacts(long listId) {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("startQueryContacts - listId=" + listId);
- }
- String selection = mHideOfflineContacts ? ONLINE_CONTACT_SELECTION : CONTACTS_SELECTION;
- String[] args = { Long.toString(listId) };
- int token = (int)listId;
- mQueryHandler.startQuery(token, null, Im.Contacts.CONTENT_URI,
- ContactView.CONTACT_PROJECTION, selection, args, Im.Contacts.DEFAULT_SORT_ORDER);
- }
- public Object getChild(int groupPosition, int childPosition) {
- if (isPosForOngoingConversation(groupPosition)) {
- // No cursor exists for the "Empty" TextView item
- if (getOngoingConversationCount() == 0) return null;
- return moveTo(getOngoingConversations(), childPosition);
- } else if (isPosForSubscription(groupPosition)) {
- return moveTo(getSubscriptions(), childPosition);
- } else {
- return mAdapter.getChild(getChildAdapterPosition(groupPosition), childPosition);
- }
- }
- public long getChildId(int groupPosition, int childPosition) {
- if (isPosForOngoingConversation(groupPosition)) {
- // No cursor id exists for the "Empty" TextView item
- if (getOngoingConversationCount() == 0) return 0;
- return getId(getOngoingConversations(), childPosition);
- } else if (isPosForSubscription(groupPosition)) {
- return getId(getSubscriptions(), childPosition);
- } else {
- return mAdapter.getChildId(getChildAdapterPosition(groupPosition), childPosition);
- }
- }
- public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
- View convertView, ViewGroup parent) {
- boolean isOngoingConversation = isPosForOngoingConversation(groupPosition);
- boolean displayEmpty = isOngoingConversation && (getOngoingConversationCount() == 0);
- if (isOngoingConversation || isPosForSubscription(groupPosition)) {
- View view = null;
- if (convertView != null) {
- // use the convert view if it matches the type required by displayEmpty
- if (displayEmpty && (convertView instanceof TextView)) {
- view = convertView;
- ((TextView) view).setText(mActivity.getText(R.string.empty_conversation_group));
- } else if (!displayEmpty && (convertView instanceof ContactView)) {
- view = convertView;
- }
- }
- if (view == null) {
- if (displayEmpty) {
- view = newEmptyView(parent);
- } else {
- view = newChildView(parent);
- }
- }
- if (!displayEmpty) {
- Cursor cursor = isPosForOngoingConversation(groupPosition)
- ? getOngoingConversations() : getSubscriptions();
- cursor.moveToPosition(childPosition);
- ((ContactView) view).bind(cursor, null, isScrolling());
- }
- return view;
- } else {
- return mAdapter.getChildView(getChildAdapterPosition(groupPosition), childPosition,
- isLastChild, convertView, parent);
- }
- }
- public int getChildrenCount(int groupPosition) {
- if (!mDataValid) {
- return 0;
- }
- if (isPosForOngoingConversation(groupPosition)) {
- // if there are no ongoing conversations, we want to display "empty" textview
- int count = getOngoingConversationCount();
- if (count == 0) {
- count = 1;
- }
- return count;
- } else if (isPosForSubscription(groupPosition)) {
- return getSubscriptionCount();
- } else {
- // XXX getChildrenCount() may be called with an invalid groupPosition that is larger
- // than the total number of all groups.
- int position = getChildAdapterPosition(groupPosition);
- if (position >= mAdapter.getGroupCount()) {
- Log.w(ImApp.LOG_TAG, "getChildrenCount out of range");
- return 0;
- }
- return mAdapter.getChildrenCount(position);
- }
- }
- public Object getGroup(int groupPosition) {
- if (isPosForOngoingConversation(groupPosition)
- || isPosForSubscription(groupPosition)) {
- return null;
- } else {
- return mAdapter.getGroup(getChildAdapterPosition(groupPosition));
- }
- }
- public int getGroupCount() {
- if (!mDataValid) {
- return 0;
- }
- int count = mAdapter.getGroupCount();
- // ongoing conversations
- count++;
- if (getSubscriptionCount() > 0) {
- count++;
- }
- return count;
- }
- public long getGroupId(int groupPosition) {
- if (isPosForOngoingConversation(groupPosition) || isPosForSubscription(groupPosition)) {
- return 0;
- } else {
- return mAdapter.getGroupId(getChildAdapterPosition(groupPosition));
- }
- }
- public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
- ViewGroup parent) {
- if (isPosForOngoingConversation(groupPosition) || isPosForSubscription(groupPosition)) {
- View v;
- if (convertView != null) {
- v = convertView;
- } else {
- v = newGroupView(parent);
- }
- TextView text1 = (TextView)v.findViewById(R.id.text1);
- TextView text2 = (TextView)v.findViewById(R.id.text2);
- Resources r = v.getResources();
- ImApp app = ImApp.getApplication(mActivity);
- BrandingResources brandingRes = app.getBrandingResource(mProviderId);
- String text = isPosForOngoingConversation(groupPosition) ?
- brandingRes.getString(
- BrandingResourceIDs.STRING_ONGOING_CONVERSATION,
- getOngoingConversationCount()) :
- r.getString(R.string.subscriptions);
- text1.setText(text);
- text2.setVisibility(View.GONE);
- return v;
- } else {
- return mAdapter.getGroupView(getChildAdapterPosition(groupPosition), isExpanded,
- convertView, parent);
- }
- }
- public boolean isChildSelectable(int groupPosition, int childPosition) {
- if (isPosForOngoingConversation(groupPosition)) {
- // "Empty" TextView is not selectable
- if (getOngoingConversationCount()==0) return false;
- return true;
- }
- if (isPosForSubscription(groupPosition)) return true;
- return mAdapter.isChildSelectable(getChildAdapterPosition(groupPosition), childPosition);
- }
- public boolean stableIds() {
- return true;
- }
- @Override
- public void registerDataSetObserver(DataSetObserver observer) {
- mAdapter.registerDataSetObserver(observer);
- super.registerDataSetObserver(observer);
- }
- @Override
- public void unregisterDataSetObserver(DataSetObserver observer) {
- mAdapter.unregisterDataSetObserver(observer);
- super.unregisterDataSetObserver(observer);
- }
- public boolean hasStableIds() {
- return true;
- }
- @Override
- public void onGroupCollapsed(int groupPosition) {
- super.onGroupCollapsed(groupPosition);
- mExpandedGroups.remove(Integer.valueOf(groupPosition));
- int pos = getChildAdapterPosition(groupPosition);
- if (pos >= 0) {
- mAdapter.onGroupCollapsed(pos);
- }
- }
- @Override
- public void onGroupExpanded(int groupPosition) {
- super.onGroupExpanded(groupPosition);
- mExpandedGroups.add(groupPosition);
- int pos = getChildAdapterPosition(groupPosition);
- if (pos >= 0) {
- mAdapter.onGroupExpanded(pos);
- }
- }
- public int[] getExpandedGroups() {
- ArrayList<Integer> expandedGroups = mExpandedGroups;
- int size = expandedGroups.size();
- int[] res = new int[size];
- for (int i = 0; i < size; i++) {
- res[i] = expandedGroups.get(i);
- }
- return res;
- }
- View newChildView(ViewGroup parent) {
- return mInflate.inflate(R.layout.contact_view, parent, false);
- }
- View newEmptyView(ViewGroup parent) {
- return mInflate.inflate(R.layout.empty_conversation_group_view, parent, false);
- }
- View newGroupView(ViewGroup parent) {
- return mInflate.inflate(R.layout.group_view, parent, false);
- }
- private synchronized Cursor getOngoingConversations() {
- if (mOngoingConversations == null) {
- startQueryOngoingConversations();
- }
- return mOngoingConversations;
- }
- synchronized void setOngoingConversations(Cursor c) {
- if (mOngoingConversations != null) {
- mOngoingConversations.unregisterContentObserver(mContentObserver);
- mOngoingConversations.unregisterDataSetObserver(mDataSetObserver);
- mOngoingConversations.close();
- }
- c.registerContentObserver(mContentObserver);
- c.registerDataSetObserver(mDataSetObserver);
- mOngoingConversations = c;
- }
- private int getOngoingConversationCount() {
- Cursor c = getOngoingConversations();
- return c == null ? 0 : c.getCount();
- }
- private synchronized Cursor getSubscriptions() {
- if (mSubscriptions == null) {
- startQuerySubscriptions();
- }
- return mSubscriptions;
- }
- synchronized void setSubscriptions(Cursor c) {
- if (mSubscriptions != null) {
- mSubscriptions.close();
- }
- // we don't need to register observers on mSubscriptions because
- // we already have observers on mOngoingConversations and they
- // will be notified if there is any changes of subscription
- // since the two cursors come from the same table.
- mSubscriptions = c;
- }
- private int getSubscriptionCount() {
- Cursor c = getSubscriptions();
- return c == null ? 0 : c.getCount();
- }
- public boolean isPosForOngoingConversation(int groupPosition) {
- return groupPosition == 0;
- }
- public boolean isPosForSubscription(int groupPosition) {
- return groupPosition == 1 && getSubscriptionCount() > 0;
- }
- private int getChildAdapterPosition(int groupPosition) {
- if (getSubscriptionCount() > 0) {
- return groupPosition - 2;
- } else {
- return groupPosition - 1;
- }
- }
- private Cursor moveTo(Cursor cursor, int position) {
- if (cursor.moveToPosition(position)) {
- return cursor;
- }
- return null;
- }
- private long getId(Cursor cursor, int position) {
- if (cursor.moveToPosition(position)) {
- return cursor.getLong(ContactView.COLUMN_CONTACT_ID);
- }
- return 0;
- }
- class ListTreeAdapter extends CursorTreeAdapter {
- public ListTreeAdapter(Cursor cursor) {
- super(cursor, mActivity);
- }
- @Override
- protected void bindChildView(View view, Context context, Cursor cursor,
- boolean isLastChild) {
- // binding when child is text view for an empty group
- if (view instanceof TextView) {
- ((TextView) view).setText(mActivity.getText(R.string.empty_contact_group));
- } else {
- ((ContactView) view).bind(cursor, null, isScrolling());
- }
- }
- @Override
- protected void bindGroupView(View view, Context context, Cursor cursor,
- boolean isExpanded) {
- TextView text1 = (TextView)view.findViewById(R.id.text1);
- TextView text2 = (TextView)view.findViewById(R.id.text2);
- Resources r = view.getResources();
- text1.setText(cursor.getString(COLUMN_CONTACT_LIST_NAME));
- text2.setVisibility(View.VISIBLE);
- text2.setText(r.getString(R.string.online_count, getOnlineChildCount(cursor)));
- }
- View newEmptyView(ViewGroup parent) {
- return mInflate.inflate(R.layout.empty_contact_group_view, parent, false);
- }
- // if the group is empty, provide a text view. The infrastructure provides a "convertView"
- // as a possible suggestion to reuse an existing view's data. It may be null, it may be a
- // TextView, or it may be a ContactView, so we need to test the possible cases.
- @Override
- public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
- View convertView, ViewGroup parent) {
- // Provide a TextView if the group is empty
- if (super.getChildrenCount(groupPosition)==0) {
- if (convertView != null) {
- if (convertView instanceof TextView) {
- ((TextView) convertView).setText(
- mActivity.getText(R.string.empty_contact_group));
- return convertView;
- }
- }
- return newEmptyView(parent);
- }
- if ( !(convertView instanceof ContactView) ) {
- convertView = null;
- }
- return super.getChildView(groupPosition, childPosition, isLastChild, convertView,
- parent);
- }
- @Override
- protected Cursor getChildrenCursor(Cursor groupCursor) {
- long listId = groupCursor.getLong(COLUMN_CONTACT_LIST_ID);
- startQueryContacts(listId);
- return null;
- }
- // return a TextView for empty groups
- @Override
- protected View newChildView(Context context, Cursor cursor, boolean isLastChild,
- ViewGroup parent) {
- if (cursor.getCount() == 0) {
- return newEmptyView(parent);
- } else {
- return ContactListTreeAdapter.this.newChildView(parent);
- }
- }
- @Override
- protected View newGroupView(Context context, Cursor cursor, boolean isExpanded,
- ViewGroup parent) {
- return ContactListTreeAdapter.this.newGroupView(parent);
- }
- private int getOnlineChildCount(Cursor groupCursor) {
- long listId = groupCursor.getLong(COLUMN_CONTACT_LIST_ID);
- if (mOnlineContactsCountMap == null) {
- String where = Im.Contacts.ACCOUNT + "=" + mAccountId;
- ContentResolver cr = mActivity.getContentResolver();
- Cursor c = cr.query(Im.Contacts.CONTENT_URI_ONLINE_COUNT,
- CONTACT_COUNT_PROJECTION, where, null, null);
- mOnlineContactsCountMap = new ContentQueryMap(c,
- Im.Contacts.CONTACTLIST, true, mHandler);
- mOnlineContactsCountMap.addObserver(new Observer(){
- public void update(Observable observable, Object data) {
- notifyDataSetChanged();
- }});
- }
- ContentValues value = mOnlineContactsCountMap.getValues(String.valueOf(listId));
- return value == null ? 0 : value.getAsInteger(Im.Contacts._COUNT);
- }
- @Override
- public int getChildrenCount(int groupPosition) {
- int children = super.getChildrenCount(groupPosition);
- if (children == 0) {
- // Count the empty group text item as a child
- return 1;
- }
- return children;
- }
- // Don't allow the empty group text item to be selected
- @Override
- public boolean isChildSelectable(int groupPosition, int childPosition) {
- return (super.getChildrenCount(groupPosition) > 0);
- }
- }
- private class MyContentObserver extends ContentObserver {
- public MyContentObserver() {
- super(mHandler);
- }
- @Override
- public void onChange(boolean selfChange) {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("MyContentObserver.onChange() autoRequery=" + mAutoRequery);
- }
- // Don't requery when fling. We will schedule a requery when the fling is complete.
- if (isScrolling()) {
- return;
- }
- if (mAutoRequery) {
- startQueryOngoingConversations();
- } else {
- mRequeryPending = true;
- }
- }
- }
- private class MyDataSetObserver extends DataSetObserver {
- public MyDataSetObserver() {
- }
- @Override
- public void onChanged() {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("MyDataSetObserver.onChanged()");
- }
- mDataValid = true;
- notifyDataSetChanged();
- }
- @Override
- public void onInvalidated() {
- if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){
- log("MyDataSetObserver.onInvalidated()");
- }
- mDataValid = false;
- notifyDataSetInvalidated();
- }
- }
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
- // no op
- }
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- int oldState = mScrollState;
- mScrollState = scrollState;
- // If we just finished a fling then some items may not have an icon
- // So force a full redraw now that the fling is complete
- if (oldState == OnScrollListener.SCROLL_STATE_FLING) {
- notifyDataSetChanged();
- }
- }
- public boolean isScrolling() {
- return mScrollState == OnScrollListener.SCROLL_STATE_FLING;
- }
- }