ro.weednet.contactssync.client.NetworkUtilities.java Source code

Java tutorial

Introduction

Here is the source code for ro.weednet.contactssync.client.NetworkUtilities.java

Source

/*
 * Copyright (C) 2012 Danut Chereches
 *
 * Contact: Danut Chereches <admin@weednet.ro>
 *
 * This file is part of Facebook Contact Sync.
 * 
 * Facebook Contact Sync is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Facebook Contact Sync.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */
package ro.weednet.contactssync.client;

import org.apache.http.ParseException;
import org.apache.http.auth.AuthenticationException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import ro.weednet.ContactsSync;
import ro.weednet.contactssync.authenticator.Authenticator;

import com.facebook.AccessToken;
import com.facebook.FacebookException;
import com.facebook.HttpMethod;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.Session.StatusCallback;
import com.facebook.SessionState;

import android.accounts.Account;
import android.accounts.NetworkErrorException;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Provides utility methods for communicating with the server.
 */
final public class NetworkUtilities {
    private Session mSession;

    public NetworkUtilities(String token, Context context) {
        AccessToken accessToken = AccessToken.createFromExistingAccessToken(token, null, null, null, null);
        mSession = Session.getActiveSession();
        if (mSession == null) {
            mSession = Session.openActiveSessionWithAccessToken(context, accessToken, new StatusCallback() {

                @Override
                public void call(Session session, SessionState state, Exception exception) {

                }
            });
        }
    }

    /**
     * Connects to the Sync test server, authenticates the provided
     * username and password.
     * 
     * @param username
     *            The server account username
     * @param password
     *            The server account password
     * @return String The authentication token returned by the server (or null)
     * @throws NetworkErrorException 
     */
    public boolean checkAccessToken() throws NetworkErrorException {
        //TODO: try to re-use timeout values (or remove preferences options
        //   params.putInt("timeout", ContactsSync.getInstance().getConnectionTimeout() * 1000);

        if (!mSession.isOpened()) {
            return false;
        }

        try {
            Request request = new Request(mSession, "me/permissions");
            Response response = request.executeAndWait();

            if (response.getError() != null) {
                if (response.getError().getErrorCode() == 190) {
                    return false;
                } else {
                    throw new NetworkErrorException(response.getError().getErrorMessage());
                }
            }

            JSONObject json = response.getGraphObject().getInnerJSONObject();
            JSONObject permissions = json.getJSONArray("data").getJSONObject(0);

            for (int i = 0; i < Authenticator.REQUIRED_PERMISSIONS.length; i++) {
                if (permissions.isNull(Authenticator.REQUIRED_PERMISSIONS[i])
                        || permissions.getInt(Authenticator.REQUIRED_PERMISSIONS[i]) == 0) {
                    return false;
                }
            }
        } catch (FacebookException e) {
            throw new NetworkErrorException(e.getMessage());
        } catch (JSONException e) {
            throw new NetworkErrorException(e.getMessage());
        }

        return true;
    }

