Android Open Source - CCSocialNetwork Graph Object Adapter






From Project

Back to project page CCSocialNetwork.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project CCSocialNetwork listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * Copyright 2010-present Facebook.//  ww  w  .  j  a  va  2 s . c o  m
 *
 * 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.facebook.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.*;
import com.facebook.*;
import com.facebook.android.R;
import com.facebook.model.GraphObject;
import org.json.JSONObject;

import java.net.MalformedURLException;
import java.net.URL;
import java.text.Collator;
import java.util.*;

class GraphObjectAdapter<T extends GraphObject> extends BaseAdapter implements SectionIndexer {
    private static final int DISPLAY_SECTIONS_THRESHOLD = 1;
    private static final int HEADER_VIEW_TYPE = 0;
    private static final int GRAPH_OBJECT_VIEW_TYPE = 1;
    private static final int ACTIVITY_CIRCLE_VIEW_TYPE = 2;
    private static final int MAX_PREFETCHED_PICTURES = 20;

    private static final String ID = "id";
    private static final String NAME = "name";
    private static final String PICTURE = "picture";

    private final Map<String, ImageRequest> pendingRequests = new HashMap<String, ImageRequest>();
    private final LayoutInflater inflater;
    private List<String> sectionKeys = new ArrayList<String>();
    private Map<String, ArrayList<T>> graphObjectsBySection = new HashMap<String, ArrayList<T>>();
    private Map<String, T> graphObjectsById = new HashMap<String, T>();
    private boolean displaySections;
    private List<String> sortFields;
    private String groupByField;
    private boolean showPicture;
    private boolean showCheckbox;
    private Filter<T> filter;
    private DataNeededListener dataNeededListener;
    private GraphObjectCursor<T> cursor;
    private Context context;
    private Map<String, ImageResponse> prefetchedPictureCache = new HashMap<String, ImageResponse>();
    private ArrayList<String> prefetchedProfilePictureIds = new ArrayList<String>();
    private OnErrorListener onErrorListener;

    public interface DataNeededListener {
        public void onDataNeeded();
    }

    public interface OnErrorListener {
        void onError(GraphObjectAdapter<?> adapter, FacebookException error);
    }

    public static class SectionAndItem<T extends GraphObject> {
        public String sectionKey;
        public T graphObject;

        public enum Type {
            GRAPH_OBJECT,
            SECTION_HEADER,
            ACTIVITY_CIRCLE
        }

        public SectionAndItem(String sectionKey, T graphObject) {
            this.sectionKey = sectionKey;
            this.graphObject = graphObject;
        }

        public Type getType() {
            if (sectionKey == null) {
                return Type.ACTIVITY_CIRCLE;
            } else if (graphObject == null) {
                return Type.SECTION_HEADER;
            } else {
                return Type.GRAPH_OBJECT;
            }
        }
    }

    interface Filter<T> {
        boolean includeItem(T graphObject);
    }

    public GraphObjectAdapter(Context context) {
        this.context = context;
        this.inflater = LayoutInflater.from(context);
    }

    public List<String> getSortFields() {
        return sortFields;
    }

    public void setSortFields(List<String> sortFields) {
        this.sortFields = sortFields;
    }

    public String getGroupByField() {
        return groupByField;
    }

    public void setGroupByField(String groupByField) {
        this.groupByField = groupByField;
    }

    public boolean getShowPicture() {
        return showPicture;
    }

    public void setShowPicture(boolean showPicture) {
        this.showPicture = showPicture;
    }

    public boolean getShowCheckbox() {
        return showCheckbox;
    }

    public void setShowCheckbox(boolean showCheckbox) {
        this.showCheckbox = showCheckbox;
    }

    public DataNeededListener getDataNeededListener() {
        return dataNeededListener;
    }

    public void setDataNeededListener(DataNeededListener dataNeededListener) {
        this.dataNeededListener = dataNeededListener;
    }

    public OnErrorListener getOnErrorListener() {
        return onErrorListener;
    }

    public void setOnErrorListener(OnErrorListener onErrorListener) {
        this.onErrorListener = onErrorListener;
    }

    public GraphObjectCursor<T> getCursor() {
        return cursor;
    }

