package com.androidsocialnetworks.lib.impl; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.text.TextUtils; import android.util.Log; import com.androidsocialnetworks.lib.AccessToken; import com.androidsocialnetworks.lib.OAuthActivity; import com.androidsocialnetworks.lib.OAuthSocialNetwork; import com.androidsocialnetworks.lib.SocialNetworkAsyncTask; 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.google.code.linkedinapi.client.CommunicationsApiClient; import com.google.code.linkedinapi.client.LinkedInApiClient; import com.google.code.linkedinapi.client.LinkedInApiClientFactory; import com.google.code.linkedinapi.client.constant.ApplicationConstants; import com.google.code.linkedinapi.client.enumeration.ProfileField; import com.google.code.linkedinapi.client.oauth.LinkedInAccessToken; import com.google.code.linkedinapi.client.oauth.LinkedInOAuthService; import com.google.code.linkedinapi.client.oauth.LinkedInOAuthServiceFactory; import com.google.code.linkedinapi.client.oauth.LinkedInRequestToken; import com.google.code.linkedinapi.schema.Headers; import com.google.code.linkedinapi.schema.HttpHeader; import com.google.code.linkedinapi.schema.Person; import com.google.code.linkedinapi.schema.Position; import java.io.File; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; public class LinkedInSocialNetwork extends OAuthSocialNetwork { public static final int ID = 2; public static final String OAUTH_CALLBACK_SCHEME = "x-oauthflow-linkedin"; public static final String OAUTH_CALLBACK_HOST = "linkedinApiTestCallback"; public static final String OAUTH_CALLBACK_URL = String.format("%s://%s", OAUTH_CALLBACK_SCHEME, OAUTH_CALLBACK_HOST); public static final String OAUTH_QUERY_TOKEN = "oauth_token"; public static final String OAUTH_QUERY_VERIFIER = "oauth_verifier"; public static final String OAUTH_QUERY_PROBLEM = "oauth_problem"; private static final String TAG = LinkedInSocialNetwork.class.getSimpleName(); private static final String SAVE_STATE_KEY_OAUTH_TOKEN = "LinkedInSocialNetwork.SAVE_STATE_KEY_OAUTH_TOKEN"; private static final String SAVE_STATE_KEY_OAUTH_SECRET = "LinkedInSocialNetwork.SAVE_STATE_KEY_OAUTH_SECRET"; // internal server error // private static final EnumSet<ProfileField> PROFILE_PARAMETERS = EnumSet.allOf(ProfileField.class); private static final EnumSet<ProfileField> PROFILE_PARAMETERS = EnumSet.of( ProfileField.ID, ProfileField.FIRST_NAME, ProfileField.LAST_NAME, ProfileField.POSITIONS, ProfileField.CONNECTIONS, ProfileField.API_STANDARD_PROFILE_REQUEST_HEADERS, ProfileField.PICTURE_URL, ProfileField.PUBLIC_PROFILE_URL ); // max 16 bit to use in startActivityForResult private static final int REQUEST_AUTH = UUID.randomUUID().hashCode() & 0xFFFF; private final LinkedInOAuthService mOAuthService; private final LinkedInApiClientFactory mLinkedInApiClientFactory; private String mOAuthTokenSecret; public LinkedInSocialNetwork(Fragment fragment, String consumerKey, String consumerSecret, String permissions) { super(fragment); Log.d(TAG, "new LinkedInSocialNetwork: " + consumerKey + " : " + consumerSecret + " : " + permissions); if (TextUtils.isEmpty(consumerKey) || TextUtils.isEmpty(consumerSecret) || TextUtils.isEmpty(permissions)) { throw new IllegalArgumentException("TextUtils.isEmpty(fConsumerKey) || TextUtils.isEmpty(fConsumerSecret) || TextUtils.isEmpty(fPermissions)"); } mOAuthService = LinkedInOAuthServiceFactory.getInstance() .createLinkedInOAuthService(consumerKey, consumerSecret, permissions); mLinkedInApiClientFactory = LinkedInApiClientFactory.newInstance(consumerKey, consumerSecret); } @Override public boolean isConnected() { String accessToken = mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, null); String accessTokenSecret = mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, null); return accessToken != null && accessTokenSecret != null; } @Override public AccessToken getAccessToken() { return new AccessToken( mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, null), mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, null) ); } @Override public void requestLogin(OnLoginCompleteListener onLoginCompleteListener) { super.requestLogin(onLoginCompleteListener); executeRequest(new RequestLoginAsyncTask(), null, REQUEST_LOGIN); } @Override public void logout() { fatalError(); } @Override public int getID() { return ID; } @Override public void requestCurrentPerson(OnRequestSocialPersonCompleteListener onRequestSocialPersonCompleteListener) { super.requestCurrentPerson(onRequestSocialPersonCompleteListener); executeRequest(new RequestCurrentPersonAsyncTask(), null, REQUEST_GET_CURRENT_PERSON); } @Override public void requestSocialPerson(String userID, OnRequestSocialPersonCompleteListener onRequestSocialPersonCompleteListener) { super.requestSocialPerson(userID, onRequestSocialPersonCompleteListener); Bundle args = new Bundle(); args.putString(RequestSocialPersonAsyncTask.PARAM_USER_ID, userID); executeRequest(new RequestSocialPersonAsyncTask(), args, REQUEST_GET_PERSON); } @Override public void requestPostMessage(String message, OnPostingCompleteListener onPostingCompleteListener) { super.requestPostMessage(message, onPostingCompleteListener); Bundle args = new Bundle(); args.putString(RequestPostMessageAsyncTask.PARAM_MESSAGE, message); executeRequest(new RequestPostMessageAsyncTask(), args, REQUEST_POST_MESSAGE); } @Override public void requestPostPhoto(File photo, String message, OnPostingCompleteListener onPostingCompleteListener) { throw new SocialNetworkException("requestPostPhoto isn't allowed for LinkedInSocialNetwork"); } @Override public void requestCheckIsFriend(String userID, OnCheckIsFriendCompleteListener onCheckIsFriendCompleteListener) { super.requestCheckIsFriend(userID, onCheckIsFriendCompleteListener); Bundle args = new Bundle(); args.putString(RequestCheckIsFriendAsyncTask.PARAM_USER_ID, userID); executeRequest(new RequestCheckIsFriendAsyncTask(), args, REQUEST_CHECK_IS_FRIEND); } @Override public void requestAddFriend(String userID, OnRequestAddFriendCompleteListener onRequestAddFriendCompleteListener) { super.requestAddFriend(userID, onRequestAddFriendCompleteListener); Bundle args = new Bundle(); args.putString(RequestSendInviteAsyncTask.PARAM_USER_ID, userID); executeRequest(new RequestSendInviteAsyncTask(), args, REQUEST_ADD_FRIEND); } @Override public void requestRemoveFriend(String userID, OnRequestRemoveFriendCompleteListener onRequestRemoveFriendCompleteListener) { throw new SocialNetworkException("requestRemoveFriend isn't allowed for LinkedInSocialNetwork"); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode != REQUEST_AUTH) return; if (resultCode != Activity.RESULT_OK || data == null || data.getData() == null) { if (mLocalListeners.get(REQUEST_LOGIN) != null) { mLocalListeners.get(REQUEST_LOGIN).onError(getID(), REQUEST_LOGIN, "Login canceled", null); } return; } Uri uri = data.getData(); final String problem = uri.getQueryParameter(OAUTH_QUERY_PROBLEM); if (problem != null) { if (mLocalListeners.get(REQUEST_LOGIN) != null) { mLocalListeners.get(REQUEST_LOGIN).onError(getID(), REQUEST_LOGIN, problem, null); } return; } Bundle args = new Bundle(); args.putString(RequestLogin2AsyncTask.PARAM_VERIFIER, uri.toString()); args.putString(RequestLogin2AsyncTask.PARAM_AUTH_REQUEST_TOKEN, mOAuthTokenSecret); executeRequest(new RequestLogin2AsyncTask(), args, REQUEST_LOGIN2); } private void fatalError() { mSharedPreferences.edit() .remove(SAVE_STATE_KEY_OAUTH_TOKEN) .remove(SAVE_STATE_KEY_OAUTH_SECRET) .apply(); } private class RequestLoginAsyncTask extends SocialNetworkAsyncTask { private static final String RESULT_URL = "RequestLoginAsyncTask.RESULT_URL"; @Override protected Bundle doInBackground(Bundle... params) { Bundle result = new Bundle(); try { final LinkedInRequestToken liToken = mOAuthService.getOAuthRequestToken(OAUTH_CALLBACK_URL); mOAuthTokenSecret = liToken.getTokenSecret(); result.putString(RESULT_URL, liToken.getAuthorizationUrl()); } catch (Exception e) { Log.e(TAG, "ERROR", e); result.putString(RESULT_ERROR, e.getMessage()); } return result; } @Override protected void onPostExecute(Bundle result) { if (!handleRequestResult(result, REQUEST_LOGIN)) return; Intent intent = new Intent(mSocialNetworkManager.getActivity(), OAuthActivity.class) .putExtra(OAuthActivity.PARAM_CALLBACK, OAUTH_CALLBACK_URL) .putExtra(OAuthActivity.PARAM_URL_TO_LOAD, result.getString(RESULT_URL)); mSocialNetworkManager.startActivityForResult(intent, REQUEST_AUTH); } } private class RequestLogin2AsyncTask extends SocialNetworkAsyncTask { public static final String PARAM_AUTH_REQUEST_TOKEN = "PARAM_AUTH_REQUEST_TOKEN"; public static final String PARAM_VERIFIER = "PARAM_VERIFIER"; private static final String RESULT_TOKEN = "RESULT_TOKEN"; private static final String RESULT_SECRET = "RESULT_SECRET"; @Override protected Bundle doInBackground(Bundle... params) { Bundle args = params[0]; final String paramAuthRequestToken = args.getString(PARAM_AUTH_REQUEST_TOKEN); final String paramVerifier = args.getString(PARAM_VERIFIER); Uri uri = Uri.parse(paramVerifier); Bundle result = new Bundle(); try { final LinkedInAccessToken accessToken = mOAuthService.getOAuthAccessToken( new LinkedInRequestToken( uri.getQueryParameter(OAUTH_QUERY_TOKEN), paramAuthRequestToken ), uri.getQueryParameter(OAUTH_QUERY_VERIFIER) ); result.putString(RESULT_TOKEN, accessToken.getToken()); result.putString(RESULT_SECRET, accessToken.getTokenSecret()); } catch (Exception e) { Log.e(TAG, "ERROR", e); result.putString(RESULT_ERROR, e.getMessage()); } return result; } @Override protected void onPostExecute(Bundle result) { mRequests.remove(REQUEST_LOGIN2); if (!handleRequestResult(result, REQUEST_LOGIN)) return; // Shared Preferences mSharedPreferences.edit() .putString(SAVE_STATE_KEY_OAUTH_TOKEN, result.getString(RESULT_TOKEN)) .putString(SAVE_STATE_KEY_OAUTH_SECRET, result.getString(RESULT_SECRET)) .apply(); ((OnLoginCompleteListener) mLocalListeners.get(REQUEST_LOGIN)).onLoginSuccess(getID()); mLocalListeners.remove(REQUEST_LOGIN); } } private class RequestCurrentPersonAsyncTask extends SocialNetworkAsyncTask { private static final String RESULT_ID = "LoginAsyncTask.RESULT_ID"; private static final String RESULT_NAME = "LoginAsyncTask.RESULT_NAME"; private static final String RESULT_AVATAR_URL = "LoginAsyncTask.RESULT_AVATAR_URL"; private static final String RESULT_COMPANY = "LoginAsyncTask.RESULT_COMPANY"; private static final String RESULT_POSITION = "LoginAsyncTask.RESULT_POSITION"; private static final String RESULT_PROFILE_URL = "LoginAsyncTask.RESULT_PROFILE_URL"; @Override protected Bundle doInBackground(Bundle... params) { Bundle result = new Bundle(); try { LinkedInApiClient client = mLinkedInApiClientFactory.createLinkedInApiClient( new LinkedInAccessToken( mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, null), mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, null) ) ); Person person = client.getProfileForCurrentUser(PROFILE_PARAMETERS); result.putString(RESULT_ID, person.getId()); result.putString(RESULT_NAME, person.getFirstName() + " " + person.getLastName()); result.putString(RESULT_AVATAR_URL, person.getPictureUrl()); result.putString(RESULT_PROFILE_URL, person.getPublicProfileUrl()); List<Position> positions = person.getPositions().getPositionList(); if (positions.size() > 0) { Position position = positions.get(positions.size() - 1); result.putString(RESULT_COMPANY, position.getCompany().getName()); result.putString(RESULT_POSITION, position.getTitle()); } } catch (Exception e) { Log.e(TAG, "ERROR", e); result.putString(RESULT_ERROR, e.getMessage()); } return result; } @Override protected void onPostExecute(Bundle result) { if (!handleRequestResult(result, REQUEST_GET_CURRENT_PERSON)) return; SocialPerson socialPerson = new SocialPerson(); socialPerson.id = result.getString(RESULT_ID); socialPerson.name = result.getString(RESULT_NAME); socialPerson.avatarURL = result.getString(RESULT_AVATAR_URL); socialPerson.company = result.getString(RESULT_COMPANY); socialPerson.position = result.getString(RESULT_POSITION); socialPerson.profileURL = result.getString(RESULT_PROFILE_URL); ((OnRequestSocialPersonCompleteListener) mLocalListeners.get(REQUEST_GET_CURRENT_PERSON)). onRequestSocialPersonSuccess(getID(), socialPerson); mLocalListeners.remove(REQUEST_GET_CURRENT_PERSON); } } private class RequestSocialPersonAsyncTask extends SocialNetworkAsyncTask { public static final String PARAM_USER_ID = "PARAM_USER_ID"; private static final String RESULT_ID = "LoginAsyncTask.RESULT_ID"; private static final String RESULT_NAME = "LoginAsyncTask.RESULT_NAME"; private static final String RESULT_AVATAR_URL = "LoginAsyncTask.RESULT_AVATAR_URL"; private static final String RESULT_COMPANY = "LoginAsyncTask.RESULT_COMPANY"; private static final String RESULT_POSITION = "LoginAsyncTask.RESULT_POSITION"; @Override protected Bundle doInBackground(Bundle... params) { String userID = params[0].getString(PARAM_USER_ID); Bundle result = new Bundle(); try { LinkedInApiClient client = mLinkedInApiClientFactory.createLinkedInApiClient( new LinkedInAccessToken( mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, null), mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, null) ) ); Person person = client.getProfileById(userID); result.putString(RESULT_ID, person.getId()); result.putString(RESULT_NAME, person.getFirstName() + " " + person.getLastName()); result.putString(RESULT_AVATAR_URL, person.getPictureUrl()); List<Position> positions = person.getPositions() == null ? new ArrayList<Position>() : person.getPositions().getPositionList(); if (positions.size() > 0) { Position position = positions.get(positions.size() - 1); result.putString(RESULT_COMPANY, position.getCompany().getName()); result.putString(RESULT_POSITION, position.getTitle()); } } catch (Exception e) { Log.e(TAG, "ERROR", e); result.putString(RESULT_ERROR, e.getMessage()); } return result; } @Override protected void onPostExecute(Bundle result) { if (!handleRequestResult(result, REQUEST_GET_PERSON)) return; SocialPerson socialPerson = new SocialPerson(); socialPerson.id = result.getString(RESULT_ID); socialPerson.name = result.getString(RESULT_NAME); socialPerson.avatarURL = result.getString(RESULT_AVATAR_URL); socialPerson.company = result.getString(RESULT_COMPANY); socialPerson.position = result.getString(RESULT_POSITION); ((OnRequestSocialPersonCompleteListener) mLocalListeners.get(REQUEST_GET_PERSON)). onRequestSocialPersonSuccess(getID(), socialPerson); mLocalListeners.remove(REQUEST_GET_PERSON); } } private class RequestPostMessageAsyncTask extends SocialNetworkAsyncTask { private static final String PARAM_MESSAGE = "PARAM_MESSAGE"; @Override protected Bundle doInBackground(Bundle... params) { String message = params[0].getString(PARAM_MESSAGE); Bundle result = new Bundle(); try { LinkedInApiClient apiClient = mLinkedInApiClientFactory.createLinkedInApiClient( mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, ""), mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, "") ); apiClient.updateCurrentStatus(message); } catch (Exception e) { Log.e(TAG, "ERROR", e); result.putString(RESULT_ERROR, e.getMessage()); } return result; } @Override protected void onPostExecute(Bundle result) { if (!handleRequestResult(result, REQUEST_POST_MESSAGE)) return; ((OnPostingCompleteListener) mLocalListeners.get(REQUEST_POST_MESSAGE)) .onPostSuccessfully(getID()); } } private class RequestCheckIsFriendAsyncTask extends SocialNetworkAsyncTask { public static final String PARAM_USER_ID = "PARAM_USER_ID"; private static final String RESULT_IS_FRIEND = "RESULT_IS_FRIEND"; private static final String RESULT_REQUESTED_ID = "RESULT_REQUESTED_ID"; @Override protected Bundle doInBackground(Bundle... params) { String userID = params[0].getString(PARAM_USER_ID); Bundle result = new Bundle(); result.putString(RESULT_REQUESTED_ID, userID); try { LinkedInApiClient apiClient = mLinkedInApiClientFactory.createLinkedInApiClient( mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, ""), mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, "") ); Person person = apiClient.getProfileForCurrentUser(PROFILE_PARAMETERS); List<Person> list = person.getConnections().getPersonList(); if (list != null) { for (Person p : list) { if (p.getId().equals(userID)) { result.putBoolean(RESULT_IS_FRIEND, true); return result; } } } result.putBoolean(RESULT_IS_FRIEND, false); } catch (Exception e) { Log.e(TAG, "ERROR", e); result.putString(RESULT_ERROR, e.getMessage()); } return result; } @Override protected void onPostExecute(Bundle result) { if (!handleRequestResult(result, REQUEST_CHECK_IS_FRIEND, result.getString(RESULT_REQUESTED_ID))) return; ((OnCheckIsFriendCompleteListener) mLocalListeners.get(REQUEST_CHECK_IS_FRIEND)) .onCheckIsFriendComplete( getID(), result.getString(RESULT_REQUESTED_ID), result.getBoolean(RESULT_IS_FRIEND) ); mLocalListeners.remove(REQUEST_CHECK_IS_FRIEND); } } private class RequestSendInviteAsyncTask extends SocialNetworkAsyncTask { public static final String PARAM_USER_ID = "PARAM_USER_ID"; private static final String RESULT_REQUESTED_ID = "RESULT_REQUESTED_ID"; @Override protected Bundle doInBackground(Bundle... params) { String userID = params[0].getString(PARAM_USER_ID); Bundle result = new Bundle(); try { result.putString(RESULT_REQUESTED_ID, userID); LinkedInApiClient apiClient = mLinkedInApiClientFactory.createLinkedInApiClient( mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, ""), mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, "") ); Set<ProfileField> fields = new HashSet<ProfileField>(); fields.add(ProfileField.API_STANDARD_PROFILE_REQUEST); Person person = apiClient.getProfileById(userID, fields); String authHeader = ""; Headers headers = person.getApiStandardProfileRequest().getHeaders(); List<HttpHeader> httpHeaders = headers.getHttpHeaderList(); for (HttpHeader httpHeader : httpHeaders) { if (httpHeader.getName().equals(ApplicationConstants.AUTH_HEADER_NAME)) { authHeader = httpHeader.getValue(); break; } } CommunicationsApiClient communicationsApiClient = mLinkedInApiClientFactory.createCommunicationsApiClient( mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_TOKEN, ""), mSharedPreferences.getString(SAVE_STATE_KEY_OAUTH_SECRET, "") ); communicationsApiClient.sendInviteById(userID, "Join my network on LinkedIn", "Since you are a person I trust, I wanted to invite you to join my network on LinkedIn.", authHeader); } catch (Exception e) { Log.e(TAG, "ERROR", e); result.putString(RESULT_ERROR, e.getMessage()); } return result; } @Override protected void onPostExecute(Bundle result) { if (!handleRequestResult(result, REQUEST_ADD_FRIEND, result.getString(RESULT_REQUESTED_ID))) return; ((OnRequestAddFriendCompleteListener) mLocalListeners.get(REQUEST_ADD_FRIEND)) .onRequestAddFriendComplete( getID(), result.getString(RESULT_REQUESTED_ID) ); mLocalListeners.remove(REQUEST_CHECK_IS_FRIEND); } } }