001package com.gigya.android.sdk.providers.provider; 002 003import android.content.Context; 004import android.content.Intent; 005import android.os.Bundle; 006import android.support.annotation.Nullable; 007import android.support.v7.app.AppCompatActivity; 008 009import com.facebook.AccessToken; 010import com.facebook.AccessTokenTracker; 011import com.facebook.CallbackManager; 012import com.facebook.FacebookCallback; 013import com.facebook.FacebookException; 014import com.facebook.login.LoginBehavior; 015import com.facebook.login.LoginManager; 016import com.facebook.login.LoginResult; 017import com.gigya.android.sdk.api.IBusinessApiService; 018import com.gigya.android.sdk.persistence.IPersistenceService; 019import com.gigya.android.sdk.ui.HostActivity; 020import com.gigya.android.sdk.utils.FileUtils; 021import com.gigya.android.sdk.utils.ObjectUtils; 022 023import org.json.JSONObject; 024 025import java.util.Arrays; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029 030import static com.gigya.android.sdk.GigyaDefinitions.Providers.FACEBOOK; 031 032public class FacebookProvider extends Provider { 033 034 public FacebookProvider(Context context, 035 IPersistenceService persistenceService, 036 IBusinessApiService businessApiService, 037 ProviderCallback providerCallback) { 038 super(context, persistenceService, businessApiService, providerCallback); 039 } 040 041 private static final String[] DEFAULT_READ_PERMISSIONS = {"email"}; 042 043 private final CallbackManager _callbackManager = CallbackManager.Factory.create(); 044 private AccessTokenTracker _tokenTracker; 045 046 @Override 047 public String getName() { 048 return FACEBOOK; 049 } 050 051 public static boolean isAvailable(FileUtils fileUtils) { 052 try { 053 String fbAppId = fileUtils.stringFromMetaData("com.facebook.sdk.ApplicationId"); 054 Class.forName("com.facebook.login.LoginManager"); 055 return fbAppId != null; 056 } catch (Throwable t) { 057 return false; 058 } 059 } 060 061 @Override 062 public void login(final Map<String, Object> loginParams, final String loginMode) { 063 if (_connecting) { 064 return; 065 } 066 _connecting = true; 067 _loginMode = loginMode; 068 // Get login permissions. 069 final List<String> readPermissions = getReadPermissions(loginParams); 070 071 AccessToken accessToken = AccessToken.getCurrentAccessToken(); 072 // Check login state. 073 boolean isLoggedIn = accessToken != null && !accessToken.isExpired() && permissionsGranted(readPermissions); 074 if (isLoggedIn) { 075 onLoginSuccess(loginParams, getProviderSessions(accessToken.getToken(), accessToken.getExpires().getTime() / 1000, null), loginMode); 076 return; 077 } 078 // Start new login flow. 079 HostActivity.present(_context, new HostActivity.HostActivityLifecycleCallbacks() { 080 @Override 081 public void onCreate(final AppCompatActivity activity, @Nullable Bundle savedInstanceState) { 082 final LoginManager loginManager = LoginManager.getInstance(); 083 // Set login behaviour. 084 LoginBehavior loginBehaviour = LoginBehavior.NATIVE_WITH_FALLBACK; 085 if (loginParams != null && loginParams.containsKey(LOGIN_BEHAVIOUR)) { 086 Object behaviour = loginParams.get(LOGIN_BEHAVIOUR); 087 if (behaviour instanceof LoginBehavior) { 088 loginBehaviour = (LoginBehavior) behaviour; 089 } 090 } 091 loginManager.setLoginBehavior(loginBehaviour); 092 loginManager.registerCallback(_callbackManager, new FacebookCallback<LoginResult>() { 093 @Override 094 public void onSuccess(LoginResult loginResult) { 095 loginManager.unregisterCallback(_callbackManager); 096 AccessToken accessToken = AccessToken.getCurrentAccessToken(); 097 onLoginSuccess(loginParams, getProviderSessions(accessToken.getToken(), accessToken.getExpires().getTime() / 1000, null), loginMode); 098 activity.finish(); 099 } 100 101 @Override 102 public void onCancel() { 103 loginManager.unregisterCallback(_callbackManager); 104 onCanceled(); 105 activity.finish(); 106 } 107 108 @Override 109 public void onError(FacebookException error) { 110 loginManager.unregisterCallback(_callbackManager); 111 onLoginFailed(error.getLocalizedMessage()); 112 activity.finish(); 113 } 114 }); 115 // Request login. 116 loginManager.logInWithReadPermissions(activity, readPermissions); 117 } 118 119 @Override 120 public void onActivityResult(AppCompatActivity activity, int requestCode, int resultCode, @Nullable Intent data) { 121 _callbackManager.onActivityResult(requestCode, resultCode, data); 122 } 123 124 }); 125 } 126 127 @Override 128 public void logout() { 129 super.logout(); 130 if (_tokenTracker != null) { 131 _tokenTracker.stopTracking(); 132 } 133 if (AccessToken.getCurrentAccessToken() != null) { 134 LoginManager.getInstance().logOut(); 135 } 136 } 137 138 @Override 139 public String getProviderSessions(String tokenOrCode, long expiration, String uid) { 140 // token & expiration is relevant 141 try { 142 return new JSONObject() 143 .put("facebook", new JSONObject() 144 .put("authToken", tokenOrCode).put("tokenExpiration", expiration)).toString(); 145 } catch (Exception ex) { 146 _connecting = false; 147 ex.printStackTrace(); 148 } 149 return null; 150 } 151 152 @Override 153 public boolean supportsTokenTracking() { 154 return true; 155 } 156 157 @Override 158 public void trackTokenChange() { 159 _tokenTracker = new AccessTokenTracker() { 160 161 @Override 162 protected void onCurrentAccessTokenChanged(AccessToken oldAccessToken, AccessToken currentAccessToken) { 163 // Send api request. 164 final String newAuthToken = currentAccessToken.getToken(); 165 final long expiresInSeconds = currentAccessToken.getExpires().getTime() / 1000; 166 _tokenTrackingListener.onTokenChange(getName(), getProviderSessions(newAuthToken, expiresInSeconds, null), null); 167 } 168 }; 169 } 170 171 //region SPECIFIC PROVIDER LOGIC 172 173 public static final String LOGIN_BEHAVIOUR = "facebookLoginBehavior"; 174 public static final String READ_PERMISSIONS = "facebookReadPermissions"; 175 public static final String PUBLISH_PERMISSIONS = "facebookPublishPermissions"; 176 177 private List<String> getReadPermissions(Map<String, Object> loginParams) { 178 List<String> readPermissions = Arrays.asList(DEFAULT_READ_PERMISSIONS); 179 if (loginParams != null && loginParams.containsKey(READ_PERMISSIONS)) { 180 String userDefinedReadPermissions = (String) loginParams.get(READ_PERMISSIONS); 181 if (userDefinedReadPermissions != null) { 182 final String[] split = userDefinedReadPermissions.split(","); 183 readPermissions = ObjectUtils.mergeRemovingDuplicates(readPermissions, Arrays.asList(split)); 184 } 185 } 186 return readPermissions; 187 } 188 189 private boolean permissionsGranted(List<String> permissions) { 190 AccessToken fbAccessToken = AccessToken.getCurrentAccessToken(); 191 Set<String> grantedPermissions = fbAccessToken.getPermissions(); 192 for (String permission : permissions) { 193 if (!grantedPermissions.contains(permission)) 194 return false; 195 } 196 return true; 197 } 198 199 //endregion 200}