    public boolean changeCursor(GraphObjectCursor<T> cursor) {
        if (this.cursor == cursor) {
            return false;
        }
        if (this.cursor != null) {
            this.cursor.close();
        }
        this.cursor = cursor;

        rebuildAndNotify();
        return true;
    }

    public void rebuildAndNotify() {
        rebuildSections();
        notifyDataSetChanged();
    }

    public void prioritizeViewRange(int firstVisibleItem, int lastVisibleItem, int prefetchBuffer) {
        if (lastVisibleItem < firstVisibleItem) {
            return;
        }

        // We want to prioritize requests for items which are visible but do not have pictures
        // loaded yet. We also want to pre-fetch pictures for items which are not yet visible
        // but are within a buffer on either side of the visible items, on the assumption that
        // they will be visible soon. For these latter items, we'll store the images in memory
        // in the hopes we can immediately populate their image view when needed.

        // Prioritize the requests in reverse order since each call to prioritizeRequest will just
        // move it to the front of the queue. And we want the earliest ones in the range to be at
        // the front of the queue, so all else being equal, the list will appear to populate from
        // the top down.
        for (int i = lastVisibleItem; i >= 0; i--) {
            SectionAndItem<T> sectionAndItem = getSectionAndItem(i);
            if (sectionAndItem.graphObject != null) {
                String id = getIdOfGraphObject(sectionAndItem.graphObject);
                ImageRequest request = pendingRequests.get(id);
                if (request != null) {
                    ImageDownloader.prioritizeRequest(request);
                }
            }
        }

        // For items which are not visible, but within the buffer on either side, we want to
        // fetch those items and store them in a small in-memory cache of bitmaps.
        int start = Math.max(0, firstVisibleItem - prefetchBuffer);
        int end = Math.min(lastVisibleItem + prefetchBuffer, getCount() - 1);
        ArrayList<T> graphObjectsToPrefetchPicturesFor = new ArrayList<T>();
        // Add the IDs before and after the visible range.
        for (int i = start; i < firstVisibleItem; ++i) {
            SectionAndItem<T> sectionAndItem = getSectionAndItem(i);
            if (sectionAndItem.graphObject != null) {
                graphObjectsToPrefetchPicturesFor.add(sectionAndItem.graphObject);
            }
        }
        for (int i = lastVisibleItem + 1; i <= end; ++i) {
            SectionAndItem<T> sectionAndItem = getSectionAndItem(i);
            if (sectionAndItem.graphObject != null) {
                graphObjectsToPrefetchPicturesFor.add(sectionAndItem.graphObject);
            }
        }
        for (T graphObject : graphObjectsToPrefetchPicturesFor) {
            URL url = getPictureUrlOfGraphObject(graphObject);
            final String id = getIdOfGraphObject(graphObject);

            // This URL already have been requested for pre-fetching, but we want to act in an LRU manner, so move
            // it to the end of the list regardless.
            boolean alreadyPrefetching = prefetchedProfilePictureIds.remove(id);
            prefetchedProfilePictureIds.add(id);

            // If we've already requested it for pre-fetching, no need to do so again.
            if (!alreadyPrefetching) {
                downloadProfilePicture(id, url, null);
            }
        }
    }

    protected String getSectionKeyOfGraphObject(T graphObject) {
        String result = null;

        if (groupByField != null) {
            result = (String) graphObject.getProperty(groupByField);
            if (result != null && result.length() > 0) {
                result = result.substring(0, 1).toUpperCase();
            }
        }

        return (result != null) ? result : "";
    }

    protected CharSequence getTitleOfGraphObject(T graphObject) {
        return (String) graphObject.getProperty(NAME);
    }

    protected CharSequence getSubTitleOfGraphObject(T graphObject) {
        return null;
    }

    protected URL getPictureUrlOfGraphObject(T graphObject) {
        String url = null;
        Object o = graphObject.getProperty(PICTURE);
        if (o instanceof String) {
            url = (String) o;
        } else if (o instanceof JSONObject) {
            ItemPicture itemPicture = GraphObject.Factory.create((JSONObject) o).cast(ItemPicture.class);
            ItemPictureData data = itemPicture.getData();
            if (data != null) {
                url = data.getUrl();
            }
        }

        if (url != null) {
            try {
                return new URL(url);
            } catch (MalformedURLException e) {
            }
        }
        return null;
    }