    @SuppressLint("SimpleDateFormat")
    public List<RawContact> getContacts(Account account)
            throws JSONException, ParseException, IOException, AuthenticationException {

        final ArrayList<RawContact> serverList = new ArrayList<RawContact>();
        ContactsSync app = ContactsSync.getInstance();
        int pictureSize = app.getPictureSize();
        String pic_size = null;
        boolean album_picture = false;

        if (app.getSyncType() == ContactsSync.SyncType.LEGACY) {
            switch (pictureSize) {
            case RawContact.IMAGE_SIZES.SMALL_SQUARE:
                pic_size = "pic_square";
                break;
            case RawContact.IMAGE_SIZES.SMALL:
                pic_size = "pic_small";
                break;
            case RawContact.IMAGE_SIZES.NORMAL:
                pic_size = "pic";
                break;
            case RawContact.IMAGE_SIZES.SQUARE:
            case RawContact.IMAGE_SIZES.BIG_SQUARE:
            case RawContact.IMAGE_SIZES.HUGE_SQUARE:
            case RawContact.IMAGE_SIZES.MAX:
            case RawContact.IMAGE_SIZES.MAX_SQUARE:
                album_picture = true;
            case RawContact.IMAGE_SIZES.BIG:
                pic_size = "pic_big";
                break;
            }
        } else {
            pic_size = "pic";
            album_picture = false;
        }

        String fields = "uid, first_name, last_name, " + pic_size;

        boolean more = true;
        int limit;
        int offset = 0;
        while (more) {
            more = false;
            Bundle params = new Bundle();

            if (album_picture) {
                limit = 20;
                String query1 = "SELECT " + fields
                        + " FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = me()) LIMIT " + limit
                        + " OFFSET " + offset;
                String query2 = "SELECT owner, src_big, modified FROM photo WHERE pid IN (SELECT cover_pid FROM album WHERE owner IN (SELECT uid FROM #query1) AND type = 'profile')";
                params.putString("method", "fql.multiquery");
                params.putString("queries", "{\"query1\":\"" + query1 + "\", \"query2\":\"" + query2 + "\"}");
            } else {
                limit = 1000;
                String query = "SELECT " + fields
                        + " FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = me()) LIMIT " + limit
                        + " OFFSET " + offset;
                params.putString("method", "fql.query");
                params.putString("query", query);
            }

            params.putInt("timeout", app.getConnectionTimeout() * 1000);
            Request request = Request.newRestRequest(mSession, "fql.query", params, HttpMethod.GET);
            Response response = request.executeAndWait();

            if (response == null) {
                throw new IOException();
            }
            if (response.getGraphObjectList() == null) {
                if (response.getError() != null) {
                    if (response.getError().getErrorCode() == 190) {
                        throw new AuthenticationException();
                    } else {
                        throw new ParseException(response.getError().getErrorMessage());
                    }
                } else {
                    throw new ParseException();
                }
            }

            try {
                JSONArray serverContacts;
                HashMap<String, JSONObject> serverImages = new HashMap<String, JSONObject>();
                if (album_picture) {
                    JSONArray result = response.getGraphObjectList().getInnerJSONArray();
                    serverContacts = result.getJSONObject(0).getJSONArray("fql_result_set");
                    JSONArray images = result.getJSONObject(1).getJSONArray("fql_result_set");
                    JSONObject image;
                    for (int j = 0; j < images.length(); j++) {
                        image = images.getJSONObject(j);
                        serverImages.put(image.getString("owner"), image);
                    }
                } else {
                    serverContacts = response.getGraphObjectList().getInnerJSONArray();
                }

                JSONObject contact;
                for (int i = 0; i < serverContacts.length(); i++) {
                    contact = serverContacts.getJSONObject(i);
                    contact.put("picture", !contact.isNull(pic_size) ? contact.getString(pic_size) : null);
                    if (album_picture && serverImages.containsKey(contact.getString("uid"))) {
                        contact.put("picture", serverImages.get(contact.getString("uid")).getString("src_big"));
                    }
                    RawContact rawContact = RawContact.valueOf(contact);
                    if (rawContact != null) {
                        serverList.add(rawContact);
                    }
                }

                if (serverContacts.length() > limit / 2) {
                    offset += limit;
                    more = true;
                }
            } catch (FacebookException e) {
                throw new ParseException(e.getMessage());
            } catch (JSONException e) {
                throw new ParseException(e.getMessage());
            }
        }

        return serverList;
    }

    public ContactPhoto getContactPhotoHD(RawContact contact, int width, int height)
            throws IOException, AuthenticationException, JSONException {

        Bundle params = new Bundle();
        ContactsSync app = ContactsSync.getInstance();
        params.putInt("width", width);
        params.putInt("height", height);
        params.putBoolean("redirect", false);
        params.putInt("timeout", app.getConnectionTimeout() * 1000);
        Request request = new Request(mSession, contact.getUid() + "/picture", params, HttpMethod.GET);
        Response response = request.executeAndWait();

        if (response == null) {
            throw new IOException();
        }
        if (response.getGraphObject() == null) {
            if (response.getError() != null) {
                if (response.getError().getErrorCode() == 190) {
                    throw new AuthenticationException();
                } else {
                    throw new ParseException(response.getError().getErrorMessage());
                }
            } else {
                throw new ParseException();
            }
        }

        Log.d("FacebookGetPhoto", "response: " + response.getGraphObject().getInnerJSONObject().toString());
        String image = response.getGraphObject().getInnerJSONObject().getJSONObject("data").getString("url");

        return new ContactPhoto(contact, image, 0);
    }

