package com.androidsocialnetworks.lib.impl; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import com.androidsocialnetworks.lib.AccessToken; import com.androidsocialnetworks.lib.SocialNetwork; import com.androidsocialnetworks.lib.SocialNetworkException; import com.androidsocialnetworks.lib.SocialPerson; import com.androidsocialnetworks.lib.listener.OnCheckIsFriendCompleteListener; import com.androidsocialnetworks.lib.listener.OnLoginCompleteListener; import com.androidsocialnetworks.lib.listener.OnPostingCompleteListener; import com.androidsocialnetworks.lib.listener.OnRequestAddFriendCompleteListener; import com.androidsocialnetworks.lib.listener.OnRequestRemoveFriendCompleteListener; import com.androidsocialnetworks.lib.listener.OnRequestSocialPersonCompleteListener; import com.facebook.FacebookAuthorizationException; import com.facebook.FacebookOperationCanceledException; import com.facebook.Request; import com.facebook.Response; import com.facebook.Session; import com.facebook.SessionDefaultAudience; import com.facebook.SessionLoginBehavior; import com.facebook.SessionState; import com.facebook.UiLifecycleHelper; import com.facebook.internal.SessionTracker; import com.facebook.internal.Utility; import com.facebook.model.GraphUser; import java.io.File; import java.util.Collections; /** * TODO: think about canceling requests */ public class FacebookSocialNetwork extends SocialNetwork { public static final int ID = 4; private static final String TAG = FacebookSocialNetwork.class.getSimpleName(); private static final String PERMISSION = "publish_actions"; private SessionTracker mSessionTracker; private UiLifecycleHelper mUILifecycleHelper; private String mApplicationId; private SessionState mSessionState; private String mPhotoPath; private String mStatus; private PendingAction mPendingAction = PendingAction.NONE; private Session.StatusCallback mSessionStatusCallback = new Session.StatusCallback() { @Override public void call(Session session, SessionState state, Exception exception) { onSessionStateChange(session, state, exception); } }; public FacebookSocialNetwork(Fragment fragment) { super(fragment); } @Override public boolean isConnected() { Session session = Session.getActiveSession(); return (session != null && session.isOpened()); } @Override public AccessToken getAccessToken() { return new AccessToken(Session.getActiveSession().getAccessToken(), null); } @Override public void requestLogin(OnLoginCompleteListener onLoginCompleteListener) { super.requestLogin(onLoginCompleteListener); final Session openSession = mSessionTracker.getOpenSession(); if (openSession != null) { if (mLocalListeners.get(REQUEST_LOGIN) != null) { mLocalListeners.get(REQUEST_LOGIN).onError(getID(), REQUEST_LOGIN, "already loginned", null); } } Session currentSession = mSessionTracker.getSession(); if (currentSession == null || currentSession.getState().isClosed()) { mSessionTracker.setSession(null); Session session = new Session.Builder(mSocialNetworkManager.getActivity()) .setApplicationId(mApplicationId).build(); Session.setActiveSession(session); currentSession = session; } if (!currentSession.isOpened()) { Session.OpenRequest openRequest = null; openRequest = new Session.OpenRequest(mSocialNetworkManager); openRequest.setDefaultAudience(SessionDefaultAudience.EVERYONE); openRequest.setPermissions(Collections.<String>emptyList()); openRequest.setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK); currentSession.openForRead(openRequest); } } @Override public void logout() { if (mSessionTracker == null) return; final Session openSession = mSessionTracker.getOpenSession(); if (openSession != null) { openSession.closeAndClearTokenInformation(); } } @Override public int getID() { return ID; } @Override public void requestCurrentPerson(OnRequestSocialPersonCompleteListener onRequestSocialPersonCompleteListener) { super.requestCurrentPerson(onRequestSocialPersonCompleteListener); final Session currentSession = mSessionTracker.getOpenSession(); if (currentSession == null) { if (mLocalListeners.get(REQUEST_GET_CURRENT_PERSON) != null) { mLocalListeners.get(REQUEST_GET_CURRENT_PERSON).onError(getID(), REQUEST_GET_CURRENT_PERSON, "please login first", null); } return; } Request request = Request.newMeRequest(currentSession, new Request.GraphUserCallback() { @Override public void onCompleted(GraphUser me, Response response) { if (response.getError() != null) { if (mLocalListeners.get(REQUEST_GET_CURRENT_PERSON) != null) { mLocalListeners.get(REQUEST_GET_CURRENT_PERSON).onError( getID(), REQUEST_GET_CURRENT_PERSON, response.getError().getErrorMessage() , null); } return; } if (mLocalListeners.get(REQUEST_GET_CURRENT_PERSON) != null) { SocialPerson socialPerson = new SocialPerson(); socialPerson.id = me.getId(); socialPerson.name = me.getName(); socialPerson.avatarURL = String.format("http://graph.facebook.com/%s/picture?width=200&height=200", me.getId()); socialPerson.profileURL = me.getLink(); socialPerson.nickname = me.getUsername(); ((OnRequestSocialPersonCompleteListener) mLocalListeners.get(REQUEST_GET_CURRENT_PERSON)) .onRequestSocialPersonSuccess(getID(), socialPerson); } } }); request.executeAsync(); } @Override public void requestSocialPerson(String userID, OnRequestSocialPersonCompleteListener onRequestSocialPersonCompleteListener) { throw new SocialNetworkException("requestSocialPerson isn't allowed for FacebookSocialNetwork"); } @Override public void requestPostMessage(String message, OnPostingCompleteListener onPostingCompleteListener) { super.requestPostMessage(message, onPostingCompleteListener); mStatus = message; performPublish(PendingAction.POST_STATUS_UPDATE); } @Override public void requestPostPhoto(File photo, String message, OnPostingCompleteListener onPostingCompleteListener) { super.requestPostPhoto(photo, message, onPostingCompleteListener); mPhotoPath = photo.getAbsolutePath(); performPublish(PendingAction.POST_PHOTO); } private void performPublish(PendingAction action) { Session session = Session.getActiveSession(); if (session != null) { mPendingAction = action; if (hasPublishPermission()) { // We can do the action right away. handlePendingAction(); return; } else if (session.isOpened()) { // We need to get new permissions, then complete the action when we get called back. session.requestNewPublishPermissions(new Session.NewPermissionsRequest(mSocialNetworkManager.getActivity(), PERMISSION)); return; } } if (action == PendingAction.POST_STATUS_UPDATE) { if (mLocalListeners.get(REQUEST_POST_MESSAGE) != null) { mLocalListeners.get(REQUEST_POST_MESSAGE).onError(getID(), REQUEST_POST_MESSAGE, "no session", null); } } if (action == PendingAction.POST_PHOTO) { if (mLocalListeners.get(REQUEST_POST_PHOTO) != null) { mLocalListeners.get(REQUEST_POST_PHOTO).onError(getID(), REQUEST_POST_PHOTO, "no session", null); } } } @Override public void requestCheckIsFriend(String userID, OnCheckIsFriendCompleteListener onCheckIsFriendCompleteListener) { throw new SocialNetworkException("requestCheckIsFriend isn't allowed for FacebookSocialNetwork"); } @Override public void requestAddFriend(String userID, OnRequestAddFriendCompleteListener onRequestAddFriendCompleteListener) { throw new SocialNetworkException("requestAddFriend isn't allowed for FacebookSocialNetwork"); } @Override public void requestRemoveFriend(String userID, OnRequestRemoveFriendCompleteListener onRequestRemoveFriendCompleteListener) { throw new SocialNetworkException("requestRemoveFriend isn't allowed for FacebookSocialNetwork"); } private void onSessionStateChange(Session session, SessionState state, Exception exception) { Log.d(TAG, "onSessionStateChange: " + state + " : " + exception); if (mSessionState == SessionState.OPENING && state == SessionState.OPENED) { if (mLocalListeners.get(REQUEST_LOGIN) != null) { ((OnLoginCompleteListener) mLocalListeners.get(REQUEST_LOGIN)).onLoginSuccess(getID()); mLocalListeners.remove(REQUEST_LOGIN); } } if (state == SessionState.CLOSED_LOGIN_FAILED) { if (mLocalListeners.get(REQUEST_LOGIN) != null) { mLocalListeners.get(REQUEST_LOGIN).onError(getID(), REQUEST_LOGIN, exception.getMessage(), null); mLocalListeners.remove(REQUEST_LOGIN); } } mSessionState = state; if (mPendingAction != PendingAction.NONE && (exception instanceof FacebookOperationCanceledException || exception instanceof FacebookAuthorizationException)) { mPendingAction = PendingAction.NONE; if (mLocalListeners.get(REQUEST_POST_MESSAGE) != null) { mLocalListeners.get(REQUEST_POST_MESSAGE).onError(getID(), REQUEST_POST_MESSAGE, "permission not granted", null); } if (mLocalListeners.get(REQUEST_POST_PHOTO) != null) { mLocalListeners.get(REQUEST_POST_PHOTO).onError(getID(), REQUEST_POST_PHOTO, "permission not granted", null); } } if (session.getPermissions().contains(PERMISSION) && state == SessionState.OPENED_TOKEN_UPDATED) { handlePendingAction(); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUILifecycleHelper = new UiLifecycleHelper(mSocialNetworkManager.getActivity(), mSessionStatusCallback); mUILifecycleHelper.onCreate(savedInstanceState); initializeActiveSessionWithCachedToken(mSocialNetworkManager.getActivity()); finishInit(); } private boolean initializeActiveSessionWithCachedToken(Context context) { if (context == null) { return false; } Session session = Session.getActiveSession(); if (session != null) { return session.isOpened(); } mApplicationId = Utility.getMetadataApplicationId(context); if (mApplicationId == null) { return false; } return Session.openActiveSessionFromCache(context) != null; } private void finishInit() { mSessionTracker = new SessionTracker( mSocialNetworkManager.getActivity(), mSessionStatusCallback, null, false); } @Override public void onResume() { super.onResume(); mUILifecycleHelper.onResume(); } @Override public void onPause() { super.onPause(); mUILifecycleHelper.onPause(); } @Override public void onDestroy() { super.onDestroy(); mUILifecycleHelper.onDestroy(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mUILifecycleHelper.onSaveInstanceState(outState); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { mUILifecycleHelper.onActivityResult(requestCode, resultCode, data, null); } private boolean hasPublishPermission() { Session session = Session.getActiveSession(); return session != null && session.getPermissions().contains(PERMISSION); } @SuppressWarnings("incomplete-switch") private void handlePendingAction() { PendingAction previouslyPendingAction = mPendingAction; // These actions may re-set pendingAction if they are still pending, but we assume they // will succeed. mPendingAction = PendingAction.NONE; switch (previouslyPendingAction) { case POST_PHOTO: postPhoto(mPhotoPath); break; case POST_STATUS_UPDATE: postStatusUpdate(mStatus); break; } } private void postStatusUpdate(String message) { if (isConnected() && hasPublishPermission()) { Request request = Request .newStatusUpdateRequest(Session.getActiveSession(), message, null, null, new Request.Callback() { @Override public void onCompleted(Response response) { publishSuccess(REQUEST_POST_MESSAGE, response.getError() == null ? null : response.getError().getErrorMessage()); } }); request.executeAsync(); } else { mPendingAction = PendingAction.POST_STATUS_UPDATE; } } private void postPhoto(final String path) { if (hasPublishPermission()) { Bitmap image = BitmapFactory.decodeFile(path); Request request = Request.newUploadPhotoRequest(Session.getActiveSession(), image, new Request.Callback() { @Override public void onCompleted(Response response) { publishSuccess(REQUEST_POST_PHOTO, response.getError() == null ? null : response.getError().getErrorMessage()); } }); request.executeAsync(); } else { mPendingAction = PendingAction.POST_PHOTO; } } private void publishSuccess(String requestID, String error) { if (mLocalListeners.get(requestID) == null) return; if (error != null) { mLocalListeners.get(requestID).onError(getID(), requestID, error, null); return; } ((OnPostingCompleteListener) mLocalListeners.get(requestID)).onPostSuccessfully(getID()); mLocalListeners.remove(requestID); } private enum PendingAction { NONE, POST_PHOTO, POST_STATUS_UPDATE } }