    protected View getSectionHeaderView(String sectionHeader, View convertView, ViewGroup parent) {
        TextView result = (TextView) convertView;

        if (result == null) {
            result = (TextView) inflater.inflate(R.layout.com_facebook_picker_list_section_header, null);
        }

        result.setText(sectionHeader);

        return result;
    }

    protected View getGraphObjectView(T graphObject, View convertView, ViewGroup parent) {
        View result = convertView;

        if (result == null) {
            result = createGraphObjectView(graphObject, convertView);
        }

        populateGraphObjectView(result, graphObject);
        return result;
    }

    private View getActivityCircleView(View convertView, ViewGroup parent) {
        View result = convertView;

        if (result == null) {
            result = inflater.inflate(R.layout.com_facebook_picker_activity_circle_row, null);
        }
        ProgressBar activityCircle = (ProgressBar) result.findViewById(R.id.com_facebook_picker_row_activity_circle);
        activityCircle.setVisibility(View.VISIBLE);

        return result;
    }

    protected int getGraphObjectRowLayoutId(T graphObject) {
        return R.layout.com_facebook_picker_list_row;
    }

    protected int getDefaultPicture() {
        return R.drawable.com_facebook_profile_default_icon;
    }

    protected View createGraphObjectView(T graphObject, View convertView) {
        View result = inflater.inflate(getGraphObjectRowLayoutId(graphObject), null);

        ViewStub checkboxStub = (ViewStub) result.findViewById(R.id.com_facebook_picker_checkbox_stub);
        if (checkboxStub != null) {
            if (!getShowCheckbox()) {
                checkboxStub.setVisibility(View.GONE);
            } else {
                CheckBox checkBox = (CheckBox) checkboxStub.inflate();
                updateCheckboxState(checkBox, false);
            }
        }

        ViewStub profilePicStub = (ViewStub) result.findViewById(R.id.com_facebook_picker_profile_pic_stub);
        if (!getShowPicture()) {
            profilePicStub.setVisibility(View.GONE);
        } else {
            ImageView imageView = (ImageView) profilePicStub.inflate();
            imageView.setVisibility(View.VISIBLE);
        }

        return result;
    }

    protected void populateGraphObjectView(View view, T graphObject) {
        String id = getIdOfGraphObject(graphObject);
        view.setTag(id);

        CharSequence title = getTitleOfGraphObject(graphObject);
        TextView titleView = (TextView) view.findViewById(R.id.com_facebook_picker_title);
        if (titleView != null) {
            titleView.setText(title, TextView.BufferType.SPANNABLE);
        }

        CharSequence subtitle = getSubTitleOfGraphObject(graphObject);
        TextView subtitleView = (TextView) view.findViewById(R.id.picker_subtitle);
        if (subtitleView != null) {
            if (subtitle != null) {
                subtitleView.setText(subtitle, TextView.BufferType.SPANNABLE);
                subtitleView.setVisibility(View.VISIBLE);
            } else {
                subtitleView.setVisibility(View.GONE);
            }
        }

        if (getShowCheckbox()) {
            CheckBox checkBox = (CheckBox) view.findViewById(R.id.com_facebook_picker_checkbox);
            updateCheckboxState(checkBox, isGraphObjectSelected(id));
        }

        if (getShowPicture()) {
            URL pictureURL = getPictureUrlOfGraphObject(graphObject);

            if (pictureURL != null) {
                ImageView profilePic = (ImageView) view.findViewById(R.id.com_facebook_picker_image);

                // See if we have already pre-fetched this; if not, download it.
                if (prefetchedPictureCache.containsKey(id)) {
                    ImageResponse response = prefetchedPictureCache.get(id);
                    profilePic.setImageBitmap(response.getBitmap());
                    profilePic.setTag(response.getRequest().getImageUrl());
                } else {
                    downloadProfilePicture(id, pictureURL, profilePic);
                }
            }
        }
    }