    /**
     * Download the avatar image from the server.
     * 
     * @param avatarUrl
     *            the URL pointing to the avatar image
     * @return a byte array with the raw JPEG avatar image
     */
    public static byte[] downloadAvatar(final String avatarUrl) {
        // If there is no avatar, we're done
        if (TextUtils.isEmpty(avatarUrl)) {
            return null;
        }

        try {
            ContactsSync app = ContactsSync.getInstance();
            URL url = new URL(avatarUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            try {
                BitmapFactory.Options options = new BitmapFactory.Options();
                Bitmap originalImage = BitmapFactory.decodeStream(connection.getInputStream(), null, options);
                ByteArrayOutputStream convertStream;

                if (app.getPictureSize() == RawContact.IMAGE_SIZES.SQUARE
                        || app.getPictureSize() == RawContact.IMAGE_SIZES.BIG_SQUARE
                        || app.getPictureSize() == RawContact.IMAGE_SIZES.HUGE_SQUARE
                        || app.getPictureSize() == RawContact.IMAGE_SIZES.MAX_SQUARE) {
                    int targetWidth, targetHeight;
                    switch (app.getPictureSize()) {
                    case RawContact.IMAGE_SIZES.MAX_SQUARE:
                        targetWidth = app.getMaxPhotoSize();
                        targetHeight = app.getMaxPhotoSize();
                        break;
                    case RawContact.IMAGE_SIZES.HUGE_SQUARE:
                        targetWidth = Math.min(720, app.getMaxPhotoSize());
                        targetHeight = Math.min(720, app.getMaxPhotoSize());
                        break;
                    case RawContact.IMAGE_SIZES.BIG_SQUARE:
                        targetWidth = Math.min(512, app.getMaxPhotoSize());
                        targetHeight = Math.min(512, app.getMaxPhotoSize());
                        break;
                    case RawContact.IMAGE_SIZES.SQUARE:
                    default:
                        targetWidth = Math.min(256, app.getMaxPhotoSize());
                        targetHeight = Math.min(256, app.getMaxPhotoSize());
                    }

                    int cropWidth = Math.min(originalImage.getWidth(), originalImage.getHeight());
                    int cropHeight = cropWidth;
                    int offsetX = Math.round((originalImage.getWidth() - cropWidth) / 2);
                    int offsetY = Math.round((originalImage.getHeight() - cropHeight) / 2);

                    Log.v("pic_size", "w:" + cropWidth + ", h:" + cropHeight);

                    Bitmap croppedImage = Bitmap.createBitmap(originalImage, offsetX, offsetY, cropWidth,
                            cropHeight);
                    Bitmap resizedBitmap = Bitmap.createScaledBitmap(croppedImage, targetWidth, targetHeight, true);

                    convertStream = new ByteArrayOutputStream(targetWidth * targetHeight * 4);
                    resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 95, convertStream);

                    croppedImage.recycle();
                    resizedBitmap.recycle();
                } else {
                    Log.v("pic_size",
                            "original: w:" + originalImage.getWidth() + ", h:" + originalImage.getHeight());
                    convertStream = new ByteArrayOutputStream(
                            originalImage.getWidth() * originalImage.getHeight() * 4);
                    originalImage.compress(Bitmap.CompressFormat.JPEG, 95, convertStream);
                }

                convertStream.flush();
                convertStream.close();
                originalImage.recycle();
                return convertStream.toByteArray();
            } finally {
                connection.disconnect();
            }
        } catch (MalformedURLException muex) {
            // A bad URL - nothing we can really do about it here...
            Log.e("network_utils", "Malformed avatar URL: " + avatarUrl);
        } catch (IOException ioex) {
            // If we're unable to download the avatar, it's a bummer but not the
            // end of the world. We'll try to get it next time we sync.
            Log.e("network_utils", "Failed to download user avatar: " + avatarUrl);
        } catch (NullPointerException npe) {
            // probably `avatar` is null
            Log.e("network_utils", "Failed to download user avatar: " + avatarUrl);
        }
        return null;
    }
}