Java tutorial
/* * Copyright 2012 I.ndigo * * 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 br.com.indigo.android.facebook; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.TimeZone; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.util.Log; import br.com.indigo.android.facebook.models.FbComment; import br.com.indigo.android.facebook.models.FbEvent; import br.com.indigo.android.facebook.models.FbSimpleApplication; import br.com.indigo.android.facebook.models.FbSimplePost; import br.com.indigo.android.facebook.models.FbSimpleUser; import br.com.indigo.android.facebook.models.FbSimpleUser.RSVP_STATUS; import com.facebook.android.AsyncFacebookRunner; import com.facebook.android.AsyncFacebookRunner.RequestListener; import com.facebook.android.DialogError; import com.facebook.android.Facebook; import com.facebook.android.Facebook.DialogListener; import com.facebook.android.FacebookError; import com.facebook.android.R; import com.facebook.android.Util; public class SocialFacebook { private static final String TAG = SocialFacebook.class.getSimpleName(); private static final String PREFERENCES = "br.com.indigo.android.facebook"; private static final String TOKEN = "access_token"; private static final String EXPIRES = "expires_in"; private Context mAppContext; private Facebook mFacebook; private AsyncFacebookRunner mAsync; private String[] mPermissions; private FbSimpleApplication mApp; private String mAppSecret; private String mAppAccessToken; private SimpleDateFormat mDateFormat; private TimeZone mFacebookTimeZone; /** Singleton Instance **/ private static SocialFacebook mInstance; public static SocialFacebook getInstance() { if (mInstance == null) { throw new RuntimeException( "There is no singleton instance. You must invoke getInstance(Context, String, String, String[]) first."); } return mInstance; } public static SocialFacebook getInstance(Context context, String appId, String appSecret, String[] permissions) { synchronized (SocialFacebook.class) { if (mInstance == null) { mInstance = new SocialFacebook(context, appId, appSecret, permissions); } } return mInstance; } private SocialFacebook(Context context, String appId, String appSecret, String[] permissions) { if (appId == null) { new AlertDialog.Builder(context).setTitle("Facebook Setup Error") .setMessage("Missing app ID. You cannot run the app until you provide this in the code.") .setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton("OK", new OnClickListener() { public void onClick(DialogInterface dialog, int which) { // Quit the app System.exit(1); } }).create().show(); } else { // Everything is OK mFacebook = new Facebook(appId); mAsync = new AsyncFacebookRunner(mFacebook); mAppContext = context.getApplicationContext(); mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); mFacebookTimeZone = TimeZone.getTimeZone("PST8PDT"); mPermissions = permissions; // restore session if one exists loadLoginInfo(); mApp = new FbSimpleApplication(); mApp.setId(appId); mAppSecret = appSecret; } } /** * IMPORTANT: This method must be invoked at the top of the calling * activity's onActivityResult() function or Facebook authentication will * not function properly! * * If your calling activity does not currently implement onActivityResult(), * you must implement it and include a call to this method if you intend to * use the authorize() method in this SDK. * * For more information, see * http://developer.android.com/reference/android/app/ * Activity.html#onActivityResult(int, int, android.content.Intent) */ public void authorizeCallback(int requestCode, int resultCode, Intent data) { mFacebook.authorizeCallback(requestCode, resultCode, data); } public boolean isSessionValid() { return mFacebook.isSessionValid(); } public void getAppAccessToken(final AppTokenRequestListener listener) { new Thread() { @Override public void run() { try { Bundle params = new Bundle(); params.putString("client_id", mApp.getId()); params.putString("client_secret", mAppSecret); params.putString("grant_type", "client_credentials"); String response = Util.openUrl("https://graph.facebook.com/oauth/access_token", "GET", params); String[] components = response.split("="); if (components.length == 2) { // Success mAppAccessToken = components[1]; listener.onComplete(mAppAccessToken); } else { // Error Log.d(TAG, "Could not parse App Login Acess Token"); listener.onFail(new Exception("Could not parse App Login Acess Token")); } } catch (MalformedURLException e) { Log.d(TAG, "Error retrieving App Acess Token", e); listener.onFail(e); } catch (IOException e) { Log.d(TAG, "Error retrieving App Acess Token", e); listener.onFail(e); } } }.start(); } public void login(Activity activity, final SimpleRequestListener listener) { mFacebook.authorize(activity, mPermissions, new DialogAdapter() { public void onComplete(Bundle values) { Log.d(TAG, "User logged in"); saveLoginInfo(); listener.onComplete(); } public void onCancel() { Log.d(TAG, "User cancelled login"); listener.onCancel(); } public void onFail(Throwable thr) { Log.d(TAG, "Did not login"); listener.onFail(thr); } }); } public void logout(Context context, final SimpleRequestListener listener) { mAsync.logout(context, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { Log.d(TAG, "Logout"); clearLoginInfo(); listener.onComplete(); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void uninstallApp(final SimpleRequestListener listener) { if (mFacebook.isSessionValid()) { // Passing empty (no) parameters unauthorizes the entire app. To revoke individual permissions // add a permission parameter with the name of the permission to revoke. Bundle params = new Bundle(); facebookRequest(null, "me/permissions", params, "DELETE", true, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { // [self logoutWithSuccess:nil]; listener.onComplete(); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } else { // Failure listener.onFail(new RuntimeException("User is not logged in")); } } public void getAppInfo(final AppInfoListener listener) { if (mApp.getName() != null) { listener.onComplete(mApp); } else { Bundle params = new Bundle(); params.putString("fields", "name,icon_url"); facebookRequest(null, mApp.getId(), params, false, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { try { mApp.setName(jsonResponse.getString("name")); mApp.setIconUrl(jsonResponse.getString("icon_url")); listener.onComplete(mApp); } catch (JSONException e) { Log.d(TAG, "Could not parse Json response", e); listener.onFail(new RuntimeException("Could not parse Json response", e)); } } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } } public void getProfileFeed(Activity activity, String profileId, int pageSize, boolean needsLogin, final FeedListener listener) { Bundle params = new Bundle(); params.putString("date_format", "U"); params.putString("limit", String.valueOf(pageSize)); params.putString("fields", "id,from,message,picture,link,name,caption,description,source,type,created_time,updated_time,comments,likes"); facebookRequest(activity, profileId + "/feed", params, needsLogin, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleFeedResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getProfileFeedNextPage(final String nextPageUrl, final FeedListener listener) { new Thread() { @Override public void run() { try { String response = Util.openUrl(nextPageUrl, "GET", null); JSONObject jsonResponse = Util.parseJson(response); handleFeedResponse(jsonResponse, listener); } catch (FileNotFoundException e) { listener.onFail(e); } catch (MalformedURLException e) { listener.onFail(e); } catch (IOException e) { listener.onFail(e); } catch (FacebookError e) { listener.onFail(e); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } }.start(); } public void publish(final Activity activity, final FbSimplePost post, final NewObjectListener listener) { if (!mFacebook.isSessionValid()) { login(activity, new SimpleRequestListener() { public void onComplete() { publish(activity, post, listener); } public void onFail(Throwable thr) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } else { mFacebook.dialog(activity, "feed", paramsForPost(post), new DialogAdapter() { public void onComplete(Bundle values) { String postId = values.getString("post_id"); // Successful posts return a post_id if (postId != null) { Log.d(TAG, "Feed post ID: " + postId); listener.onComplete(postId); } } public void onCancel() { listener.onCancel(); } public void onFail(Throwable thr) { listener.onFail(thr); } }); } } public void publishWithoutDialog(Activity activity, FbSimplePost post, final NewObjectListener listener) { facebookRequest(activity, "me/feed", paramsForPost(post), "POST", true, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { listener.onComplete(jsonResponse.optString("id")); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getFriends(Activity activity, int pageSize, final UsersListener listener) { Bundle params = new Bundle(1); params.putString("limit", String.valueOf(pageSize)); facebookRequest(activity, "me/friends", params, true, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleUsersResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getFriendsNextPage(final String nextPageUrl, final UsersListener listener) { new Thread() { @Override public void run() { try { String response = Util.openUrl(nextPageUrl, "GET", null); JSONObject jsonResponse = Util.parseJson(response); handleUsersResponse(jsonResponse, listener); } catch (FileNotFoundException e) { listener.onFail(e); } catch (MalformedURLException e) { listener.onFail(e); } catch (IOException e) { listener.onFail(e); } catch (FacebookError e) { listener.onFail(e); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } }.start(); } public void getEvent(Activity activity, String eventId, boolean needsLogin, final EventListener listener) { Bundle params = new Bundle(); params.putString("date_format", "U"); facebookRequest(activity, eventId, params, needsLogin, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { try { listener.onComplete(parseEvent(jsonResponse)); } catch (JSONException e) { Log.d(TAG, "Could not parse Json response", e); listener.onFail(new RuntimeException("Could not parse Json response", e)); } } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getEvents(Activity activity, int pageSize, final EventsListener listener) { Bundle params = new Bundle(3); params.putString("limit", String.valueOf(pageSize)); params.putString("fields", "id,name,start_time,end_time,location"); params.putString("date_format", "U"); facebookRequest(activity, "me/events", params, true, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleEventsResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getEventsNextPage(final String nextPageUrl, final EventsListener listener) { new Thread() { @Override public void run() { try { String response = Util.openUrl(nextPageUrl, "GET", null); JSONObject jsonResponse = Util.parseJson(response); handleEventsResponse(jsonResponse, listener); } catch (FileNotFoundException e) { listener.onFail(e); } catch (MalformedURLException e) { listener.onFail(e); } catch (IOException e) { listener.onFail(e); } catch (FacebookError e) { listener.onFail(e); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } }.start(); } public void createEvent(Activity activity, FbEvent event, final NewObjectListener listener) { facebookRequest(activity, "me/events", paramsForEvent(event), "POST", true, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { listener.onComplete(jsonResponse.optString("id")); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void inviteUsers(Activity activity, String[] userIds, String eventId, final SimpleRequestListener listener) { StringBuilder users = new StringBuilder(); for (String userId : userIds) { users.append(userId); users.append(","); } if (users.length() > 0) { users.deleteCharAt(users.length() - 1); // Remove last colon } Bundle params = new Bundle(); params.putString("users", users.toString()); facebookRequest(activity, eventId + "/invited", params, "POST", true, new RequestAdapter() { public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onComplete(JSONObject jsonResponse, Object state) { listener.onComplete(); } public void onCancel() { listener.onCancel(); } }); } public void getInvitedUsers(Activity activity, String eventId, int pageSize, UsersListener listener) { getInvitedUsers(activity, eventId, RSVP_STATUS.UNKNOWN, pageSize, listener); } public void getInvitedUsers(Activity activity, String eventId, RSVP_STATUS rsvpStatus, int pageSize, final UsersListener listener) { String inviteeType = null; switch (rsvpStatus) { case UNKNOWN: inviteeType = "invited"; break; case ATTENDING: inviteeType = "attending"; break; case MAYBE: inviteeType = "maybe"; break; case DECLINED: inviteeType = "declined"; break; case NOT_REPLIED: inviteeType = "noreply"; break; default: break; } Bundle params = new Bundle(); params.putString("limit", String.valueOf(pageSize)); facebookRequest(activity, String.format("%s/%s", eventId, inviteeType), params, true, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleUsersResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getInvitedUsersNextPage(final String nextPageUrl, final UsersListener listener) { new Thread() { @Override public void run() { try { String response = Util.openUrl(nextPageUrl, "GET", null); JSONObject jsonResponse = Util.parseJson(response); handleUsersResponse(jsonResponse, listener); } catch (FileNotFoundException e) { listener.onFail(e); } catch (MalformedURLException e) { listener.onFail(e); } catch (IOException e) { listener.onFail(e); } catch (FacebookError e) { listener.onFail(e); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } }.start(); } public void attendEvent(Activity activity, String eventId, final SimpleRequestListener listner) { facebookRequest(activity, eventId + "/attending", new Bundle(), "POST", true, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { listner.onComplete(); } public void onFail(Throwable thr, Object state) { listner.onFail(thr); } public void onCancel() { listner.onCancel(); } }); } public void getCommentsFromPost(Activity activity, String postId, int pageSize, boolean needsLogin, final CommentsListener listener) { Bundle params = new Bundle(); params.putString("date_format", "U"); params.putString("limit", String.valueOf(pageSize)); facebookRequest(activity, postId + "/comments", params, needsLogin, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleCommentsResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getCommentsFromPostNextPage(final String nextPageUrl, final CommentsListener listener) { facebookRequest(nextPageUrl, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleCommentsResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getUsersWhoLikedPost(Activity activity, String postId, int pageSize, boolean needsLogin, final UsersListener listener) { Bundle params = new Bundle(); params.putString("date_format", "U"); params.putString("limit", String.valueOf(pageSize)); facebookRequest(activity, postId + "/likes", params, needsLogin, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleUsersResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void getUsersWhoLikedPostNextPage(String nextPageUrl, final UsersListener listener) { facebookRequest(nextPageUrl, new RequestAdapter() { public void onComplete(JSONObject jsonResponse, Object state) { handleUsersResponse(jsonResponse, listener); } public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } public void commentPost(final Activity activity, final String postId, final NewObjectListener listener) { if (!mFacebook.isSessionValid()) { login(activity, new SimpleRequestListener() { public void onComplete() { commentPost(activity, postId, listener); } public void onFail(Throwable thr) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } }); } else { final FbTextDialog dialog = new FbTextDialog(activity); dialog.setDialogListener(new DialogListener() { public void onComplete(Bundle values) { final ProgressDialog spinner = new ProgressDialog(activity); spinner.setMessage(spinner.getContext().getString(R.string.loading)); spinner.setCancelable(false); spinner.show(); facebookRequest(activity, postId + "/comments", values, "POST", true, new RequestAdapter() { public void onFail(Throwable thr, Object state) { listener.onFail(thr); spinner.dismiss(); dialog.dismiss(); } public void onComplete(JSONObject jsonResponse, Object state) { listener.onComplete(jsonResponse.optString("id")); spinner.dismiss(); dialog.dismiss(); } public void onCancel() { listener.onCancel(); spinner.dismiss(); dialog.dismiss(); } }); } public void onFacebookError(FacebookError e) { listener.onFail(e); } public void onError(DialogError e) { listener.onFail(e); } public void onCancel() { listener.onCancel(); } }); dialog.show(); } } public void likeObject(Activity activity, String objectId, final SimpleRequestListener listener) { facebookRequest(activity, objectId + "/likes", new Bundle(), "POST", true, new RequestAdapter() { public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onComplete(JSONObject jsonResponse, Object state) { listener.onComplete(); } public void onCancel() { listener.onCancel(); } }); } public void publish(final Activity activity, final FbSimplePost post, final String pageId, final NewObjectListener listener) { if (!mFacebook.isSessionValid()) { login(activity, new SimpleRequestListener() { public void onFail(Throwable thr) { listener.onFail(thr); } public void onCancel() { listener.onCancel(); } public void onComplete() { publish(activity, post, pageId, listener); } }); } else { final FbTextDialog dialog = new FbTextDialog(activity); dialog.setTitle(R.string.dialog_post_to_wall_title); dialog.setPlaceHolder(R.string.dialog_post_to_wall_placeholder); dialog.setDialogListener(new DialogListener() { public void onComplete(Bundle values) { final ProgressDialog spinner = new ProgressDialog(activity); spinner.setMessage(spinner.getContext().getString(R.string.loading)); spinner.setCancelable(false); spinner.show(); Bundle params = paramsForPost(post); params.putAll(values); facebookRequest(activity, pageId + "/feed", params, "POST", true, new RequestAdapter() { public void onFail(Throwable thr, Object state) { listener.onFail(thr); spinner.dismiss(); dialog.dismiss(); } public void onComplete(JSONObject jsonResponse, Object state) { listener.onComplete(jsonResponse.optString("id")); spinner.dismiss(); dialog.dismiss(); } public void onCancel() { listener.onCancel(); spinner.dismiss(); dialog.dismiss(); } }); } public void onFacebookError(FacebookError e) { listener.onFail(e); } public void onError(DialogError e) { listener.onFail(e); } public void onCancel() { listener.onCancel(); } }); dialog.show(); } } public void publishWithoutDialog(Activity activity, FbSimplePost post, String pageId, final NewObjectListener listener) { facebookRequest(activity, pageId + "/feed", paramsForPost(post), "POST", true, new RequestAdapter() { public void onFail(Throwable thr, Object state) { listener.onFail(thr); } public void onComplete(JSONObject jsonResponse, Object state) { listener.onComplete(jsonResponse.optString("id")); } public void onCancel() { listener.onCancel(); } }); } /** Private Methods **/ private void facebookRequest(Activity activity, String graphPath, boolean needsLogin, RequestAdapter adapter) { facebookRequest(activity, graphPath, new Bundle(), "GET", needsLogin, adapter); } private void facebookRequest(Activity activity, String graphPath, Bundle params, boolean needsLogin, RequestAdapter adapter) { facebookRequest(activity, graphPath, params, "GET", needsLogin, adapter); } private void facebookRequest(Activity activity, final String graphPath, final Bundle params, final String httpMethod, boolean needsLogin, final RequestAdapter adapter) { if (needsLogin && !mFacebook.isSessionValid()) { login(activity, new SimpleRequestListener() { public void onComplete() { mAsync.request(graphPath, params, httpMethod, adapter, null); } public void onFail(Throwable thr) { adapter.onFail(thr, null); } public void onCancel() { adapter.onCancel(); } }); } else if (!needsLogin && mAppAccessToken == null && !mFacebook.isSessionValid()) { getAppAccessToken(new AppTokenRequestListener() { public void onFail(Throwable thr) { adapter.onFail(thr, null); } public void onComplete(String accessToken) { params.putString("access_token", accessToken); mAsync.request(graphPath, params, httpMethod, adapter, null); } }); } else { if (mAppAccessToken != null) { params.putString("access_token", mAppAccessToken); } mAsync.request(graphPath, params, httpMethod, adapter, null); } } private void facebookRequest(final String url, final RequestAdapter adapter) { new Thread() { @Override public void run() { try { String response = Util.openUrl(url, "GET", null); JSONObject jsonResponse = Util.parseJson(response); adapter.onComplete(jsonResponse, null); } catch (FileNotFoundException e) { adapter.onFail(e, null); } catch (MalformedURLException e) { adapter.onFail(e, null); } catch (IOException e) { adapter.onFail(e, null); } catch (FacebookError e) { adapter.onFail(e, null); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); adapter.onFail(e, null); } } }.start(); } private void saveLoginInfo() { Editor editor = mAppContext.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE).edit(); editor.putString(TOKEN, mFacebook.getAccessToken()); editor.putLong(EXPIRES, mFacebook.getAccessExpires()); editor.commit(); Log.d(TAG, "Access token info saved"); } private void loadLoginInfo() { // Retrieve authorization information SharedPreferences prefs = mAppContext.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE); mFacebook.setAccessToken(prefs.getString(TOKEN, null)); mFacebook.setAccessExpires(prefs.getLong(EXPIRES, 0)); } private void clearLoginInfo() { // Remove saved authorization information if it exists Editor editor = mAppContext.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE).edit(); editor.remove(TOKEN); editor.remove(EXPIRES); editor.commit(); } private Bundle paramsForPost(FbSimplePost post) { Bundle params = new Bundle(); if (post != null) { // The action links to be shown with the post in the feed String actionName = post.getActionName(); String actionLink = post.getActionLink(); if (actionName != null && actionLink != null) { params.putString("actions", String.format("[{name:\"%s\",link:\"%s\"}]", actionName, actionLink)); } // Dialog parameters String value = null; List<FbSimpleUser> to = post.getTo(); if (to != null && to.size() > 0) { value = to.get(0).getId(); if (value != null) { params.putString("to", value); } } value = post.getName(); if (value != null) { params.putString("name", value); } value = post.getCaption(); if (value != null) { params.putString("caption", value); } value = post.getDescription(); if (value != null) { params.putString("description", value); } value = post.getLink(); if (value != null) { params.putString("link", value); } value = post.getPicture(); if (value != null) { params.putString("picture", value); } value = post.getSource(); if (value != null) { params.putString("source", value); } value = post.getMessage(); if (value != null) { params.putString("message", value); } } return params; } private Bundle paramsForEvent(FbEvent event) { Bundle params = new Bundle(); if (event != null) { String value = event.getName(); if (value != null) { params.putString("name", value); } Date date = event.getStartTime(); if (date != null) { params.putString("start_time", String.valueOf(facebookUnixTimestampFromDate(date) / 1000)); date = event.getEndTime(); if (date != null) { params.putString("end_time", String.valueOf(facebookUnixTimestampFromDate(date) / 1000)); } } value = event.getDescription(); if (value != null) { params.putString("description", value); } value = event.getLocation(); if (value != null) { params.putString("location", value); } value = event.getPrivacy(); if (value != null) { params.putString("privacy_type", value); } else { params.putString("privacy_type", FbEvent.PRIVACY_SECRET); } } return params; } private Date dateWithFacebookUnixTimestamp(long unixTimestamp) { mDateFormat.setTimeZone(mFacebookTimeZone); Date sourceDate = new Date(unixTimestamp * 1000); String dateString = mDateFormat.format(sourceDate); mDateFormat.setTimeZone(TimeZone.getDefault()); Date resultDate = null; try { resultDate = mDateFormat.parse(dateString); } catch (ParseException e) { // Should never enter here Log.d(TAG, "Could not convert Unix timestamp to date", e); } return resultDate; } private long facebookUnixTimestampFromDate(Date date) { mDateFormat.setTimeZone(TimeZone.getDefault()); String dateString = mDateFormat.format(date); mDateFormat.setTimeZone(mFacebookTimeZone); long resultTime = 0; try { resultTime = mDateFormat.parse(dateString).getTime(); } catch (ParseException e) { // Should never enter here Util.logd(TAG, "Could not convert date to Facebook Unix timestamp", e); } return resultTime; } private void handleFeedResponse(JSONObject jsonResponse, FeedListener listener) { FbSimplePost post; ArrayList<FbSimplePost> posts = new ArrayList<FbSimplePost>(); try { JSONArray objs = jsonResponse.getJSONArray("data"); for (int i = 0; i < objs.length(); i++) { JSONObject obj = objs.getJSONObject(i); post = new FbSimplePost(); post.setId(obj.getString("id")); JSONObject fromJson = obj.optJSONObject("from"); if (fromJson != null) { FbSimpleUser from = new FbSimpleUser(); from.setId(fromJson.getString("id")); from.setName(fromJson.getString("name")); post.setFrom(from); } post.setMessage(obj.optString("message")); post.setPicture(obj.optString("picture")); post.setLink(obj.optString("link")); post.setName(obj.optString("name")); post.setCaption(obj.optString("caption")); post.setDescription(obj.optString("description")); post.setSource(obj.optString("source")); post.setType(obj.optString("type")); post.setCreatedTime(new Date(obj.getLong("created_time"))); post.setUpdatedTime(new Date(obj.getLong("updated_time"))); JSONObject comments = obj.optJSONObject("comments"); if (comments != null) { post.setNumberOfComments(comments.getInt("count")); } JSONObject likes = obj.optJSONObject("likes"); if (likes != null) { post.setNumberOfLikes(likes.getInt("count")); } posts.add(post); } String nextPage = null; JSONObject paging = jsonResponse.optJSONObject("paging"); if (paging != null) { nextPage = paging.optString("next"); } listener.onComplete(posts, nextPage); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } private void handleUsersResponse(JSONObject jsonResponse, UsersListener listener) { FbSimpleUser user = null; ArrayList<FbSimpleUser> friends = new ArrayList<FbSimpleUser>(); try { JSONArray objs = jsonResponse.getJSONArray("data"); for (int i = 0; i < objs.length(); i++) { JSONObject obj = objs.getJSONObject(i); user = new FbSimpleUser(); user.setId(obj.getString("id")); user.setName(obj.getString("name")); String rsvpStatus = obj.optString("rsvp_status"); if (rsvpStatus != null) { if (rsvpStatus.equals("not_replied")) { user.setRSVPStatus(RSVP_STATUS.NOT_REPLIED); } else if (rsvpStatus.equals("attending")) { user.setRSVPStatus(RSVP_STATUS.ATTENDING); } else if (rsvpStatus.equals("declined")) { user.setRSVPStatus(RSVP_STATUS.DECLINED); } else if (rsvpStatus.equals("unsure")) { user.setRSVPStatus(RSVP_STATUS.MAYBE); } } friends.add(user); } String nextPage = null; JSONObject paging = jsonResponse.optJSONObject("paging"); if (paging != null) { nextPage = paging.optString("next"); } listener.onComplete(friends, nextPage); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } private void handleEventsResponse(JSONObject jsonResponse, EventsListener listener) { ArrayList<FbEvent> events = new ArrayList<FbEvent>(); try { JSONArray objs = jsonResponse.getJSONArray("data"); for (int i = 0; i < objs.length(); i++) { JSONObject obj = objs.getJSONObject(i); events.add(parseEvent(obj)); } String nextPage = null; JSONObject paging = jsonResponse.optJSONObject("paging"); if (paging != null) { nextPage = paging.optString("next"); } listener.onComplete(events, nextPage); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } private FbEvent parseEvent(JSONObject eventJson) throws JSONException { FbEvent event = new FbEvent(); event.setId(eventJson.getString("id")); event.setName(eventJson.getString("name")); event.setDescription(eventJson.optString("description")); event.setStartTime(dateWithFacebookUnixTimestamp(eventJson.getLong("start_time"))); event.setEndTime(dateWithFacebookUnixTimestamp(eventJson.optLong("end_time"))); event.setLocation(eventJson.optString("location")); event.setPrivacy(eventJson.optString("privacy")); JSONObject ownerJson = eventJson.optJSONObject("owner"); if (ownerJson != null) { FbSimpleUser owner = new FbSimpleUser(); owner.setId(ownerJson.getString("id")); owner.setName(ownerJson.optString("name")); event.setOwner(owner); } return event; } private void handleCommentsResponse(JSONObject jsonResponse, CommentsListener listener) { FbComment comment = null; ArrayList<FbComment> comments = new ArrayList<FbComment>(); try { JSONArray objs = jsonResponse.getJSONArray("data"); for (int i = 0; i < objs.length(); i++) { JSONObject obj = objs.getJSONObject(i); comment = new FbComment(); comment.setId(obj.getString("id")); comment.setMessage(obj.optString("message")); comment.setCreatedTime(new Date(obj.optLong("created_time") * 1000)); comment.setNumberOfLikes(obj.optInt("likes")); JSONObject fromJson = obj.optJSONObject("from"); if (fromJson != null) { FbSimpleUser fromUser = new FbSimpleUser(); fromUser.setId(fromJson.getString("id")); fromUser.setName(fromJson.optString("name")); comment.setFrom(fromUser); } comments.add(comment); } String nextPage = null; JSONObject paging = jsonResponse.optJSONObject("paging"); if (paging != null) { nextPage = paging.optString("next"); } listener.onComplete(comments, nextPage); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); listener.onFail(e); } } /** Shingle **/ public void shingleConfiguration(final String url, final int area, final ShingleListener listener) { new Thread() { @Override public void run() { try { Bundle params = new Bundle(); params.putString("area_id", String.valueOf(area)); String response = Util.openUrl(url + "facebook/getFacebook", "GET", params); try { JSONArray result = new JSONArray(response); String profileId = result.getJSONObject(0).getString("account_number"); Log.d(TAG, "Shingle profileId = " + profileId); listener.onComplete(profileId, false); } catch (JSONException e) { Log.d(TAG, "Could not parse server response", e); listener.onFail(new RuntimeException("Could not parse server response", e)); } } catch (MalformedURLException e) { Log.d(TAG, "Error retrieving App Acess Token", e); listener.onFail(e); } catch (IOException e) { Log.d(TAG, "Error retrieving App Acess Token", e); listener.onFail(e); } } }.start(); } /** Listeners **/ public interface AppTokenRequestListener { public void onComplete(String accessToken); public void onFail(Throwable thr); } public static interface ShingleListener { public void onComplete(String profile, boolean needsLogin); public void onFail(Throwable thr); } private static interface FacebookListener { public void onFail(Throwable thr); public void onCancel(); } public static interface SimpleRequestListener extends FacebookListener { public void onComplete(); } public static interface AppInfoListener extends FacebookListener { public void onComplete(FbSimpleApplication app); } public static interface EventListener extends FacebookListener { public void onComplete(FbEvent event); } public static interface NewObjectListener extends FacebookListener { public void onComplete(String id); } public static interface FeedListener extends FacebookListener { public void onComplete(List<FbSimplePost> posts, String nextPage); } public static interface UsersListener extends FacebookListener { public void onComplete(List<FbSimpleUser> users, String nextPage); } public static interface EventsListener extends FacebookListener { public void onComplete(List<FbEvent> events, String nextPage); } public static interface CommentsListener extends FacebookListener { public void onComplete(List<FbComment> comments, String nextPage); } private abstract class RequestAdapter implements RequestListener { public abstract void onFail(Throwable thr, Object state); public abstract void onCancel(); public abstract void onComplete(JSONObject jsonResponse, Object state); @Override public void onComplete(String response, Object state) { try { JSONObject jsonResponse = Util.parseJson(response); onComplete(jsonResponse, state); } catch (FacebookError e) { if (e.getErrorCode() == 190) { // RESTAPIAccessTokenErrorCode mFacebook.setAccessToken(null); mFacebook.setAccessExpires(0); clearLoginInfo(); } onFail(e, state); } catch (JSONException e) { Util.logd(TAG, "Could not parse Json response", e); onFail(e, state); } } @Override public void onIOException(IOException e, Object state) { onFail(e, state); } @Override public void onFileNotFoundException(FileNotFoundException e, Object state) { onFail(e, state); } @Override public void onMalformedURLException(MalformedURLException e, Object state) { onFail(e, state); } @Override public void onFacebookError(FacebookError e, Object state) { onFail(e, state); } } private abstract class DialogAdapter implements DialogListener { public abstract void onFail(Throwable thr); public void onFacebookError(FacebookError e) { onFail(e); } public void onError(DialogError e) { onFail(e); } } }