    /**
     * @throws FacebookException if the GraphObject doesn't have an ID.
     */
    String getIdOfGraphObject(T graphObject) {
        if (graphObject.asMap().containsKey(ID)) {
            Object obj = graphObject.getProperty(ID);
            if (obj instanceof String) {
                return (String) obj;
            }
        }
        throw new FacebookException("Received an object without an ID.");
    }

    boolean filterIncludesItem(T graphObject) {
        return filter == null || filter.includeItem(graphObject);
    }

    Filter<T> getFilter() {
        return filter;
    }

    void setFilter(Filter<T> filter) {
        this.filter = filter;
    }

    boolean isGraphObjectSelected(String graphObjectId) {
        return false;
    }

    void updateCheckboxState(CheckBox checkBox, boolean graphObjectSelected) {
        // Default is no-op
    }

    String getPictureFieldSpecifier() {
        // How big is our image?
        View view = createGraphObjectView(null, null);
        ImageView picture = (ImageView) view.findViewById(R.id.com_facebook_picker_image);
        if (picture == null) {
            return null;
        }

        // Note: these dimensions are in pixels, not dips
        ViewGroup.LayoutParams layoutParams = picture.getLayoutParams();
        return String.format("picture.height(%d).width(%d)", layoutParams.height, layoutParams.width);
    }


    private boolean shouldShowActivityCircleCell() {
        // We show the "more data" activity circle cell if we have a listener to request more data,
        // we are expecting more data, and we have some data already (i.e., not on a fresh query).
        return (cursor != null) && cursor.areMoreObjectsAvailable() && (dataNeededListener != null) && !isEmpty();
    }

    private void rebuildSections() {
        sectionKeys = new ArrayList<String>();
        graphObjectsBySection = new HashMap<String, ArrayList<T>>();
        graphObjectsById = new HashMap<String, T>();
        displaySections = false;

        if (cursor == null || cursor.getCount() == 0) {
            return;
        }

        int objectsAdded = 0;
        cursor.moveToFirst();
        do {
            T graphObject = cursor.getGraphObject();

            if (!filterIncludesItem(graphObject)) {
                continue;
            }

            objectsAdded++;

            String sectionKeyOfItem = getSectionKeyOfGraphObject(graphObject);
            if (!graphObjectsBySection.containsKey(sectionKeyOfItem)) {
                sectionKeys.add(sectionKeyOfItem);
                graphObjectsBySection.put(sectionKeyOfItem, new ArrayList<T>());
            }
            List<T> section = graphObjectsBySection.get(sectionKeyOfItem);
            section.add(graphObject);

            graphObjectsById.put(getIdOfGraphObject(graphObject), graphObject);
        } while (cursor.moveToNext());

        if (sortFields != null) {
            final Collator collator = Collator.getInstance();
            for (List<T> section : graphObjectsBySection.values()) {
                Collections.sort(section, new Comparator<GraphObject>() {
                    @Override
                    public int compare(GraphObject a, GraphObject b) {
                        return compareGraphObjects(a, b, sortFields, collator);
                    }
                });
            }
        }

        Collections.sort(sectionKeys, Collator.getInstance());

        displaySections = sectionKeys.size() > 1 && objectsAdded > DISPLAY_SECTIONS_THRESHOLD;
    }

    SectionAndItem<T> getSectionAndItem(int position) {
        if (sectionKeys.size() == 0) {
            return null;
        }
        String sectionKey = null;
        T graphObject = null;

        if (!displaySections) {
            sectionKey = sectionKeys.get(0);
            List<T> section = graphObjectsBySection.get(sectionKey);
            if (position >= 0 && position < section.size()) {
                graphObject = graphObjectsBySection.get(sectionKey).get(position);
            } else {
                // We are off the end; we must be adding an activity circle to indicate more data is coming.
                assert dataNeededListener != null && cursor.areMoreObjectsAvailable();
                // We return null for both to indicate this.
                return new SectionAndItem<T>(null, null);
            }
        } else {
            // Count through the sections; the "0" position in each section is the header. We decrement
            // position each time we skip forward a certain number of elements, including the header.
            for (String key : sectionKeys) {
                // Decrement if we skip over the header
                if (position-- == 0) {
                    sectionKey = key;
                    break;
                }

                List<T> section = graphObjectsBySection.get(key);
                if (position < section.size()) {
                    // The position is somewhere in this section. Get the corresponding graph object.
                    sectionKey = key;
                    graphObject = section.get(position);
                    break;
                }
                // Decrement by as many items as we skipped over
                position -= section.size();
            }
        }
        if (sectionKey != null) {
            // Note: graphObject will be null if this represents a section header.
            return new SectionAndItem<T>(sectionKey, graphObject);
        } else {
            throw new IndexOutOfBoundsException("position");
        }
    }

