/* * Copyright (c) 2012 Socialize Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.socialize.networks.facebook.v2; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import com.facebook.HttpMethod; import com.socialize.android.ioc.IBeanFactory; import com.socialize.api.SocializeSession; import com.socialize.auth.AuthProviderType; import com.socialize.auth.DefaultUserProviderCredentials; import com.socialize.auth.UserProviderCredentials; import com.socialize.auth.UserProviderCredentialsMap; import com.socialize.auth.facebook.FacebookDialogListener; import com.socialize.auth.facebook.FacebookSessionStore; import com.socialize.error.SocializeException; import com.socialize.facebook.AsyncFacebookRunner; import com.socialize.facebook.AsyncFacebookRunner.RequestListener; import com.socialize.facebook.Facebook; import com.socialize.facebook.Facebook.ServiceListener; import com.socialize.facebook.FacebookError; import com.socialize.listener.AuthProviderListener; import com.socialize.listener.ListenerHolder; import com.socialize.listener.SocializeAuthListener; import com.socialize.log.SocializeLogger; import com.socialize.networks.PostData; import com.socialize.networks.SocialNetwork; import com.socialize.networks.SocialNetworkListener; import com.socialize.networks.SocialNetworkPostListener; import com.socialize.networks.facebook.BaseFacebookFacade; import com.socialize.networks.facebook.FacebookUtilsProxy; import com.socialize.networks.facebook.OnPermissionResult; import com.socialize.util.StringUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * @author Jason Polites */ @Deprecated public class FacebookFacadeV2 extends BaseFacebookFacade { private FacebookUtilsProxy facebookUtils; private IBeanFactory<AsyncFacebookRunner> facebookRunnerFactory; private FacebookSessionStore facebookSessionStore; @Override public void onActivityResult(Activity context, int requestCode, int resultCode, Intent data) { getFacebook(context).authorizeCallback(requestCode, resultCode, data); } @Override public int getSDKMajorVersion() { return 2; } @Override public void authenticate(Activity context, String appId, String[] permissions, boolean sso, boolean read, AuthProviderListener listener) { authenticate(context, appId, permissions, sso, listener); } @Deprecated @Override public void authenticate(final Activity context, String appId, final String[] permissions, final boolean sso, final AuthProviderListener listener) { Facebook facebook = getFacebook(context); facebookSessionStore.restore(facebook, context); FacebookDialogListener facebookDialogListener = new FacebookDialogListener(context, facebook, facebookSessionStore, listener) { @Override public void onFinish() { context.finish(); } @Override public void handleError(Throwable error) { if(listener != null) { listener.onError(new SocializeException(error)); } else { error.printStackTrace(); } } }; if(sso) { facebook.authorize(context, permissions, facebookDialogListener); } else { facebook.authorize(context, permissions, Facebook.FORCE_DIALOG_AUTH, facebookDialogListener); } } @Override public void onResume(Activity context, SocializeAuthListener listener) { extendAccessToken(context, listener); } /* (non-Javadoc) * @see com.socialize.networks.facebook.FacebookFacade#extendAccessToken(android.app.Activity, com.socialize.listener.SocializeAuthListener) */ @Override public void extendAccessToken(final Activity context, final SocializeAuthListener listener) { try { Facebook facebook = getFacebook(context); if(isLinked(context)) { if(facebook != null && !facebook.extendAccessTokenIfNeeded(context, new ServiceListener() { @Override public void onFacebookError(FacebookError e) { if(logger != null) { logger.warn("An error occurred while attempting to extend a Facebook access token. The local Facebook account will be cleared.", e); } // Clear the local session state unlink(context, null); } @Override public void onError(Error e) { if(logger != null) { logger.warn("An error occurred while attempting to extend a Facebook access token. The local Facebook account will be cleared.", e); } // Clear the local session state unlink(context, null); } @Override public void onComplete(Bundle values) { // Update the local session state SocializeSession session = getSocialize().getSession(); if(session != null) { final String newAccessToken = values.getString(Facebook.TOKEN); if(!StringUtils.isEmpty(newAccessToken)) { if(logger != null && logger.isDebugEnabled()) { logger.debug("Got new Facebook access token [" + newAccessToken + "]"); } // Link the user again link(context, newAccessToken, false, new SocializeAuthListener() { @Override public void onError(SocializeException error) { if(logger != null) { logger.error("An error occurred while attempting to update authentication details", error); } if(listener != null) { listener.onError(error); } } @Override public void onCancel() { if(listener != null) { listener.onCancel(); } } @Override public void onAuthSuccess(SocializeSession session) { UserProviderCredentialsMap map = session.getUserProviderCredentials(); UserProviderCredentials creds = map.get(AuthProviderType.FACEBOOK); DefaultUserProviderCredentials newCreds = new DefaultUserProviderCredentials(); if(creds != null) { newCreds.merge(creds); } newCreds.setAccessToken(newAccessToken); map.put(AuthProviderType.FACEBOOK, newCreds); getSocialize().setSession(session); getSocialize().saveSession(context); if(listener != null) { listener.onAuthSuccess(session); } } @Override public void onAuthFail(SocializeException error) { if(logger != null) { logger.error("An error occurred while attempting to update authentication details", error); } if(listener != null) { listener.onAuthFail(error); } } }); } else { if(logger != null) { logger.warn("Access token returned from Facebook was empty during request to extend"); } } } } })) { if(logger != null) { logger.warn("Failed to bind to the Facebook RefreshToken Service"); } } } else if(facebook != null) { // Ensure the local fb session is cleared String accessToken = facebook.getAccessToken(); if(!StringUtils.isEmpty(accessToken)) { new FacebookSessionStore().clear(context); } } } catch (Exception e) { if(listener != null) { listener.onError(SocializeException.wrap(e)); } if(logger != null) { logger.error("Failure during Facebook Token Refresh", e); } } } /* (non-Javadoc) * @see com.socialize.networks.facebook.FacebookFacade#post(android.app.Activity, com.socialize.networks.SocialNetworkListener, com.socialize.networks.PostData) */ @Override public void post(Activity parent, SocialNetworkListener listener, PostData postData) { boolean okToGo = true; if(listener != null) { okToGo = !listener.onBeforePost(parent, SocialNetwork.FACEBOOK, postData); } if(okToGo) { Bundle bundle = new Bundle(); Map<String, Object> postValues = postData.getPostValues(); if(postValues != null) { Set<Entry<String, Object>> entries = postValues.entrySet(); for (Entry<String, Object> entry : entries) { if(entry != null) { Object value = entry.getValue(); String key = entry.getKey(); if(key != null && value != null) { if(value instanceof byte[]) { bundle.putByteArray(entry.getKey(), (byte[]) value); } else { bundle.putString(entry.getKey(), value.toString()); } } } } } Facebook fb = getFacebook(parent); final FacebookSessionStore store = newFacebookSessionStore(); store.restore(fb, parent); AsyncFacebookRunner runner = newAsyncFacebookRunner(fb); RequestListener requestListener = newRequestListener(parent, listener); String path = postData.getPath(); if(StringUtils.isEmpty(path)) { path = "me/links"; } runner.request(path, bundle, "POST", requestListener, null); } } /* (non-Javadoc) * @see com.socialize.networks.facebook.FacebookFacade#getCurrentPermissions(android.app.Activity, java.lang.String, com.socialize.networks.facebook.v2.FacebookPermissionCallback) */ @Override public void getCurrentPermissions(final Activity parent, String token, final OnPermissionResult callback) { Facebook fb = new Facebook(getFacebookAppId()); fb.setAccessToken(token); AsyncFacebookRunner runner = newAsyncFacebookRunner(fb); runner.request("me/permissions", new RequestListener() { @Override public void onMalformedURLException(MalformedURLException e, Object state) { handlePermissionError(parent, callback, e); } @Override public void onIOException(IOException e, Object state) { handlePermissionError(parent, callback, e); } @Override public void onFileNotFoundException(FileNotFoundException e, Object state) { handlePermissionError(parent, callback, e); } @Override public void onFacebookError(FacebookError e, Object state) { handlePermissionError(parent, callback, e); } @Override public void onComplete(final String response, final Object state) { if(callback != null) { parent.runOnUiThread(new Runnable() { @Override public void run() { try { JSONObject json = new JSONObject(response); if(json.has("data") && !json.isNull("data")) { JSONObject data = json.getJSONArray("data").getJSONObject(0); // Permissions are keys JSONArray names = data.names(); ArrayList<String> current = new ArrayList<String>(); for (int i = 0; i < names.length(); i++) { // If we're ON we're on String permission = names.getString(i); int status = data.getInt(permission); if(status == 1) { // ON current.add(permission); } } String[] values = current.toArray(new String[current.size()]); Arrays.sort(values); // Sort for binary searching callback.onSuccess(values); } } catch (JSONException e) { callback.onError(new SocializeException(e)); } } }); } } }); } /* (non-Javadoc) * @see com.socialize.networks.facebook.FacebookFacade#logout(android.content.Context) */ @Override public void logout(Context context) { // Logout does NOT clear the token.. thanks FB :/ new FacebookSessionStore().clear(context); Facebook mFacebook = getFacebook(context); try { if(mFacebook != null) { mFacebook.logout(context); } } catch (Exception e) { if(logger != null) { logger.error("Failed to log out of Facebook", e); } else { SocializeLogger.e("Failed to log out of Facebook", e); } } finally { if(facebookSessionStore != null) { facebookSessionStore.clear(context); } } } // So we can mock protected Facebook getFacebook(Context context) { return facebookUtils.getFacebook(context); } // So we can mock protected AsyncFacebookRunner newAsyncFacebookRunner(Facebook fb) { if(facebookRunnerFactory != null) { return facebookRunnerFactory.getBean(fb); } return new AsyncFacebookRunner(fb); } // So we can mock protected FacebookSessionStore newFacebookSessionStore() { return new FacebookSessionStore(); } // So we can mock protected JSONObject newJSONObject(String response) throws JSONException { return new JSONObject(response); } // So we can mock protected RequestListener newRequestListener(final Activity parent, final SocialNetworkPostListener listener) { final String defaultErrorMessage = "Facebook Error"; return new RequestListener() { public void onMalformedURLException(MalformedURLException e, Object state) { handleFacebookError(parent, 0, defaultErrorMessage, e, listener); } public void onIOException(IOException e, Object state) { handleFacebookError(parent, 0, defaultErrorMessage, e, listener); } public void onFileNotFoundException(final FileNotFoundException e, Object state) { handleFacebookError(parent, 0, defaultErrorMessage, e, listener); } public void onFacebookError(FacebookError e, Object state) { handleFacebookError(parent, 0, defaultErrorMessage, e, listener); } public void onComplete(final String response, Object state) { JSONObject responseObject = null; if(!StringUtils.isEmpty(response)) { try { responseObject = newJSONObject(response); if(responseObject.has("error")) { JSONObject error = responseObject.getJSONObject("error"); int code = 0; if(error.has("code") && !error.isNull("code")) { code = error.getInt("code"); } if(error.has("message") && !error.isNull("message")) { String msg = error.getString("message"); if(logger != null) { logger.error(msg); } else { System.err.println(msg); } handleFacebookError(parent, code, msg, new SocializeException(msg), listener); } else { handleFacebookError(parent, code, defaultErrorMessage, new SocializeException("Facebook Error (Unknown)"), listener); } return; } } catch (JSONException e) { onError(parent, defaultErrorMessage, e, listener); return; } } if(listener != null) { final JSONObject fResponse = responseObject; parent.runOnUiThread(new Runnable() { @Override public void run() { listener.onAfterPost(parent, SocialNetwork.FACEBOOK, fResponse); } }); } } }; } protected void doFacebookCall(Activity parent, Bundle data, String graphPath, HttpMethod method, SocialNetworkPostListener listener) { Facebook fb = getFacebook(parent); FacebookSessionStore store = newFacebookSessionStore(); store.restore(fb, parent); AsyncFacebookRunner runner = newAsyncFacebookRunner(fb); RequestListener requestListener = newRequestListener(parent, listener); runner.request(graphPath, data, method.toString(), requestListener, null); } public void setFacebookUtils(FacebookUtilsProxy facebookUtils) { this.facebookUtils = facebookUtils; } public void setFacebookRunnerFactory(IBeanFactory<AsyncFacebookRunner> facebookRunnerFactory) { this.facebookRunnerFactory = facebookRunnerFactory; } public void setFacebookSessionStore(FacebookSessionStore facebookSessionStore) { this.facebookSessionStore = facebookSessionStore; } public void setHolder(ListenerHolder holder) { this.holder = holder; } }