    int getPosition(String sectionKey, T graphObject) {
        int position = 0;
        boolean found = false;

        // First find the section key and increment position one for each header we will render;
        // increment by the size of each section prior to the one we want.
        for (String key : sectionKeys) {
            if (displaySections) {
                position++;
            }
            if (key.equals(sectionKey)) {
                found = true;
                break;
            } else {
                position += graphObjectsBySection.get(key).size();
            }
        }

        if (!found) {
            return -1;
        } else if (graphObject == null) {
            // null represents the header for a section; we counted this header in position earlier,
            // so subtract it back out.
            return position - (displaySections ? 1 : 0);
        }

        // Now find index of this item within that section.
        for (T t : graphObjectsBySection.get(sectionKey)) {
            if (GraphObject.Factory.hasSameId(t, graphObject)) {
                return position;
            }
            position++;
        }
        return -1;
    }

    @Override
    public boolean isEmpty() {
        // We'll never populate sectionKeys unless we have at least one object.
        return sectionKeys.size() == 0;
    }

    @Override
    public int getCount() {
        if (sectionKeys.size() == 0) {
            return 0;
        }

        // If we are not displaying sections, we don't display a header; otherwise, we have one header per item in
        // addition to the actual items.
        int count = (displaySections) ? sectionKeys.size() : 0;
        for (List<T> section : graphObjectsBySection.values()) {
            count += section.size();
        }

        // If we should show a cell with an activity circle indicating more data is coming, add it to the count.
        if (shouldShowActivityCircleCell()) {
            ++count;
        }

        return count;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return displaySections;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public boolean isEnabled(int position) {
        SectionAndItem<T> sectionAndItem = getSectionAndItem(position);
        return sectionAndItem.getType() == SectionAndItem.Type.GRAPH_OBJECT;
    }

    @Override
    public Object getItem(int position) {
        SectionAndItem<T> sectionAndItem = getSectionAndItem(position);
        return (sectionAndItem.getType() == SectionAndItem.Type.GRAPH_OBJECT) ? sectionAndItem.graphObject : null;
    }

    @Override
    public long getItemId(int position) {
        // We assume IDs that can be converted to longs. If this is not the case for certain types of
        // GraphObjects, subclasses should override this to return, e.g., position, and override hasStableIds
        // to return false.
        SectionAndItem<T> sectionAndItem = getSectionAndItem(position);
        if (sectionAndItem != null && sectionAndItem.graphObject != null) {
            String id = getIdOfGraphObject(sectionAndItem.graphObject);
            if (id != null) {
                return Long.parseLong(id);
            }
        }
        return 0;
    }

    @Override
    public int getViewTypeCount() {
        return 3;
    }

    @Override
    public int getItemViewType(int position) {
        SectionAndItem<T> sectionAndItem = getSectionAndItem(position);
        switch (sectionAndItem.getType()) {
            case SECTION_HEADER:
                return HEADER_VIEW_TYPE;
            case GRAPH_OBJECT:
                return GRAPH_OBJECT_VIEW_TYPE;
            case ACTIVITY_CIRCLE:
                return ACTIVITY_CIRCLE_VIEW_TYPE;
            default:
                throw new FacebookException("Unexpected type of section and item.");
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        SectionAndItem<T> sectionAndItem = getSectionAndItem(position);

        switch (sectionAndItem.getType()) {
            case SECTION_HEADER:
                return getSectionHeaderView(sectionAndItem.sectionKey, convertView, parent);
            case GRAPH_OBJECT:
                return getGraphObjectView(sectionAndItem.graphObject, convertView, parent);
            case ACTIVITY_CIRCLE:
                // If we get a request for this view, it means we need more data.
                assert cursor.areMoreObjectsAvailable() && (dataNeededListener != null);
                dataNeededListener.onDataNeeded();
                return getActivityCircleView(convertView, parent);
            default:
                throw new FacebookException("Unexpected type of section and item.");
        }
    }

    @Override
    public Object[] getSections() {
        if (displaySections) {
            return sectionKeys.toArray();
        } else {
            return new Object[0];
        }
    }

    @Override
    public int getPositionForSection(int section) {
        if (displaySections) {
            section = Math.max(0, Math.min(section, sectionKeys.size() - 1));
            if (section < sectionKeys.size()) {
                return getPosition(sectionKeys.get(section), null);
            }
        }
        return 0;
    }

    @Override
    public int getSectionForPosition(int position) {
        SectionAndItem<T> sectionAndItem = getSectionAndItem(position);
        if (sectionAndItem != null &&
                sectionAndItem.getType() != SectionAndItem.Type.ACTIVITY_CIRCLE) {
            return Math.max(0, Math.min(sectionKeys.indexOf(sectionAndItem.sectionKey), sectionKeys.size() - 1));
        }
        return 0;
    }

    public List<T> getGraphObjectsById(Collection<String> ids) {
        Set<String> idSet = new HashSet<String>();
        idSet.addAll(ids);

        ArrayList<T> result = new ArrayList<T>(idSet.size());
        for (String id : idSet) {
            T graphObject = graphObjectsById.get(id);
            if (graphObject != null) {
                result.add(graphObject);
            }
        }

        return result;
    }

    private void downloadProfilePicture(final String profileId, URL pictureURL, final ImageView imageView) {
        if (pictureURL == null) {
            return;
        }

        // If we don't have an imageView, we are pre-fetching this image to store in-memory because we
        // think the user might scroll to its corresponding list row. If we do have an imageView, we
        // only want to queue a download if the view's tag isn't already set to the URL (which would mean
        // it's already got the correct picture).
        boolean prefetching = imageView == null;
        if (prefetching || !pictureURL.equals(imageView.getTag())) {
            if (!prefetching) {
                // Setting the tag to the profile ID indicates that we're currently downloading the
                // picture for this profile; we'll set it to the actual picture URL when complete.
                imageView.setTag(profileId);
                imageView.setImageResource(getDefaultPicture());
            }

            ImageRequest.Builder builder = new ImageRequest.Builder(context.getApplicationContext(), pictureURL)
                    .setCallerTag(this)
                    .setCallback(
                            new ImageRequest.Callback() {
                                @Override
                                public void onCompleted(ImageResponse response) {
                                    processImageResponse(response, profileId, imageView);
                                }
                            });

            ImageRequest newRequest = builder.build();
            pendingRequests.put(profileId, newRequest);

            ImageDownloader.downloadAsync(newRequest);
        }
    }

    private void callOnErrorListener(Exception exception) {
        if (onErrorListener != null) {
            if (!(exception instanceof FacebookException)) {
                exception = new FacebookException(exception);
            }
            onErrorListener.onError(this, (FacebookException) exception);
        }
    }

    private void processImageResponse(ImageResponse response, String graphObjectId, ImageView imageView) {
        pendingRequests.remove(graphObjectId);
        if (response.getError() != null) {
            callOnErrorListener(response.getError());
        }

        if (imageView == null) {
            // This was a pre-fetch request.
            if (response.getBitmap() != null) {
                // Is the cache too big?
                if (prefetchedPictureCache.size() >= MAX_PREFETCHED_PICTURES) {
                    // Find the oldest one and remove it.
                    String oldestId = prefetchedProfilePictureIds.remove(0);
                    prefetchedPictureCache.remove(oldestId);
                }
                prefetchedPictureCache.put(graphObjectId, response);
            }
        } else if (imageView != null && graphObjectId.equals(imageView.getTag())) {
            Exception error = response.getError();
            Bitmap bitmap = response.getBitmap();
            if (error == null && bitmap != null) {
                imageView.setImageBitmap(bitmap);
                imageView.setTag(response.getRequest().getImageUrl());
            }
        }
    }

    private static int compareGraphObjects(GraphObject a, GraphObject b, Collection<String> sortFields,
            Collator collator) {
        for (String sortField : sortFields) {
            String sa = (String) a.getProperty(sortField);
            String sb = (String) b.getProperty(sortField);

            if (sa != null && sb != null) {
                int result = collator.compare(sa, sb);
                if (result != 0) {
                    return result;
                }
            } else if (!(sa == null && sb == null)) {
                return (sa == null) ? -1 : 1;
            }
        }
        return 0;
    }


    // Graph object type to navigate the JSON that sometimes comes back instead of a URL string
    private interface ItemPicture extends GraphObject {
        ItemPictureData getData();
    }

    // Graph object type to navigate the JSON that sometimes comes back instead of a URL string
    private interface ItemPictureData extends GraphObject {
        String getUrl();
    }
}




Java Source Code List

com.facebook.AccessTokenSource.java
com.facebook.AccessToken.java
com.facebook.AuthorizationClient.java
com.facebook.FacebookAuthorizationException.java
com.facebook.FacebookDialogException.java
com.facebook.FacebookException.java
com.facebook.FacebookGraphObjectException.java
com.facebook.FacebookOperationCanceledException.java
com.facebook.FacebookRequestError.java
com.facebook.FacebookSdkVersion.java
com.facebook.FacebookServiceException.java
com.facebook.GetTokenClient.java
com.facebook.HttpMethod.java
com.facebook.InsightsLogger.java
com.facebook.LegacyHelper.java
com.facebook.LoggingBehavior.java
com.facebook.LoginActivity.java
com.facebook.NativeProtocol.java
com.facebook.NonCachingTokenCachingStrategy.java
com.facebook.RequestAsyncTask.java
com.facebook.RequestBatch.java
com.facebook.Request.java
com.facebook.Response.java
com.facebook.SessionDefaultAudience.java
com.facebook.SessionLoginBehavior.java
com.facebook.SessionState.java
com.facebook.Session.java
com.facebook.Settings.java
com.facebook.SharedPreferencesTokenCachingStrategy.java
com.facebook.TestSession.java
com.facebook.TokenCachingStrategy.java
com.facebook.UiLifecycleHelper.java
com.facebook.android.AsyncFacebookRunner.java
com.facebook.android.DialogError.java
com.facebook.android.FacebookError.java
com.facebook.android.Facebook.java
com.facebook.android.FbDialog.java
com.facebook.android.Util.java
com.facebook.internal.CacheableRequestBatch.java
com.facebook.internal.FileLruCache.java
com.facebook.internal.Logger.java
com.facebook.internal.ServerProtocol.java
com.facebook.internal.SessionAuthorizationType.java
com.facebook.internal.SessionTracker.java
com.facebook.internal.Utility.java
com.facebook.internal.Validate.java
com.facebook.internal.package-info.java
com.facebook.model.GraphLocation.java
com.facebook.model.GraphMultiResult.java
com.facebook.model.GraphObjectList.java
com.facebook.model.GraphObject.java
com.facebook.model.GraphPlace.java
com.facebook.model.GraphUser.java
com.facebook.model.JsonUtil.java
com.facebook.model.OpenGraphAction.java
com.facebook.model.PropertyName.java
com.facebook.widget.FacebookFragment.java
com.facebook.widget.FriendPickerFragment.java
com.facebook.widget.GraphObjectAdapter.java
com.facebook.widget.GraphObjectCursor.java
com.facebook.widget.GraphObjectPagingLoader.java
com.facebook.widget.ImageDownloader.java
com.facebook.widget.ImageRequest.java
com.facebook.widget.ImageResponseCache.java
com.facebook.widget.ImageResponse.java
com.facebook.widget.LoginButton.java
com.facebook.widget.PickerFragment.java
com.facebook.widget.PlacePickerFragment.java
com.facebook.widget.ProfilePictureView.java
com.facebook.widget.SimpleGraphObjectCursor.java
com.facebook.widget.UrlRedirectCache.java
com.facebook.widget.UserSettingsFragment.java
com.facebook.widget.WebDialog.java
com.facebook.widget.WorkQueue.java
org.example.SocialNetwork.CCSocialNetwork.java
org.example.SocialNetwork.EmailSender.java
org.example.SocialNetwork.InternetConnection.java