- * Note that Session automatically attempts to extend the lifetime of Tokens
- * as needed when Facebook requests are made.
- *
- *
- * @return the Date at which the current token will expire, or null if there is no access token
- */
- public final Date getExpirationDate() {
- synchronized (this.lock) {
- return (this.tokenInfo == null) ? null : this.tokenInfo.getExpires();
- }
- }
-
- /**
- *
- * If there is a valid token, this represents the permissions granted by
- * that token. This can change during calls to
- * {@link #requestNewReadPermissions}
- * or {@link #requestNewPublishPermissions}.
- *
- *
- * @return the list of permissions associated with the session, or null if there is no access token
- */
- public final List getPermissions() {
- synchronized (this.lock) {
- return (this.tokenInfo == null) ? null : this.tokenInfo.getPermissions();
- }
- }
-
- /**
- *
- * Logs a user in to Facebook.
- *
- *
- * A session may not be used with {@link Request Request} and other classes
- * in the SDK until it is open. If, prior to calling open, the session is in
- * the {@link SessionState#CREATED_TOKEN_LOADED CREATED_TOKEN_LOADED}
- * state, and the requested permissions are a subset of the previously authorized
- * permissions, then the Session becomes usable immediately with no user interaction.
- *
- *
- * The permissions associated with the openRequest passed to this method must
- * be read permissions only (or null/empty). It is not allowed to pass publish
- * permissions to this method and will result in an exception being thrown.
- *
- *
- * Any open method must be called at most once, and cannot be called after the
- * Session is closed. Calling the method at an invalid time will result in
- * UnsuportedOperationException.
- *
- *
- * @param openRequest the open request, can be null only if the Session is in the
- * {@link SessionState#CREATED_TOKEN_LOADED CREATED_TOKEN_LOADED} state
- * @throws FacebookException if any publish or manage permissions are requested
- */
- public final void openForRead(OpenRequest openRequest) {
- open(openRequest, SessionAuthorizationType.READ);
- }
-
- /**
- *
- * Logs a user in to Facebook.
- *
- *
- * A session may not be used with {@link Request Request} and other classes
- * in the SDK until it is open. If, prior to calling open, the session is in
- * the {@link SessionState#CREATED_TOKEN_LOADED CREATED_TOKEN_LOADED}
- * state, and the requested permissions are a subset of the previously authorized
- * permissions, then the Session becomes usable immediately with no user interaction.
- *
- *
- * The permissions associated with the openRequest passed to this method must
- * be publish or manage permissions only and must be non-empty. Any read permissions
- * will result in a warning, and may fail during server-side authorization.
- *
- *
- * Any open method must be called at most once, and cannot be called after the
- * Session is closed. Calling the method at an invalid time will result in
- * UnsuportedOperationException.
- *
- *
- * @param openRequest the open request, can be null only if the Session is in the
- * {@link SessionState#CREATED_TOKEN_LOADED CREATED_TOKEN_LOADED} state
- * @throws FacebookException if the passed in request is null or has no permissions set.
- */
- public final void openForPublish(OpenRequest openRequest) {
- open(openRequest, SessionAuthorizationType.PUBLISH);
- }
-
- /**
- * Opens a session based on an existing Facebook access token. This method should be used
- * only in instances where an application has previously obtained an access token and wishes
- * to import it into the Session/TokenCachingStrategy-based session-management system. An
- * example would be an application which previously did not use the Facebook SDK for Android
- * and implemented its own session-management scheme, but wishes to implement an upgrade path
- * for existing users so they do not need to log in again when upgrading to a version of
- * the app that uses the SDK.
- *
- * No validation is done that the token, token source, or permissions are actually valid.
- * It is the caller's responsibility to ensure that these accurately reflect the state of
- * the token that has been passed in, or calls to the Facebook API may fail.
- *
- * @param accessToken the access token obtained from Facebook
- * @param callback a callback that will be called when the session status changes; may be null
- */
- public final void open(AccessToken accessToken, StatusCallback callback) {
- synchronized (this.lock) {
- if (pendingRequest != null) {
- throw new UnsupportedOperationException(
- "Session: an attempt was made to open a session that has a pending request.");
- }
-
- if (state != SessionState.CREATED && state != SessionState.CREATED_TOKEN_LOADED) {
- throw new UnsupportedOperationException(
- "Session: an attempt was made to open an already opened session.");
- }
-
- if (callback != null) {
- addCallback(callback);
- }
-
- this.tokenInfo = accessToken;
-
- if (this.tokenCachingStrategy != null) {
- this.tokenCachingStrategy.save(accessToken.toCacheBundle());
- }
-
- final SessionState oldState = state;
- state = SessionState.OPENED;
- this.postStateChange(oldState, state, null);
- }
-
- autoPublishAsync();
- }
-
- /**
- *
- * Issues a request to add new read permissions to the Session.
- *
- *
- * If successful, this will update the set of permissions on this session to
- * match the newPermissions. If this fails, the Session remains unchanged.
- *
- *
- * The permissions associated with the newPermissionsRequest passed to this method must
- * be read permissions only (or null/empty). It is not allowed to pass publish
- * permissions to this method and will result in an exception being thrown.
- *
- *
- * @param newPermissionsRequest the new permissions request
- */
- public final void requestNewReadPermissions(NewPermissionsRequest newPermissionsRequest) {
- requestNewPermissions(newPermissionsRequest, SessionAuthorizationType.READ);
- }
-
- /**
- *
- * Issues a request to add new publish or manage permissions to the Session.
- *
- *
- * If successful, this will update the set of permissions on this session to
- * match the newPermissions. If this fails, the Session remains unchanged.
- *
- *
- * The permissions associated with the newPermissionsRequest passed to this method must
- * be publish or manage permissions only and must be non-empty. Any read permissions
- * will result in a warning, and may fail during server-side authorization.
- *
- *
- * @param newPermissionsRequest the new permissions request
- */
- public final void requestNewPublishPermissions(NewPermissionsRequest newPermissionsRequest) {
- requestNewPermissions(newPermissionsRequest, SessionAuthorizationType.PUBLISH);
- }
-
- /**
- * Provides an implementation for {@link Activity#onActivityResult
- * onActivityResult} that updates the Session based on information returned
- * during the authorization flow. The Activity that calls open or
- * requestNewPermissions should forward the resulting onActivityResult call here to
- * update the Session state based on the contents of the resultCode and
- * data.
- *
- * @param currentActivity The Activity that is forwarding the onActivityResult call.
- * @param requestCode The requestCode parameter from the forwarded call. When this
- * onActivityResult occurs as part of Facebook authorization
- * flow, this value is the activityCode passed to open or
- * authorize.
- * @param resultCode An int containing the resultCode parameter from the forwarded
- * call.
- * @param data The Intent passed as the data parameter from the forwarded
- * call.
- * @return A boolean indicating whether the requestCode matched a pending
- * authorization request for this Session.
- */
- public final boolean onActivityResult(Activity currentActivity, int requestCode, int resultCode, Intent data) {
- Validate.notNull(currentActivity, "currentActivity");
-
- initializeStaticContext(currentActivity);
-
- synchronized (lock) {
- if (pendingRequest == null || (requestCode != pendingRequest.getRequestCode())) {
- return false;
- }
- }
-
- AccessToken newToken = null;
- Exception exception = null;
-
- if (data != null) {
- AuthorizationClient.Result result = (AuthorizationClient.Result) data.getSerializableExtra(
- LoginActivity.RESULT_KEY);
- if (result != null) {
- // This came from LoginActivity.
- handleAuthorizationResult(resultCode, result);
- return true;
- } else if (authorizationClient != null) {
- // Delegate to the auth client.
- authorizationClient.onActivityResult(requestCode, resultCode, data);
- return true;
- }
- } else if (resultCode == Activity.RESULT_CANCELED) {
- exception = new FacebookOperationCanceledException("User canceled operation.");
- }
-
- finishAuthOrReauth(newToken, exception);
- return true;
- }
-
- /**
- * Closes the local in-memory Session object, but does not clear the
- * persisted token cache.
- */
- @SuppressWarnings("incomplete-switch")
- public final void close() {
- synchronized (this.lock) {
- final SessionState oldState = this.state;
-
- switch (this.state) {
- case CREATED:
- case OPENING:
- this.state = SessionState.CLOSED_LOGIN_FAILED;
- postStateChange(oldState, this.state, new FacebookException(
- "Log in attempt aborted."));
- break;
-
- case CREATED_TOKEN_LOADED:
- case OPENED:
- case OPENED_TOKEN_UPDATED:
- this.state = SessionState.CLOSED;
- postStateChange(oldState, this.state, null);
- break;
- }
- }
- }
-
- /**
- * Closes the local in-memory Session object and clears any persisted token
- * cache related to the Session.
- */
- public final void closeAndClearTokenInformation() {
- if (this.tokenCachingStrategy != null) {
- this.tokenCachingStrategy.clear();
- }
- Utility.clearFacebookCookies(staticContext);
- close();
- }
-
- /**
- * Adds a callback that will be called when the state of this Session changes.
- *
- * @param callback the callback
- */
- public final void addCallback(StatusCallback callback) {
- synchronized (callbacks) {
- if (callback != null && !callbacks.contains(callback)) {
- callbacks.add(callback);
- }
- }
- }
-
- /**
- * Removes a StatusCallback from this Session.
- *
- * @param callback the callback
- */
- public final void removeCallback(StatusCallback callback) {
- synchronized (callbacks) {
- callbacks.remove(callback);
- }
- }
-
- @Override
- public String toString() {
- return new StringBuilder().append("{Session").append(" state:").append(this.state).append(", token:")
- .append((this.tokenInfo == null) ? "null" : this.tokenInfo).append(", appId:")
- .append((this.applicationId == null) ? "null" : this.applicationId).append("}").toString();
- }
-
- void extendTokenCompleted(Bundle bundle) {
- synchronized (this.lock) {
- final SessionState oldState = this.state;
-
- switch (this.state) {
- case OPENED:
- this.state = SessionState.OPENED_TOKEN_UPDATED;
- postStateChange(oldState, this.state, null);
- break;
- case OPENED_TOKEN_UPDATED:
- break;
- default:
- // Silently ignore attempts to refresh token if we are not open
- Log.d(TAG, "refreshToken ignored in state " + this.state);
- return;
- }
- this.tokenInfo = AccessToken.createFromRefresh(this.tokenInfo, bundle);
- if (this.tokenCachingStrategy != null) {
- this.tokenCachingStrategy.save(this.tokenInfo.toCacheBundle());
- }
- }
- }
-
- private Object writeReplace() {
- return new SerializationProxyV1(applicationId, state, tokenInfo,
- lastAttemptedTokenExtendDate, false, pendingRequest);
- }
-
- // have a readObject that throws to prevent spoofing
- private void readObject(ObjectInputStream stream) throws InvalidObjectException {
- throw new InvalidObjectException("Cannot readObject, serialization proxy required");
- }
-
- /**
- * Save the Session object into the supplied Bundle.
- *
- * @param session the Session to save
- * @param bundle the Bundle to save the Session to
- */
- public static final void saveSession(Session session, Bundle bundle) {
- if (bundle != null && session != null && !bundle.containsKey(SESSION_BUNDLE_SAVE_KEY)) {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- try {
- new ObjectOutputStream(outputStream).writeObject(session);
- } catch (IOException e) {
- throw new FacebookException("Unable to save session.", e);
- }
- bundle.putByteArray(SESSION_BUNDLE_SAVE_KEY, outputStream.toByteArray());
- bundle.putBundle(AUTH_BUNDLE_SAVE_KEY, session.authorizationBundle);
- }
- }
-
- /**
- * Restores the saved session from a Bundle, if any. Returns the restored Session or
- * null if it could not be restored.
- *
- * @param context the Activity or Service creating the Session, must not be null
- * @param cachingStrategy the TokenCachingStrategy to use to load and store the token. If this is
- * null, a default token cachingStrategy that stores data in
- * SharedPreferences will be used
- * @param callback the callback to notify for Session state changes, can be null
- * @param bundle the bundle to restore the Session from
- * @return the restored Session, or null
- */
- public static final Session restoreSession(
- Context context, TokenCachingStrategy cachingStrategy, StatusCallback callback, Bundle bundle) {
- if (bundle == null) {
- return null;
- }
- byte[] data = bundle.getByteArray(SESSION_BUNDLE_SAVE_KEY);
- if (data != null) {
- ByteArrayInputStream is = new ByteArrayInputStream(data);
- try {
- Session session = (Session) (new ObjectInputStream(is)).readObject();
- initializeStaticContext(context);
- if (cachingStrategy != null) {
- session.tokenCachingStrategy = cachingStrategy;
- } else {
- session.tokenCachingStrategy = new SharedPreferencesTokenCachingStrategy(context);
- }
- if (callback != null) {
- session.addCallback(callback);
- }
- session.authorizationBundle = bundle.getBundle(AUTH_BUNDLE_SAVE_KEY);
- return session;
- } catch (ClassNotFoundException e) {
- Log.w(TAG, "Unable to restore session", e);
- } catch (IOException e) {
- Log.w(TAG, "Unable to restore session.", e);
- }
- }
- return null;
- }
-
-
- /**
- * Returns the current active Session, or null if there is none.
- *
- * @return the current active Session, or null if there is none.
- */
- public static final Session getActiveSession() {
- synchronized (Session.STATIC_LOCK) {
- return Session.activeSession;
- }
- }
-
- /**
- *
- * Sets the current active Session.
- *
- *
- * The active Session is used implicitly by predefined Request factory
- * methods as well as optionally by UI controls in the sdk.
- *
- *
- * It is legal to set this to null, or to a Session that is not yet open.
- *
- *
- * @param session A Session to use as the active Session, or null to indicate
- * that there is no active Session.
- */
- public static final void setActiveSession(Session session) {
- synchronized (Session.STATIC_LOCK) {
- if (session != Session.activeSession) {
- Session oldSession = Session.activeSession;
-
- if (oldSession != null) {
- oldSession.close();
- }
-
- Session.activeSession = session;
-
- if (oldSession != null) {
- postActiveSessionAction(Session.ACTION_ACTIVE_SESSION_UNSET);
- }
-
- if (session != null) {
- postActiveSessionAction(Session.ACTION_ACTIVE_SESSION_SET);
-
- if (session.isOpened()) {
- postActiveSessionAction(Session.ACTION_ACTIVE_SESSION_OPENED);
- }
- }
- }
- }
- }
-
- /**
- * Create a new Session, and if a token cache is available, open the
- * Session and make it active without any user interaction.
- *
- * @param context The Context creating this session
- * @return The new session or null if one could not be created
- */
- public static Session openActiveSessionFromCache(Context context) {
- return openActiveSession(context, false, null);
- }
-
- /**
- * If allowLoginUI is true, this will create a new Session, make it active, and
- * open it. If the default token cache is not available, then this will request
- * basic permissions. If the default token cache is available and cached tokens
- * are loaded, this will use the cached token and associated permissions.
- *
- * If allowedLoginUI is false, this will only create the active session and open
- * it if it requires no user interaction (i.e. the token cache is available and
- * there are cached tokens).
- *
- * @param activity The Activity that is opening the new Session.
- * @param allowLoginUI if false, only sets the active session and opens it if it
- * does not require user interaction
- * @param callback The {@link StatusCallback SessionStatusCallback} to
- * notify regarding Session state changes. May be null.
- * @return The new Session or null if one could not be created
- */
- public static Session openActiveSession(Activity activity, boolean allowLoginUI,
- StatusCallback callback) {
- return openActiveSession(activity, allowLoginUI, new OpenRequest(activity).setCallback(callback));
- }
-
- /**
- * If allowLoginUI is true, this will create a new Session, make it active, and
- * open it. If the default token cache is not available, then this will request
- * basic permissions. If the default token cache is available and cached tokens
- * are loaded, this will use the cached token and associated permissions.
- *
- * If allowedLoginUI is false, this will only create the active session and open
- * it if it requires no user interaction (i.e. the token cache is available and
- * there are cached tokens).
- *
- * @param context The Activity or Service creating this Session
- * @param fragment The Fragment that is opening the new Session.
- * @param allowLoginUI if false, only sets the active session and opens it if it
- * does not require user interaction
- * @param callback The {@link StatusCallback SessionStatusCallback} to
- * notify regarding Session state changes.
- * @return The new Session or null if one could not be created
- */
- public static Session openActiveSession(Context context, Fragment fragment,
- boolean allowLoginUI, StatusCallback callback) {
- return openActiveSession(context, allowLoginUI, new OpenRequest(fragment).setCallback(callback));
- }
-
- /**
- * Opens a session based on an existing Facebook access token, and also makes this session
- * the currently active session. This method should be used
- * only in instances where an application has previously obtained an access token and wishes
- * to import it into the Session/TokenCachingStrategy-based session-management system. A primary
- * example would be an application which previously did not use the Facebook SDK for Android
- * and implemented its own session-management scheme, but wishes to implement an upgrade path
- * for existing users so they do not need to log in again when upgrading to a version of
- * the app that uses the SDK. In general, this method will be called only once, when the app
- * detects that it has been upgraded -- after that, the usual Session lifecycle methods
- * should be used to manage the session and its associated token.
- *
- * No validation is done that the token, token source, or permissions are actually valid.
- * It is the caller's responsibility to ensure that these accurately reflect the state of
- * the token that has been passed in, or calls to the Facebook API may fail.
- *
- * @param context the Context to use for creation the session
- * @param accessToken the access token obtained from Facebook
- * @param callback a callback that will be called when the session status changes; may be null
- * @return The new Session or null if one could not be created
- */
- public static Session openActiveSessionWithAccessToken(Context context, AccessToken accessToken,
- StatusCallback callback) {
- Session session = new Session(context, null, null, false);
-
- setActiveSession(session);
- session.open(accessToken, callback);
-
- return session;
- }
-
- private static Session openActiveSession(Context context, boolean allowLoginUI, OpenRequest openRequest) {
- Session session = new Builder(context).build();
- if (SessionState.CREATED_TOKEN_LOADED.equals(session.getState()) || allowLoginUI) {
- setActiveSession(session);
- session.openForRead(openRequest);
- return session;
- }
- return null;
- }
-
- static Context getStaticContext() {
- return staticContext;
- }
-
- static void initializeStaticContext(Context currentContext) {
- if ((currentContext != null) && (staticContext == null)) {
- Context applicationContext = currentContext.getApplicationContext();
- staticContext = (applicationContext != null) ? applicationContext : currentContext;
- }
- }
-
- void authorize(AuthorizationRequest request) {
- boolean started = false;
-
- request.setApplicationId(applicationId);
-
- autoPublishAsync();
-
- started = tryLoginActivity(request);
-
- if (!started && request.isLegacy) {
- started = tryLegacyAuth(request);
- }
-
- if (!started) {
- synchronized (this.lock) {
- final SessionState oldState = this.state;
-
- switch (this.state) {
- case CLOSED:
- case CLOSED_LOGIN_FAILED:
- return;
-
- default:
- this.state = SessionState.CLOSED_LOGIN_FAILED;
- postStateChange(oldState, this.state, new FacebookException("Log in attempt failed."));
- }
- }
- }
- }
-
- private void open(OpenRequest openRequest, SessionAuthorizationType authType) {
- validatePermissions(openRequest, authType);
- validateLoginBehavior(openRequest);
-
- SessionState newState;
- synchronized (this.lock) {
- if (pendingRequest != null) {
- postStateChange(state, state, new UnsupportedOperationException(
- "Session: an attempt was made to open a session that has a pending request."));
- return;
- }
- final SessionState oldState = this.state;
-
- switch (this.state) {
- case CREATED:
- this.state = newState = SessionState.OPENING;
- if (openRequest == null) {
- throw new IllegalArgumentException("openRequest cannot be null when opening a new Session");
- }
- pendingRequest = openRequest;
- break;
- case CREATED_TOKEN_LOADED:
- if (openRequest != null && !Utility.isNullOrEmpty(openRequest.getPermissions())) {
- if (!Utility.isSubset(openRequest.getPermissions(), getPermissions())) {
- pendingRequest = openRequest;
- }
- }
- if (pendingRequest == null) {
- this.state = newState = SessionState.OPENED;
- } else {
- this.state = newState = SessionState.OPENING;
- }
- break;
- default:
- throw new UnsupportedOperationException(
- "Session: an attempt was made to open an already opened session.");
- }
- if (openRequest != null) {
- addCallback(openRequest.getCallback());
- }
- this.postStateChange(oldState, newState, null);
- }
-
- if (newState == SessionState.OPENING) {
- authorize(openRequest);
- }
- }
-
- private void requestNewPermissions(NewPermissionsRequest newPermissionsRequest, SessionAuthorizationType authType) {
- validatePermissions(newPermissionsRequest, authType);
- validateLoginBehavior(newPermissionsRequest);
-
- if (newPermissionsRequest != null) {
- synchronized (this.lock) {
- if (pendingRequest != null) {
- throw new UnsupportedOperationException(
- "Session: an attempt was made to request new permissions for a session that has a pending request.");
- }
- switch (this.state) {
- case OPENED:
- case OPENED_TOKEN_UPDATED:
- pendingRequest = newPermissionsRequest;
- break;
- default:
- throw new UnsupportedOperationException(
- "Session: an attempt was made to request new permissions for a session that is not currently open.");
- }
- }
-
- newPermissionsRequest.setValidateSameFbidAsToken(getAccessToken());
- authorize(newPermissionsRequest);
- }
- }
-
- private void validateLoginBehavior(AuthorizationRequest request) {
- if (request != null && !request.isLegacy) {
- Intent intent = new Intent();
- intent.setClass(getStaticContext(), LoginActivity.class);
- if (!resolveIntent(intent)) {
- throw new FacebookException(String.format(
- "Cannot use SessionLoginBehavior %s when %s is not declared as an activity in AndroidManifest.xml",
- request.getLoginBehavior(), LoginActivity.class.getName()));
- }
- }
- }
-
- private void validatePermissions(AuthorizationRequest request, SessionAuthorizationType authType) {
- if (request == null || Utility.isNullOrEmpty(request.getPermissions())) {
- if (SessionAuthorizationType.PUBLISH.equals(authType)) {
- throw new FacebookException("Cannot request publish or manage authorization with no permissions.");
- }
- return; // nothing to check
- }
- for (String permission : request.getPermissions()) {
- if (isPublishPermission(permission)) {
- if (SessionAuthorizationType.READ.equals(authType)) {
- throw new FacebookException(
- String.format(
- "Cannot pass a publish or manage permission (%s) to a request for read authorization",
- permission));
- }
- } else {
- if (SessionAuthorizationType.PUBLISH.equals(authType)) {
- Log.w(TAG,
- String.format(
- "Should not pass a read permission (%s) to a request for publish or manage authorization",
- permission));
- }
- }
- }
- }
-
- static boolean isPublishPermission(String permission) {
- return permission != null &&
- (permission.startsWith(PUBLISH_PERMISSION_PREFIX) ||
- permission.startsWith(MANAGE_PERMISSION_PREFIX) ||
- OTHER_PUBLISH_PERMISSIONS.contains(permission));
-
- }
-
- private void handleAuthorizationResult(int resultCode, AuthorizationClient.Result result) {
- AccessToken newToken = null;
- Exception exception = null;
- if (resultCode == Activity.RESULT_OK) {
- if (result.code == AuthorizationClient.Result.Code.SUCCESS) {
- newToken = result.token;
- } else {
- exception = new FacebookAuthorizationException(result.errorMessage);
- }
- } else if (resultCode == Activity.RESULT_CANCELED) {
- exception = new FacebookOperationCanceledException(result.errorMessage);
- }
-
- authorizationClient = null;
- finishAuthOrReauth(newToken, exception);
- }
-
- private boolean tryLoginActivity(AuthorizationRequest request) {
- Intent intent = getLoginActivityIntent(request);
-
- if (!resolveIntent(intent)) {
- return false;
- }
-
- try {
- request.getStartActivityDelegate().startActivityForResult(intent, request.getRequestCode());
- } catch (ActivityNotFoundException e) {
- return false;
- }
-
- return true;
- }
-
- private boolean resolveIntent(Intent intent) {
- ResolveInfo resolveInfo = getStaticContext().getPackageManager().resolveActivity(intent, 0);
- if (resolveInfo == null) {
- return false;
- }
- return true;
- }
-
- private Intent getLoginActivityIntent(AuthorizationRequest request) {
- Intent intent = new Intent();
- intent.setClass(getStaticContext(), LoginActivity.class);
- intent.setAction(request.getLoginBehavior().toString());
-
- // Let LoginActivity populate extras appropriately
- AuthorizationClient.AuthorizationRequest authClientRequest = request.getAuthorizationClientRequest();
- Bundle extras = LoginActivity.populateIntentExtras(authClientRequest);
- intent.putExtras(extras);
-
- return intent;
- }
-
- private boolean tryLegacyAuth(final AuthorizationRequest request) {
- authorizationClient = new AuthorizationClient();
- authorizationClient.setOnCompletedListener(new AuthorizationClient.OnCompletedListener() {
- @Override
- public void onCompleted(AuthorizationClient.Result result) {
- handleAuthorizationResult(Activity.RESULT_OK, result);
- }
- });
- authorizationClient.setContext(getStaticContext());
- authorizationClient.startOrContinueAuth(request.getAuthorizationClientRequest());
-
- return true;
- }
-
- @SuppressWarnings("incomplete-switch")
- void finishAuthOrReauth(AccessToken newToken, Exception exception) {
- // If the token we came up with is expired/invalid, then auth failed.
- if ((newToken != null) && newToken.isInvalid()) {
- newToken = null;
- exception = new FacebookException("Invalid access token.");
- }
-
- synchronized (this.lock) {
- switch (this.state) {
- case OPENING:
- // This means we are authorizing for the first time in this Session.
- finishAuthorization(newToken, exception);
- break;
-
- case OPENED:
- case OPENED_TOKEN_UPDATED:
- // This means we are reauthorizing.
- finishReauthorization(newToken, exception);
-
- break;
- }
- }
- }
-
- private void finishAuthorization(AccessToken newToken, Exception exception) {
- final SessionState oldState = state;
- if (newToken != null) {
- tokenInfo = newToken;
- saveTokenToCache(newToken);
-
- state = SessionState.OPENED;
- } else if (exception != null) {
- state = SessionState.CLOSED_LOGIN_FAILED;
- }
- pendingRequest = null;
- postStateChange(oldState, state, exception);
- }
-
- private void finishReauthorization(final AccessToken newToken, Exception exception) {
- final SessionState oldState = state;
-
- if (newToken != null) {
- tokenInfo = newToken;
- saveTokenToCache(newToken);
-
- state = SessionState.OPENED_TOKEN_UPDATED;
- }
-
- pendingRequest = null;
- postStateChange(oldState, state, exception);
- }
-
- private void saveTokenToCache(AccessToken newToken) {
- if (newToken != null && tokenCachingStrategy != null) {
- tokenCachingStrategy.save(newToken.toCacheBundle());
- }
- }
-
- void postStateChange(final SessionState oldState, final SessionState newState, final Exception exception) {
- if (oldState == newState && exception == null) {
- return;
- }
-
- if (newState.isClosed()) {
- this.tokenInfo = AccessToken.createEmptyToken(Collections.emptyList());
- }
-
- synchronized (callbacks) {
- // Need to schedule the callbacks inside the same queue to preserve ordering.
- // Otherwise these callbacks could have been added to the queue before the SessionTracker
- // gets the ACTIVE_SESSION_SET action.
- Runnable runCallbacks = new Runnable() {
- @Override
- public void run() {
- for (final StatusCallback callback : callbacks) {
- Runnable closure = new Runnable() {
- @Override
- public void run() {
- // This can be called inside a synchronized block.
- callback.call(Session.this, newState, exception);
- }
- };
-
- runWithHandlerOrExecutor(handler, closure);
- }
- }
- };
- runWithHandlerOrExecutor(handler, runCallbacks);
- }
-
- if (this == Session.activeSession) {
- if (oldState.isOpened() != newState.isOpened()) {
- if (newState.isOpened()) {
- postActiveSessionAction(Session.ACTION_ACTIVE_SESSION_OPENED);
- } else {
- postActiveSessionAction(Session.ACTION_ACTIVE_SESSION_CLOSED);
- }
- }
- }
- }
-
- static void postActiveSessionAction(String action) {
- final Intent intent = new Intent(action);
-
- LocalBroadcastManager.getInstance(getStaticContext()).sendBroadcast(intent);
- }
-
- private static void runWithHandlerOrExecutor(Handler handler, Runnable runnable) {
- if (handler != null) {
- handler.post(runnable);
- } else {
- Settings.getExecutor().execute(runnable);
- }
- }
-
- void extendAccessTokenIfNeeded() {
- if (shouldExtendAccessToken()) {
- extendAccessToken();
- }
- }
-
- void extendAccessToken() {
- TokenRefreshRequest newTokenRefreshRequest = null;
- synchronized (this.lock) {
- if (currentTokenRefreshRequest == null) {
- newTokenRefreshRequest = new TokenRefreshRequest();
- currentTokenRefreshRequest = newTokenRefreshRequest;
- }
- }
-
- if (newTokenRefreshRequest != null) {
- newTokenRefreshRequest.bind();
- }
- }
-
- boolean shouldExtendAccessToken() {
- if (currentTokenRefreshRequest != null) {
- return false;
- }
-
- boolean result = false;
-
- Date now = new Date();
-
- if (state.isOpened() && tokenInfo.getSource().canExtendToken()
- && now.getTime() - lastAttemptedTokenExtendDate.getTime() > TOKEN_EXTEND_RETRY_SECONDS * 1000
- && now.getTime() - tokenInfo.getLastRefresh().getTime() > TOKEN_EXTEND_THRESHOLD_SECONDS * 1000) {
- result = true;
- }
-
- return result;
- }
-
- AccessToken getTokenInfo() {
- return tokenInfo;
- }
-
- void setTokenInfo(AccessToken tokenInfo) {
- this.tokenInfo = tokenInfo;
- }
-
- Date getLastAttemptedTokenExtendDate() {
- return lastAttemptedTokenExtendDate;
- }
-
- void setLastAttemptedTokenExtendDate(Date lastAttemptedTokenExtendDate) {
- this.lastAttemptedTokenExtendDate = lastAttemptedTokenExtendDate;
- }
-
- void setCurrentTokenRefreshRequest(TokenRefreshRequest request) {
- this.currentTokenRefreshRequest = request;
- }
-
- class TokenRefreshRequest implements ServiceConnection {
-
- final Messenger messageReceiver = new Messenger(
- new TokenRefreshRequestHandler(Session.this, this));
-
- Messenger messageSender = null;
-
- public void bind() {
- Intent intent = NativeProtocol.createTokenRefreshIntent(getStaticContext());
- if (intent != null
- && staticContext.bindService(intent, new TokenRefreshRequest(), Context.BIND_AUTO_CREATE)) {
- setLastAttemptedTokenExtendDate(new Date());
- } else {
- cleanup();
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- messageSender = new Messenger(service);
- refreshToken();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName arg) {
- cleanup();
-
- // We returned an error so there's no point in
- // keeping the binding open.
- staticContext.unbindService(TokenRefreshRequest.this);
- }
-
- private void cleanup() {
- if (currentTokenRefreshRequest == this) {
- currentTokenRefreshRequest = null;
- }
- }
-
- private void refreshToken() {
- Bundle requestData = new Bundle();
- requestData.putString(AccessToken.ACCESS_TOKEN_KEY, getTokenInfo().getToken());
-
- Message request = Message.obtain();
- request.setData(requestData);
- request.replyTo = messageReceiver;
-
- try {
- messageSender.send(request);
- } catch (RemoteException e) {
- cleanup();
- }
- }
-
- }
-
- // Creating a static Handler class to reduce the possibility of a memory leak.
- // Handler objects for the same thread all share a common Looper object, which they post messages
- // to and read from. As messages contain target Handler, as long as there are messages with target
- // handler in the message queue, the handler cannot be garbage collected. If handler is not static,
- // the instance of the containing class also cannot be garbage collected even if it is destroyed.
- static class TokenRefreshRequestHandler extends Handler {
-
- private WeakReference sessionWeakReference;
- private WeakReference refreshRequestWeakReference;
-
- TokenRefreshRequestHandler(Session session, TokenRefreshRequest refreshRequest) {
- super(Looper.getMainLooper());
- sessionWeakReference = new WeakReference(session);
- refreshRequestWeakReference = new WeakReference(refreshRequest);
- }
-
- @Override
- public void handleMessage(Message msg) {
- String token = msg.getData().getString(AccessToken.ACCESS_TOKEN_KEY);
- Session session = sessionWeakReference.get();
-
- if (session != null && token != null) {
- session.extendTokenCompleted(msg.getData());
- }
-
- TokenRefreshRequest request = refreshRequestWeakReference.get();
- if (request != null) {
- // The refreshToken function should be called rarely,
- // so there is no point in keeping the binding open.
- staticContext.unbindService(request);
- request.cleanup();
- }
- }
- }
-
- /**
- * Provides asynchronous notification of Session state changes.
- *
- * @see Session#open open
- */
- public interface StatusCallback {
- public void call(Session session, SessionState state, Exception exception);
- }
-
- @Override
- public int hashCode() {
- return 0;
- }
-
- @Override
- public boolean equals(Object otherObj) {
- if (!(otherObj instanceof Session)) {
- return false;
- }
- Session other = (Session) otherObj;
-
- return areEqual(other.applicationId, applicationId) &&
- areEqual(other.authorizationBundle, authorizationBundle) &&
- areEqual(other.state, state) &&
- areEqual(other.getExpirationDate(), getExpirationDate());
- }
-
- private static boolean areEqual(Object a, Object b) {
- if (a == null) {
- return b == null;
- } else {
- return a.equals(b);
- }
- }
-
- /**
- * Builder class used to create a Session.
- */
- public static final class Builder {
- private final Context context;
- private String applicationId;
- private TokenCachingStrategy tokenCachingStrategy;
-
- /**
- * Constructs a new Builder associated with the context.
- *
- * @param context the Activity or Service starting the Session
- */
- public Builder(Context context) {
- this.context = context;
- }
-
- /**
- * Sets the application id for the Session.
- *
- * @param applicationId the application id
- * @return the Builder instance
- */
- public Builder setApplicationId(final String applicationId) {
- this.applicationId = applicationId;
- return this;
- }
-
- /**
- * Sets the TokenCachingStrategy for the Session.
- *
- * @param tokenCachingStrategy the token cache to use
- * @return the Builder instance
- */
- public Builder setTokenCachingStrategy(final TokenCachingStrategy tokenCachingStrategy) {
- this.tokenCachingStrategy = tokenCachingStrategy;
- return this;
- }
-
- /**
- * Build the Session.
- *
- * @return a new Session
- */
- public Session build() {
- return new Session(context, applicationId, tokenCachingStrategy);
- }
- }
-
- interface StartActivityDelegate {
- public void startActivityForResult(Intent intent, int requestCode);
-
- public Activity getActivityContext();
- }
-
- private void autoPublishAsync() {
- AutoPublishAsyncTask asyncTask = null;
- synchronized (this) {
- if (autoPublishAsyncTask == null && Settings.getShouldAutoPublishInstall()) {
- // copy the application id to guarantee thread safety against our container.
- String applicationId = Session.this.applicationId;
-
- // skip publish if we don't have an application id.
- if (applicationId != null) {
- asyncTask = autoPublishAsyncTask = new AutoPublishAsyncTask(applicationId, staticContext);
- }
- }
- }
-
- if (asyncTask != null) {
- asyncTask.execute();
- }
- }
-
- /**
- * Async implementation to allow auto publishing to not block the ui thread.
- */
- private class AutoPublishAsyncTask extends AsyncTask {
- private final String mApplicationId;
- private final Context mApplicationContext;
-
- public AutoPublishAsyncTask(String applicationId, Context context) {
- mApplicationId = applicationId;
- mApplicationContext = context.getApplicationContext();
- }
-
- @Override
- protected Void doInBackground(Void... voids) {
- try {
- Settings.publishInstallAndWait(mApplicationContext, mApplicationId);
- } catch (Exception e) {
- Utility.logd("Facebook-publish", e.getMessage());
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- // always clear out the publisher to allow other invocations.
- synchronized (Session.this) {
- autoPublishAsyncTask = null;
- }
- }
- }
-
- /**
- * Base class for authorization requests {@link OpenRequest} and {@link NewPermissionsRequest}.
- */
- public static class AuthorizationRequest implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- private final StartActivityDelegate startActivityDelegate;
- private SessionLoginBehavior loginBehavior = SessionLoginBehavior.SSO_WITH_FALLBACK;
- private int requestCode = DEFAULT_AUTHORIZE_ACTIVITY_CODE;
- private StatusCallback statusCallback;
- private boolean isLegacy = false;
- private List permissions = Collections.emptyList();
- private SessionDefaultAudience defaultAudience = SessionDefaultAudience.FRIENDS;
- private String applicationId;
- private String validateSameFbidAsToken;
-
- AuthorizationRequest(final Activity activity) {
- startActivityDelegate = new StartActivityDelegate() {
- @Override
- public void startActivityForResult(Intent intent, int requestCode) {
- activity.startActivityForResult(intent, requestCode);
- }
-
- @Override
- public Activity getActivityContext() {
- return activity;
- }
- };
- }
-
- AuthorizationRequest(final Fragment fragment) {
- startActivityDelegate = new StartActivityDelegate() {
- @Override
- public void startActivityForResult(Intent intent, int requestCode) {
- fragment.startActivityForResult(intent, requestCode);
- }
-
- @Override
- public Activity getActivityContext() {
- return fragment.getActivity();
- }
- };
- }
-
- /**
- * Constructor to be used for V1 serialization only, DO NOT CHANGE.
- */
- private AuthorizationRequest(SessionLoginBehavior loginBehavior, int requestCode,
- List permissions, String defaultAudience, boolean isLegacy, String applicationId,
- String validateSameFbidAsToken) {
- startActivityDelegate = new StartActivityDelegate() {
- @Override
- public void startActivityForResult(Intent intent, int requestCode) {
- throw new UnsupportedOperationException(
- "Cannot create an AuthorizationRequest without a valid Activity or Fragment");
- }
-
- @Override
- public Activity getActivityContext() {
- throw new UnsupportedOperationException(
- "Cannot create an AuthorizationRequest without a valid Activity or Fragment");
- }
- };
- this.loginBehavior = loginBehavior;
- this.requestCode = requestCode;
- this.permissions = permissions;
- this.defaultAudience = SessionDefaultAudience.valueOf(defaultAudience);
- this.isLegacy = isLegacy;
- this.applicationId = applicationId;
- this.validateSameFbidAsToken = validateSameFbidAsToken;
- }
-
- /**
- * Used for backwards compatibility with Facebook.java only, DO NOT USE.
- *
- * @param isLegacy
- */
- public void setIsLegacy(boolean isLegacy) {
- this.isLegacy = isLegacy;
- }
-
- boolean isLegacy() {
- return isLegacy;
- }
-
- AuthorizationRequest setCallback(StatusCallback statusCallback) {
- this.statusCallback = statusCallback;
- return this;
- }
-
- StatusCallback getCallback() {
- return statusCallback;
- }
-
- AuthorizationRequest setLoginBehavior(SessionLoginBehavior loginBehavior) {
- if (loginBehavior != null) {
- this.loginBehavior = loginBehavior;
- }
- return this;
- }
-
- SessionLoginBehavior getLoginBehavior() {
- return loginBehavior;
- }
-
- AuthorizationRequest setRequestCode(int requestCode) {
- if (requestCode >= 0) {
- this.requestCode = requestCode;
- }
- return this;
- }
-
- int getRequestCode() {
- return requestCode;
- }
-
- AuthorizationRequest setPermissions(List permissions) {
- if (permissions != null) {
- this.permissions = permissions;
- }
- return this;
- }
-
- List getPermissions() {
- return permissions;
- }
-
- AuthorizationRequest setDefaultAudience(SessionDefaultAudience defaultAudience) {
- if (defaultAudience != null) {
- this.defaultAudience = defaultAudience;
- }
- return this;
- }
-
- SessionDefaultAudience getDefaultAudience() {
- return defaultAudience;
- }
-
- StartActivityDelegate getStartActivityDelegate() {
- return startActivityDelegate;
- }
-
- String getApplicationId() {
- return applicationId;
- }
-
- void setApplicationId(String applicationId) {
- this.applicationId = applicationId;
- }
-
- String getValidateSameFbidAsToken() {
- return validateSameFbidAsToken;
- }
-
- void setValidateSameFbidAsToken(String validateSameFbidAsToken) {
- this.validateSameFbidAsToken = validateSameFbidAsToken;
- }
-
- AuthorizationClient.AuthorizationRequest getAuthorizationClientRequest() {
- AuthorizationClient.StartActivityDelegate delegate = new AuthorizationClient.StartActivityDelegate() {
- @Override
- public void startActivityForResult(Intent intent, int requestCode) {
- startActivityDelegate.startActivityForResult(intent, requestCode);
- }
-
- @Override
- public Activity getActivityContext() {
- return startActivityDelegate.getActivityContext();
- }
- };
- return new AuthorizationClient.AuthorizationRequest(loginBehavior, requestCode, isLegacy,
- permissions, defaultAudience, applicationId, validateSameFbidAsToken, delegate);
- }
-
- // package private so subclasses can use it
- Object writeReplace() {
- return new AuthRequestSerializationProxyV1(
- loginBehavior, requestCode, permissions, defaultAudience.name(), isLegacy, applicationId, validateSameFbidAsToken);
- }
-
- // have a readObject that throws to prevent spoofing
- // package private so subclasses can use it
- void readObject(ObjectInputStream stream) throws InvalidObjectException {
- throw new InvalidObjectException("Cannot readObject, serialization proxy required");
- }
-
- private static class AuthRequestSerializationProxyV1 implements Serializable {
- private static final long serialVersionUID = -8748347685113614927L;
- private final SessionLoginBehavior loginBehavior;
- private final int requestCode;
- private boolean isLegacy;
- private final List permissions;
- private final String defaultAudience;
- private final String applicationId;
- private final String validateSameFbidAsToken;
-
- private AuthRequestSerializationProxyV1(SessionLoginBehavior loginBehavior,
- int requestCode, List permissions, String defaultAudience, boolean isLegacy,
- String applicationId, String validateSameFbidAsToken) {
- this.loginBehavior = loginBehavior;
- this.requestCode = requestCode;
- this.permissions = permissions;
- this.defaultAudience = defaultAudience;
- this.isLegacy = isLegacy;
- this.applicationId = applicationId;
- this.validateSameFbidAsToken = validateSameFbidAsToken;
- }
-
- private Object readResolve() {
- return new AuthorizationRequest(loginBehavior, requestCode, permissions, defaultAudience, isLegacy,
- applicationId, validateSameFbidAsToken);
- }
- }
- }
-
- /**
- * A request used to open a Session.
- */
- public static final class OpenRequest extends AuthorizationRequest {
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructs an OpenRequest.
- *
- * @param activity the Activity to use to open the Session
- */
- public OpenRequest(Activity activity) {
- super(activity);
- }
-
- /**
- * Constructs an OpenRequest.
- *
- * @param fragment the Fragment to use to open the Session
- */
- public OpenRequest(Fragment fragment) {
- super(fragment);
- }
-
- /**
- * Sets the StatusCallback for the OpenRequest.
- *
- * @param statusCallback The {@link StatusCallback SessionStatusCallback} to
- * notify regarding Session state changes.
- * @return the OpenRequest object to allow for chaining
- */
- @Override
- public final OpenRequest setCallback(StatusCallback statusCallback) {
- super.setCallback(statusCallback);
- return this;
- }
-
- /**
- * Sets the login behavior for the OpenRequest.
- *
- * @param loginBehavior The {@link SessionLoginBehavior SessionLoginBehavior} that
- * specifies what behaviors should be attempted during
- * authorization.
- * @return the OpenRequest object to allow for chaining
- */
- @Override
- public final OpenRequest setLoginBehavior(SessionLoginBehavior loginBehavior) {
- super.setLoginBehavior(loginBehavior);
- return this;
- }
-
- /**
- * Sets the request code for the OpenRequest.
- *
- * @param requestCode An integer that identifies this request. This integer will be used
- * as the request code in {@link Activity#onActivityResult
- * onActivityResult}. This integer should be >= 0. If a value < 0 is
- * passed in, then a default value will be used.
- * @return the OpenRequest object to allow for chaining
- */
- @Override
- public final OpenRequest setRequestCode(int requestCode) {
- super.setRequestCode(requestCode);
- return this;
- }
-
- /**
- * Sets the permissions for the OpenRequest.
- *
- * @param permissions A List<String> representing the permissions to request
- * during the authentication flow. A null or empty List
- * represents basic permissions.
- * @return the OpenRequest object to allow for chaining
- */
- @Override
- public final OpenRequest setPermissions(List permissions) {
- super.setPermissions(permissions);
- return this;
- }
-
- /**
- * Sets the defaultAudience for the OpenRequest.
- *
- * This is only used during Native login using a sufficiently recent facebook app.
- *
- * @param defaultAudience A SessionDefaultAudience representing the default audience setting to request.
- * @return the OpenRequest object to allow for chaining
- */
- @Override
- public final OpenRequest setDefaultAudience(SessionDefaultAudience defaultAudience) {
- super.setDefaultAudience(defaultAudience);
- return this;
- }
- }
-
- /**
- * A request to be used to request new permissions for a Session.
- */
- public static final class NewPermissionsRequest extends AuthorizationRequest {
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructs a NewPermissionsRequest.
- *
- * @param activity the Activity used to issue the request
- * @param permissions additional permissions to request
- */
- public NewPermissionsRequest(Activity activity, List permissions) {
- super(activity);
- setPermissions(permissions);
- }
-
- /**
- * Constructs a NewPermissionsRequest.
- *
- * @param fragment the Fragment used to issue the request
- * @param permissions additional permissions to request
- */
- public NewPermissionsRequest(Fragment fragment, List permissions) {
- super(fragment);
- setPermissions(permissions);
- }
-
- /**
- * Sets the StatusCallback for the NewPermissionsRequest.
- *
- * @param statusCallback The {@link StatusCallback SessionStatusCallback} to
- * notify regarding Session state changes.
- * @return the NewPermissionsRequest object to allow for chaining
- */
- @Override
- public final NewPermissionsRequest setCallback(StatusCallback statusCallback) {
- super.setCallback(statusCallback);
- return this;
- }
-
- /**
- * Sets the login behavior for the NewPermissionsRequest.
- *
- * @param loginBehavior The {@link SessionLoginBehavior SessionLoginBehavior} that
- * specifies what behaviors should be attempted during
- * authorization.
- * @return the NewPermissionsRequest object to allow for chaining
- */
- @Override
- public final NewPermissionsRequest setLoginBehavior(SessionLoginBehavior loginBehavior) {
- super.setLoginBehavior(loginBehavior);
- return this;
- }
-
- /**
- * Sets the request code for the NewPermissionsRequest.
- *
- * @param requestCode An integer that identifies this request. This integer will be used
- * as the request code in {@link Activity#onActivityResult
- * onActivityResult}. This integer should be >= 0. If a value < 0 is
- * passed in, then a default value will be used.
- * @return the NewPermissionsRequest object to allow for chaining
- */
- @Override
- public final NewPermissionsRequest setRequestCode(int requestCode) {
- super.setRequestCode(requestCode);
- return this;
- }
-
- /**
- * Sets the defaultAudience for the OpenRequest.
- *
- * @param defaultAudience A SessionDefaultAudience representing the default audience setting to request.
- * @return the NewPermissionsRequest object to allow for chaining
- */
- @Override
- public final NewPermissionsRequest setDefaultAudience(SessionDefaultAudience defaultAudience) {
- super.setDefaultAudience(defaultAudience);
- return this;
- }
- }
-}
diff --git a/facebook/facebook/src/com/facebook/SessionDefaultAudience.java b/facebook/facebook/src/com/facebook/SessionDefaultAudience.java
deleted file mode 100644
index eaac2b369..000000000
--- a/facebook/facebook/src/com/facebook/SessionDefaultAudience.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-/**
- * Certain operations such as publishing a status or publishing a photo require an audience. When the user
- * grants an application permission to perform a publish operation, a default audience is selected as the
- * publication ceiling for the application. This enumerated value allows the application to select which
- * audience to ask the user to grant publish permission for.
- */
-public enum SessionDefaultAudience {
- /**
- * Represents an invalid default audience value, can be used when only reading.
- */
- NONE(null),
-
- /**
- * Indicates only the user is able to see posts made by the application.
- */
- ONLY_ME(NativeProtocol.AUDIENCE_ME),
-
- /**
- * Indicates that the user's friends are able to see posts made by the application.
- */
- FRIENDS(NativeProtocol.AUDIENCE_FRIENDS),
-
- /**
- * Indicates that all Facebook users are able to see posts made by the application.
- */
- EVERYONE(NativeProtocol.AUDIENCE_EVERYONE);
-
- private final String nativeProtocolAudience;
-
- private SessionDefaultAudience(String protocol) {
- nativeProtocolAudience = protocol;
- }
-
- String getNativeProtocolAudience() {
- return nativeProtocolAudience;
- }
-}
diff --git a/facebook/facebook/src/com/facebook/SessionLoginBehavior.java b/facebook/facebook/src/com/facebook/SessionLoginBehavior.java
deleted file mode 100644
index cc300dbd2..000000000
--- a/facebook/facebook/src/com/facebook/SessionLoginBehavior.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-/**
- * Specifies the behaviors to try during
- * {@link Session#openForRead(com.facebook.Session.OpenRequest) openForRead},
- * {@link Session#openForPublish(com.facebook.Session.OpenRequest) openForPublish},
- * {@link Session#requestNewReadPermissions(com.facebook.Session.NewPermissionsRequest) requestNewReadPermissions}, or
- * {@link Session#requestNewPublishPermissions(com.facebook.Session.NewPermissionsRequest) requestNewPublishPermissions}.
- */
-public enum SessionLoginBehavior {
- /**
- * Specifies that Session should attempt Single Sign On (SSO), and if that
- * does not work fall back to dialog auth. This is the default behavior.
- */
- SSO_WITH_FALLBACK(true, true),
-
- /**
- * Specifies that Session should only attempt SSO. If SSO fails, then the
- * open or new permissions call fails.
- */
- SSO_ONLY(true, false),
-
- /**
- * Specifies that SSO should not be attempted, and to only use dialog auth.
- */
- SUPPRESS_SSO(false, true);
-
- private final boolean allowsKatanaAuth;
- private final boolean allowsWebViewAuth;
-
- private SessionLoginBehavior(boolean allowsKatanaAuth, boolean allowsWebViewAuth) {
- this.allowsKatanaAuth = allowsKatanaAuth;
- this.allowsWebViewAuth = allowsWebViewAuth;
- }
-
- boolean allowsKatanaAuth() {
- return allowsKatanaAuth;
- }
-
- boolean allowsWebViewAuth() {
- return allowsWebViewAuth;
- }
-}
diff --git a/facebook/facebook/src/com/facebook/SessionState.java b/facebook/facebook/src/com/facebook/SessionState.java
deleted file mode 100644
index 45250624f..000000000
--- a/facebook/facebook/src/com/facebook/SessionState.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-/**
- *
- * Identifies the state of a Session.
- *
- *
- * Session objects implement a state machine that controls their lifecycle. This
- * enum represents the states of the state machine.
- *
- */
-public enum SessionState {
- /**
- * Indicates that the Session has not yet been opened and has no cached
- * token. Opening a Session in this state will involve user interaction.
- */
- CREATED(Category.CREATED_CATEGORY),
-
- /**
- *
- * Indicates that the Session has not yet been opened and has a cached
- * token. Opening a Session in this state will not involve user interaction.
- *
- *
- * If you are using Session from an Android Service, you must provide a
- * TokenCachingStrategy implementation that contains a valid token to the Session
- * constructor. The resulting Session will be created in this state, and you
- * can then safely call open, passing null for the Activity.
- *
- */
- CREATED_TOKEN_LOADED(Category.CREATED_CATEGORY),
-
- /**
- * Indicates that the Session is in the process of opening.
- */
- OPENING(Category.CREATED_CATEGORY),
-
- /**
- * Indicates that the Session is opened. In this state, the Session may be
- * used with a {@link Request}.
- */
- OPENED(Category.OPENED_CATEGORY),
-
- /**
- *
- * Indicates that the Session is opened and that the token has changed. In
- * this state, the Session may be used with {@link Request}.
- *
- *
- * Every time the token is updated, {@link Session.StatusCallback
- * StatusCallback} is called with this value.
- *
- */
- OPENED_TOKEN_UPDATED(Category.OPENED_CATEGORY),
-
- /**
- * Indicates that the Session is closed, and that it was not closed
- * normally. Typically this means that the open call failed, and the
- * Exception parameter to {@link Session.StatusCallback StatusCallback} will
- * be non-null.
- */
- CLOSED_LOGIN_FAILED(Category.CLOSED_CATEGORY),
-
- /**
- * Indicates that the Session was closed normally.
- */
- CLOSED(Category.CLOSED_CATEGORY);
-
- private final Category category;
-
- SessionState(Category category) {
- this.category = category;
- }
-
- /**
- * Returns a boolean indicating whether the state represents a successfully
- * opened state in which the Session can be used with a {@link Request}.
- *
- * @return a boolean indicating whether the state represents a successfully
- * opened state in which the Session can be used with a
- * {@link Request}.
- */
- public boolean isOpened() {
- return this.category == Category.OPENED_CATEGORY;
- }
-
- /**
- * Returns a boolean indicating whether the state represents a closed
- * Session that can no longer be used with a {@link Request}.
- *
- * @return a boolean indicating whether the state represents a closed
- * Session that can no longer be used with a {@link Request}.
- */
- public boolean isClosed() {
- return this.category == Category.CLOSED_CATEGORY;
- }
-
- private enum Category {
- CREATED_CATEGORY, OPENED_CATEGORY, CLOSED_CATEGORY
- }
-}
diff --git a/facebook/facebook/src/com/facebook/Settings.java b/facebook/facebook/src/com/facebook/Settings.java
deleted file mode 100644
index 8267cfffb..000000000
--- a/facebook/facebook/src/com/facebook/Settings.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import com.facebook.android.BuildConfig;
-import com.facebook.internal.Utility;
-import com.facebook.model.GraphObject;
-import com.facebook.internal.Validate;
-import org.json.JSONException;
-
-import java.lang.reflect.Field;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Allows some customization of sdk behavior.
- */
-public final class Settings {
- private static final HashSet loggingBehaviors = new HashSet();
- private static volatile Executor executor;
- private static volatile boolean shouldAutoPublishInstall;
-
- private static final int DEFAULT_CORE_POOL_SIZE = 5;
- private static final int DEFAULT_MAXIMUM_POOL_SIZE = 128;
- private static final int DEFAULT_KEEP_ALIVE = 1;
- private static final Object LOCK = new Object();
-
- private static final Uri ATTRIBUTION_ID_CONTENT_URI =
- Uri.parse("content://com.facebook.katana.provider.AttributionIdProvider");
- private static final String ATTRIBUTION_ID_COLUMN_NAME = "aid";
-
- private static final String ATTRIBUTION_PREFERENCES = "com.facebook.sdk.attributionTracking";
- private static final String PUBLISH_ACTIVITY_PATH = "%s/activities";
- private static final String MOBILE_INSTALL_EVENT = "MOBILE_APP_INSTALL";
- private static final String SUPPORTS_ATTRIBUTION = "supports_attribution";
- private static final String APPLICATION_FIELDS = "fields";
- private static final String ANALYTICS_EVENT = "event";
- private static final String ATTRIBUTION_KEY = "attribution";
-
- private static final BlockingQueue DEFAULT_WORK_QUEUE = new LinkedBlockingQueue(10);
-
- private static final ThreadFactory DEFAULT_THREAD_FACTORY = new ThreadFactory() {
- private final AtomicInteger counter = new AtomicInteger(0);
-
- @Override
- public Thread newThread(Runnable runnable) {
- return new Thread(runnable, "FacebookSdk #" + counter.incrementAndGet());
- }
- };
-
-
- /**
- * Certain logging behaviors are available for debugging beyond those that should be
- * enabled in production.
- *
- * Returns the types of extended logging that are currently enabled.
- *
- * @return a set containing enabled logging behaviors
- */
- public static final Set getLoggingBehaviors() {
- synchronized (loggingBehaviors) {
- return Collections.unmodifiableSet(new HashSet(loggingBehaviors));
- }
- }
-
- /**
- * Certain logging behaviors are available for debugging beyond those that should be
- * enabled in production.
- *
- * Enables a particular extended logging in the sdk.
- *
- * @param behavior
- * The LoggingBehavior to enable
- */
- public static final void addLoggingBehavior(LoggingBehavior behavior) {
- synchronized (loggingBehaviors) {
- loggingBehaviors.add(behavior);
- }
- }
-
- /**
- * Certain logging behaviors are available for debugging beyond those that should be
- * enabled in production.
- *
- * Disables a particular extended logging behavior in the sdk.
- *
- * @param behavior
- * The LoggingBehavior to disable
- */
- public static final void removeLoggingBehavior(LoggingBehavior behavior) {
- synchronized (loggingBehaviors) {
- loggingBehaviors.remove(behavior);
- }
- }
-
- /**
- * Certain logging behaviors are available for debugging beyond those that should be
- * enabled in production.
- *
- * Disables all extended logging behaviors.
- */
- public static final void clearLoggingBehaviors() {
- synchronized (loggingBehaviors) {
- loggingBehaviors.clear();
- }
- }
-
- /**
- * Certain logging behaviors are available for debugging beyond those that should be
- * enabled in production.
- *
- * Checks if a particular extended logging behavior is enabled.
- *
- * @param behavior
- * The LoggingBehavior to check
- * @return whether behavior is enabled
- */
- public static final boolean isLoggingBehaviorEnabled(LoggingBehavior behavior) {
- synchronized (loggingBehaviors) {
- return BuildConfig.DEBUG && loggingBehaviors.contains(behavior);
- }
- }
-
- /**
- * Returns the Executor used by the SDK for non-AsyncTask background work.
- *
- * By default this uses AsyncTask Executor via reflection if the API level is high enough.
- * Otherwise this creates a new Executor with defaults similar to those used in AsyncTask.
- *
- * @return an Executor used by the SDK. This will never be null.
- */
- public static Executor getExecutor() {
- synchronized (LOCK) {
- if (Settings.executor == null) {
- Executor executor = getAsyncTaskExecutor();
- if (executor == null) {
- executor = new ThreadPoolExecutor(DEFAULT_CORE_POOL_SIZE, DEFAULT_MAXIMUM_POOL_SIZE,
- DEFAULT_KEEP_ALIVE, TimeUnit.SECONDS, DEFAULT_WORK_QUEUE, DEFAULT_THREAD_FACTORY);
- }
- Settings.executor = executor;
- }
- }
- return Settings.executor;
- }
-
- /**
- * Sets the Executor used by the SDK for non-AsyncTask background work.
- *
- * @param executor
- * the Executor to use; must not be null.
- */
- public static void setExecutor(Executor executor) {
- Validate.notNull(executor, "executor");
- synchronized (LOCK) {
- Settings.executor = executor;
- }
- }
-
- private static Executor getAsyncTaskExecutor() {
- Field executorField = null;
- try {
- executorField = AsyncTask.class.getField("THREAD_POOL_EXECUTOR");
- } catch (NoSuchFieldException e) {
- return null;
- }
-
- if (executorField == null) {
- return null;
- }
-
- Object executorObject = null;
- try {
- executorObject = executorField.get(null);
- } catch (IllegalAccessException e) {
- return null;
- }
-
- if (executorObject == null) {
- return null;
- }
-
- if (!(executorObject instanceof Executor)) {
- return null;
- }
-
- return (Executor) executorObject;
- }
-
- public static void publishInstallAsync(final Context context, final String applicationId) {
- // grab the application context ahead of time, since we will return to the caller immediately.
- final Context applicationContext = context.getApplicationContext();
- Settings.getExecutor().execute(new Runnable() {
- @Override
- public void run() {
- Settings.publishInstallAndWait(applicationContext, applicationId);
- }
- });
- }
-
- /**
- * Sets whether opening a Session should automatically publish install attribution to the Facebook graph.
- *
- * @param shouldAutoPublishInstall true to automatically publish, false to not
- */
- public static void setShouldAutoPublishInstall(boolean shouldAutoPublishInstall) {
- Settings.shouldAutoPublishInstall = shouldAutoPublishInstall;
- }
-
- /**
- * Gets whether opening a Session should automatically publish install attribution to the Facebook graph.
- *
- * @return true to automatically publish, false to not
- */
- public static boolean getShouldAutoPublishInstall() {
- return shouldAutoPublishInstall;
- }
-
- /**
- * Manually publish install attribution to the Facebook graph. Internally handles tracking repeat calls to prevent
- * multiple installs being published to the graph.
- * @param context the current Context
- * @return returns false on error. Applications should retry until true is returned. Safe to call again after
- * true is returned.
- */
- public static boolean publishInstallAndWait(final Context context, final String applicationId) {
- try {
- if (applicationId == null) {
- return false;
- }
- String attributionId = Settings.getAttributionId(context.getContentResolver());
- SharedPreferences preferences = context.getSharedPreferences(ATTRIBUTION_PREFERENCES, Context.MODE_PRIVATE);
- String pingKey = applicationId+"ping";
- long lastPing = preferences.getLong(pingKey, 0);
- if (lastPing == 0 && attributionId != null) {
- Bundle supportsAttributionParams = new Bundle();
- supportsAttributionParams.putString(APPLICATION_FIELDS, SUPPORTS_ATTRIBUTION);
- Request pingRequest = Request.newGraphPathRequest(null, applicationId, null);
- pingRequest.setParameters(supportsAttributionParams);
-
- GraphObject supportResponse = pingRequest.executeAndWait().getGraphObject();
- Object doesSupportAttribution = supportResponse.getProperty(SUPPORTS_ATTRIBUTION);
-
- if (!(doesSupportAttribution instanceof Boolean)) {
- throw new JSONException(String.format(
- "%s contains %s instead of a Boolean", SUPPORTS_ATTRIBUTION, doesSupportAttribution));
- }
-
- if ((Boolean)doesSupportAttribution) {
- GraphObject publishParams = GraphObject.Factory.create();
- publishParams.setProperty(ANALYTICS_EVENT, MOBILE_INSTALL_EVENT);
- publishParams.setProperty(ATTRIBUTION_KEY, attributionId);
-
- String publishUrl = String.format(PUBLISH_ACTIVITY_PATH, applicationId);
-
- Request publishRequest = Request.newPostRequest(null, publishUrl, publishParams, null);
- publishRequest.executeAndWait();
-
- // denote success since no error threw from the post.
- SharedPreferences.Editor editor = preferences.edit();
- lastPing = System.currentTimeMillis();
- editor.putLong(pingKey, lastPing);
- editor.commit();
- }
- }
- return lastPing != 0;
- } catch (Exception e) {
- // if there was an error, fall through to the failure case.
- Utility.logd("Facebook-publish", e.getMessage());
- }
- return false;
- }
-
- public static String getAttributionId(ContentResolver contentResolver) {
- String [] projection = {ATTRIBUTION_ID_COLUMN_NAME};
- Cursor c = contentResolver.query(ATTRIBUTION_ID_CONTENT_URI, projection, null, null, null);
- if (c == null || !c.moveToFirst()) {
- return null;
- }
- String attributionId = c.getString(c.getColumnIndex(ATTRIBUTION_ID_COLUMN_NAME));
- c.close();
- return attributionId;
- }
-}
diff --git a/facebook/facebook/src/com/facebook/SharedPreferencesTokenCachingStrategy.java b/facebook/facebook/src/com/facebook/SharedPreferencesTokenCachingStrategy.java
deleted file mode 100644
index d184b976e..000000000
--- a/facebook/facebook/src/com/facebook/SharedPreferencesTokenCachingStrategy.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.util.Log;
-import com.facebook.internal.Logger;
-import com.facebook.internal.Utility;
-import com.facebook.internal.Validate;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/*
- *
- * An implementation of {@link TokenCachingStrategy TokenCachingStrategy} that uses Android SharedPreferences
- * to persist information.
- *
- *
- * The data to be cached is passed in via a Bundle. Only non-null key-value-pairs where
- * the value is one of the following types (or an array of the same) are persisted:
- * boolean, byte, int, long, float, double, char. In addition, String and List
- * are also supported.
- *
- */
-public class SharedPreferencesTokenCachingStrategy extends TokenCachingStrategy {
-
- private static final String DEFAULT_CACHE_KEY = "com.facebook.SharedPreferencesTokenCachingStrategy.DEFAULT_KEY";
- private static final String TAG = SharedPreferencesTokenCachingStrategy.class.getSimpleName();
-
- private static final String JSON_VALUE_TYPE = "valueType";
- private static final String JSON_VALUE = "value";
- private static final String JSON_VALUE_ENUM_TYPE = "enumType";
-
- private static final String TYPE_BOOLEAN = "bool";
- private static final String TYPE_BOOLEAN_ARRAY = "bool[]";
- private static final String TYPE_BYTE = "byte";
- private static final String TYPE_BYTE_ARRAY = "byte[]";
- private static final String TYPE_SHORT = "short";
- private static final String TYPE_SHORT_ARRAY = "short[]";
- private static final String TYPE_INTEGER = "int";
- private static final String TYPE_INTEGER_ARRAY = "int[]";
- private static final String TYPE_LONG = "long";
- private static final String TYPE_LONG_ARRAY = "long[]";
- private static final String TYPE_FLOAT = "float";
- private static final String TYPE_FLOAT_ARRAY = "float[]";
- private static final String TYPE_DOUBLE = "double";
- private static final String TYPE_DOUBLE_ARRAY = "double[]";
- private static final String TYPE_CHAR = "char";
- private static final String TYPE_CHAR_ARRAY = "char[]";
- private static final String TYPE_STRING = "string";
- private static final String TYPE_STRING_LIST = "stringList";
- private static final String TYPE_ENUM = "enum";
-
- private String cacheKey;
- private SharedPreferences cache;
-
- /**
- * Creates a default {@link SharedPreferencesTokenCachingStrategy SharedPreferencesTokenCachingStrategy}
- * instance that provides access to a single set of token information.
- *
- * @param context
- * The Context object to use to get the SharedPreferences object.
- *
- * @throws NullPointerException if the passed in Context is null
- */
- public SharedPreferencesTokenCachingStrategy(Context context) {
- this(context, null);
- }
-
- /**
- * Creates a {@link SharedPreferencesTokenCachingStrategy SharedPreferencesTokenCachingStrategy} instance
- * that is distinct for the passed in cacheKey.
- *
- * @param context
- * The Context object to use to get the SharedPreferences object.
- *
- * @param cacheKey
- * Identifies a distinct set of token information.
- *
- * @throws NullPointerException if the passed in Context is null
- */
- public SharedPreferencesTokenCachingStrategy(Context context, String cacheKey) {
- Validate.notNull(context, "context");
-
- this.cacheKey = Utility.isNullOrEmpty(cacheKey) ? DEFAULT_CACHE_KEY : cacheKey;
-
- // If the application context is available, use that. However, if it isn't
- // available (possibly because of a context that was created manually), use
- // the passed in context directly.
- Context applicationContext = context.getApplicationContext();
- context = applicationContext != null ? applicationContext : context;
-
- this.cache = context.getSharedPreferences(
- this.cacheKey,
- Context.MODE_PRIVATE);
- }
-
- /**
- * Returns a Bundle that contains the information stored in this cache
- *
- * @return A Bundle with the information contained in this cache
- */
- @Override
- public Bundle load() {
- Bundle settings = new Bundle();
-
- Map allCachedEntries = cache.getAll();
-
- for (String key : allCachedEntries.keySet()) {
- try {
- deserializeKey(key, settings);
- } catch (JSONException e) {
- // Error in the cache. So consider it corrupted and return null
- Logger.log(LoggingBehavior.CACHE, Log.WARN, TAG,
- "Error reading cached value for key: '" + key + "' -- " + e);
- return null;
- }
- }
-
- return settings;
- }
-
- /**
- * Persists all supported data types present in the passed in Bundle, to the
- * cache
- *
- * @param bundle
- * The Bundle containing information to be cached
- */
- @Override
- public void save(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
-
- SharedPreferences.Editor editor = cache.edit();
-
- for (String key : bundle.keySet()) {
- try {
- serializeKey(key, bundle, editor);
- } catch (JSONException e) {
- // Error in the bundle. Don't store a partial cache.
- Logger.log(LoggingBehavior.CACHE, Log.WARN, TAG, "Error processing value for key: '" + key + "' -- " + e);
-
- // Bypass the commit and just return. This cancels the entire edit transaction
- return;
- }
- }
-
- boolean successfulCommit = editor.commit();
- if (!successfulCommit) {
- Logger.log(LoggingBehavior.CACHE, Log.WARN, TAG, "SharedPreferences.Editor.commit() was not successful");
- }
- }
-
- /**
- * Clears out all token information stored in this cache.
- */
- @Override
- public void clear() {
- cache.edit().clear().commit();
- }
-
- private void serializeKey(String key, Bundle bundle, SharedPreferences.Editor editor)
- throws JSONException {
- Object value = bundle.get(key);
- if (value == null) {
- // Cannot serialize null values.
- return;
- }
-
- String supportedType = null;
- JSONArray jsonArray = null;
- JSONObject json = new JSONObject();
-
- if (value instanceof Byte) {
- supportedType = TYPE_BYTE;
- json.put(JSON_VALUE, ((Byte)value).intValue());
- } else if (value instanceof Short) {
- supportedType = TYPE_SHORT;
- json.put(JSON_VALUE, ((Short)value).intValue());
- } else if (value instanceof Integer) {
- supportedType = TYPE_INTEGER;
- json.put(JSON_VALUE, ((Integer)value).intValue());
- } else if (value instanceof Long) {
- supportedType = TYPE_LONG;
- json.put(JSON_VALUE, ((Long)value).longValue());
- } else if (value instanceof Float) {
- supportedType = TYPE_FLOAT;
- json.put(JSON_VALUE, ((Float)value).doubleValue());
- } else if (value instanceof Double) {
- supportedType = TYPE_DOUBLE;
- json.put(JSON_VALUE, ((Double)value).doubleValue());
- } else if (value instanceof Boolean) {
- supportedType = TYPE_BOOLEAN;
- json.put(JSON_VALUE, ((Boolean)value).booleanValue());
- } else if (value instanceof Character) {
- supportedType = TYPE_CHAR;
- json.put(JSON_VALUE, value.toString());
- } else if (value instanceof String) {
- supportedType = TYPE_STRING;
- json.put(JSON_VALUE, (String)value);
- } else if (value instanceof Enum>) {
- supportedType = TYPE_ENUM;
- json.put(JSON_VALUE, value.toString());
- json.put(JSON_VALUE_ENUM_TYPE, value.getClass().getName());
- } else {
- // Optimistically create a JSONArray. If not an array type, we can null
- // it out later
- jsonArray = new JSONArray();
- if (value instanceof byte[]) {
- supportedType = TYPE_BYTE_ARRAY;
- for (byte v : (byte[])value) {
- jsonArray.put((int)v);
- }
- } else if (value instanceof short[]) {
- supportedType = TYPE_SHORT_ARRAY;
- for (short v : (short[])value) {
- jsonArray.put((int)v);
- }
- } else if (value instanceof int[]) {
- supportedType = TYPE_INTEGER_ARRAY;
- for (int v : (int[])value) {
- jsonArray.put(v);
- }
- } else if (value instanceof long[]) {
- supportedType = TYPE_LONG_ARRAY;
- for (long v : (long[])value) {
- jsonArray.put(v);
- }
- } else if (value instanceof float[]) {
- supportedType = TYPE_FLOAT_ARRAY;
- for (float v : (float[])value) {
- jsonArray.put((double)v);
- }
- } else if (value instanceof double[]) {
- supportedType = TYPE_DOUBLE_ARRAY;
- for (double v : (double[])value) {
- jsonArray.put(v);
- }
- } else if (value instanceof boolean[]) {
- supportedType = TYPE_BOOLEAN_ARRAY;
- for (boolean v : (boolean[])value) {
- jsonArray.put(v);
- }
- } else if (value instanceof char[]) {
- supportedType = TYPE_CHAR_ARRAY;
- for (char v : (char[])value) {
- jsonArray.put(String.valueOf(v));
- }
- } else if (value instanceof List>) {
- supportedType = TYPE_STRING_LIST;
- @SuppressWarnings("unchecked")
- List stringList = (List)value;
- for (String v : stringList) {
- jsonArray.put((v == null) ? JSONObject.NULL : v);
- }
- } else {
- // Unsupported type. Clear out the array as a precaution even though
- // it is redundant with the null supportedType.
- jsonArray = null;
- }
- }
-
- if (supportedType != null) {
- json.put(JSON_VALUE_TYPE, supportedType);
- if (jsonArray != null) {
- // If we have an array, it has already been converted to JSON. So use
- // that instead.
- json.putOpt(JSON_VALUE, jsonArray);
- }
-
- String jsonString = json.toString();
- editor.putString(key, jsonString);
- }
- }
-
- private void deserializeKey(String key, Bundle bundle)
- throws JSONException {
- String jsonString = cache.getString(key, "{}");
- JSONObject json = new JSONObject(jsonString);
-
- String valueType = json.getString(JSON_VALUE_TYPE);
-
- if (valueType.equals(TYPE_BOOLEAN)) {
- bundle.putBoolean(key, json.getBoolean(JSON_VALUE));
- } else if (valueType.equals(TYPE_BOOLEAN_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- boolean[] array = new boolean[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- array[i] = jsonArray.getBoolean(i);
- }
- bundle.putBooleanArray(key, array);
- } else if (valueType.equals(TYPE_BYTE)) {
- bundle.putByte(key, (byte)json.getInt(JSON_VALUE));
- } else if (valueType.equals(TYPE_BYTE_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- byte[] array = new byte[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- array[i] = (byte)jsonArray.getInt(i);
- }
- bundle.putByteArray(key, array);
- } else if (valueType.equals(TYPE_SHORT)) {
- bundle.putShort(key, (short)json.getInt(JSON_VALUE));
- } else if (valueType.equals(TYPE_SHORT_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- short[] array = new short[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- array[i] = (short)jsonArray.getInt(i);
- }
- bundle.putShortArray(key, array);
- } else if (valueType.equals(TYPE_INTEGER)) {
- bundle.putInt(key, json.getInt(JSON_VALUE));
- } else if (valueType.equals(TYPE_INTEGER_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- int[] array = new int[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- array[i] = jsonArray.getInt(i);
- }
- bundle.putIntArray(key, array);
- } else if (valueType.equals(TYPE_LONG)) {
- bundle.putLong(key, json.getLong(JSON_VALUE));
- } else if (valueType.equals(TYPE_LONG_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- long[] array = new long[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- array[i] = jsonArray.getLong(i);
- }
- bundle.putLongArray(key, array);
- } else if (valueType.equals(TYPE_FLOAT)) {
- bundle.putFloat(key, (float)json.getDouble(JSON_VALUE));
- } else if (valueType.equals(TYPE_FLOAT_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- float[] array = new float[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- array[i] = (float)jsonArray.getDouble(i);
- }
- bundle.putFloatArray(key, array);
- } else if (valueType.equals(TYPE_DOUBLE)) {
- bundle.putDouble(key, json.getDouble(JSON_VALUE));
- } else if (valueType.equals(TYPE_DOUBLE_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- double[] array = new double[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- array[i] = jsonArray.getDouble(i);
- }
- bundle.putDoubleArray(key, array);
- } else if (valueType.equals(TYPE_CHAR)) {
- String charString = json.getString(JSON_VALUE);
- if (charString != null && charString.length() == 1) {
- bundle.putChar(key, charString.charAt(0));
- }
- } else if (valueType.equals(TYPE_CHAR_ARRAY)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- char[] array = new char[jsonArray.length()];
- for (int i = 0; i < array.length; i++) {
- String charString = jsonArray.getString(i);
- if (charString != null && charString.length() == 1) {
- array[i] = charString.charAt(0);
- }
- }
- bundle.putCharArray(key, array);
- } else if (valueType.equals(TYPE_STRING)) {
- bundle.putString(key, json.getString(JSON_VALUE));
- } else if (valueType.equals(TYPE_STRING_LIST)) {
- JSONArray jsonArray = json.getJSONArray(JSON_VALUE);
- int numStrings = jsonArray.length();
- ArrayList stringList = new ArrayList(numStrings);
- for (int i = 0; i < numStrings; i++) {
- Object jsonStringValue = jsonArray.get(i);
- stringList.add(i, jsonStringValue == JSONObject.NULL ? null : (String)jsonStringValue);
- }
- bundle.putStringArrayList(key, stringList);
- } else if (valueType.equals(TYPE_ENUM)) {
- try {
- String enumType = json.getString(JSON_VALUE_ENUM_TYPE);
- @SuppressWarnings({ "unchecked", "rawtypes" })
- Class extends Enum> enumClass = (Class extends Enum>) Class.forName(enumType);
- @SuppressWarnings("unchecked")
- Enum> enumValue = Enum.valueOf(enumClass, json.getString(JSON_VALUE));
- bundle.putSerializable(key, enumValue);
- } catch (ClassNotFoundException e) {
- } catch (IllegalArgumentException e) {
- }
- }
- }
-}
diff --git a/facebook/facebook/src/com/facebook/TestSession.java b/facebook/facebook/src/com/facebook/TestSession.java
deleted file mode 100644
index 0c6651812..000000000
--- a/facebook/facebook/src/com/facebook/TestSession.java
+++ /dev/null
@@ -1,516 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.Log;
-import com.facebook.model.GraphObject;
-import com.facebook.model.GraphObjectList;
-import com.facebook.internal.Logger;
-import com.facebook.internal.Utility;
-import com.facebook.internal.Validate;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.*;
-
-/**
- * Implements an subclass of Session that knows about test users for a particular
- * application. This should never be used from a real application, but may be useful
- * for writing unit tests, etc.
- *
- * Facebook allows developers to create test accounts for testing their applications'
- * Facebook integration (see https://developers.facebook.com/docs/test_users/). This class
- * simplifies use of these accounts for writing unit tests. It is not designed for use in
- * production application code.
- *
- * The main use case for this class is using {@link #createSessionWithPrivateUser(android.app.Activity, java.util.List)}
- * or {@link #createSessionWithSharedUser(android.app.Activity, java.util.List)}
- * to create a session for a test user. Two modes are supported. In "shared" mode, an attempt
- * is made to find an existing test user that has the required permissions. If no such user is available,
- * a new one is created with the required permissions. In "private" mode, designed for
- * scenarios which require a new user in a known clean state, a new test user will always be
- * created, and it will be automatically deleted when the TestSession is closed. The session
- * obeys the same lifecycle as a regular Session, meaning it must be opened after creation before
- * it can be used to make calls to the Facebook API.
- *
- * Prior to creating a TestSession, two static methods must be called to initialize the
- * application ID and application Secret to be used for managing test users. These methods are
- * {@link #setTestApplicationId(String)} and {@link #setTestApplicationSecret(String)}.
- *
- * Note that the shared test user functionality depends on a naming convention for the test users.
- * It is important that any testing of functionality which will mutate the permissions for a
- * test user NOT use a shared test user, or this scheme will break down. If a shared test user
- * seems to be in an invalid state, it can be deleted manually via the Web interface at
- * https://developers.facebook.com/apps/APP_ID/permissions?role=test+users.
- */
-public class TestSession extends Session {
- private static final long serialVersionUID = 1L;
-
- private enum Mode {
- PRIVATE, SHARED
- }
-
- private static final String LOG_TAG = Logger.LOG_TAG_BASE + "TestSession";
-
- private static Map appTestAccounts;
- private static String testApplicationSecret;
- private static String testApplicationId;
-
- private final String sessionUniqueUserTag;
- private final List requestedPermissions;
- private final Mode mode;
- private String testAccountId;
-
- private boolean wasAskedToExtendAccessToken;
-
- TestSession(Activity activity, List permissions, TokenCachingStrategy tokenCachingStrategy,
- String sessionUniqueUserTag, Mode mode) {
- super(activity, TestSession.testApplicationId, tokenCachingStrategy);
-
- Validate.notNull(permissions, "permissions");
-
- // Validate these as if they were arguments even though they are statics.
- Validate.notNullOrEmpty(testApplicationId, "testApplicationId");
- Validate.notNullOrEmpty(testApplicationSecret, "testApplicationSecret");
-
- this.sessionUniqueUserTag = sessionUniqueUserTag;
- this.mode = mode;
- this.requestedPermissions = permissions;
- }
-
- /**
- * Constructs a TestSession which creates a test user on open, and destroys the user on
- * close; This method should not be used in application code -- but is useful for creating unit tests
- * that use the Facebook SDK.
- *
- * @param activity the Activity to use for opening the session
- * @param permissions list of strings containing permissions to request; nil will result in
- * a common set of permissions (email, publish_actions) being requested
- * @return a new TestSession that is in the CREATED state, ready to be opened
- */
- public static TestSession createSessionWithPrivateUser(Activity activity, List permissions) {
- return createTestSession(activity, permissions, Mode.PRIVATE, null);
- }
-
- /**
- * Constructs a TestSession which uses a shared test user with the right permissions,
- * creating one if necessary on open (but not deleting it on close, so it can be re-used in later
- * tests).
- *
- * This method should not be used in application code -- but is useful for creating unit tests
- * that use the Facebook SDK.
- *
- * @param activity the Activity to use for opening the session
- * @param permissions list of strings containing permissions to request; nil will result in
- * a common set of permissions (email, publish_actions) being requested
- * @return a new TestSession that is in the CREATED state, ready to be opened
- */
- public static TestSession createSessionWithSharedUser(Activity activity, List permissions) {
- return createSessionWithSharedUser(activity, permissions, null);
- }
-
- /**
- * Constructs a TestSession which uses a shared test user with the right permissions,
- * creating one if necessary on open (but not deleting it on close, so it can be re-used in later
- * tests).
- *
- * This method should not be used in application code -- but is useful for creating unit tests
- * that use the Facebook SDK.
- *
- * @param activity the Activity to use for opening the session
- * @param permissions list of strings containing permissions to request; nil will result in
- * a common set of permissions (email, publish_actions) being requested
- * @param sessionUniqueUserTag a string which will be used to make this user unique among other
- * users with the same permissions. Useful for tests which require two or more users to interact
- * with each other, and which therefore must have sessions associated with different users.
- * @return a new TestSession that is in the CREATED state, ready to be opened
- */
- public static TestSession createSessionWithSharedUser(Activity activity, List permissions,
- String sessionUniqueUserTag) {
- return createTestSession(activity, permissions, Mode.SHARED, sessionUniqueUserTag);
- }
-
- /**
- * Gets the Facebook Application ID for the application under test.
- *
- * @return the application ID
- */
- public static synchronized String getTestApplicationId() {
- return testApplicationId;
- }
-
- /**
- * Sets the Facebook Application ID for the application under test. This must be specified
- * prior to creating a TestSession.
- *
- * @param applicationId the application ID
- */
- public static synchronized void setTestApplicationId(String applicationId) {
- if (testApplicationId != null && !testApplicationId.equals(applicationId)) {
- throw new FacebookException("Can't have more than one test application ID");
- }
- testApplicationId = applicationId;
- }
-
- /**
- * Gets the Facebook Application Secret for the application under test.
- *
- * @return the application secret
- */
- public static synchronized String getTestApplicationSecret() {
- return testApplicationSecret;
- }
-
- /**
- * Sets the Facebook Application Secret for the application under test. This must be specified
- * prior to creating a TestSession.
- *
- * @param applicationSecret the application secret
- */
- public static synchronized void setTestApplicationSecret(String applicationSecret) {
- if (testApplicationSecret != null && !testApplicationSecret.equals(applicationSecret)) {
- throw new FacebookException("Can't have more than one test application secret");
- }
- testApplicationSecret = applicationSecret;
- }
-
- /**
- * Gets the ID of the test user that this TestSession is authenticated as.
- *
- * @return the Facebook user ID of the test user
- */
- public final String getTestUserId() {
- return testAccountId;
- }
-
- private static synchronized TestSession createTestSession(Activity activity, List permissions, Mode mode,
- String sessionUniqueUserTag) {
- if (Utility.isNullOrEmpty(testApplicationId) || Utility.isNullOrEmpty(testApplicationSecret)) {
- throw new FacebookException("Must provide app ID and secret");
- }
-
- if (Utility.isNullOrEmpty(permissions)) {
- permissions = Arrays.asList("email", "publish_actions");
- }
-
- return new TestSession(activity, permissions, new TestTokenCachingStrategy(), sessionUniqueUserTag,
- mode);
- }
-
- private static synchronized void retrieveTestAccountsForAppIfNeeded() {
- if (appTestAccounts != null) {
- return;
- }
-
- appTestAccounts = new HashMap();
-
- // The data we need is split across two different FQL tables. We construct two queries, submit them
- // together (the second one refers to the first one), then cross-reference the results.
-
- // Get the test accounts for this app.
- String testAccountQuery = String.format("SELECT id,access_token FROM test_account WHERE app_id = %s",
- testApplicationId);
- // Get the user names for those accounts.
- String userQuery = "SELECT uid,name FROM user WHERE uid IN (SELECT id FROM #test_accounts)";
-
- Bundle parameters = new Bundle();
-
- // Build a JSON string that contains our queries and pass it as the 'q' parameter of the query.
- JSONObject multiquery;
- try {
- multiquery = new JSONObject();
- multiquery.put("test_accounts", testAccountQuery);
- multiquery.put("users", userQuery);
- } catch (JSONException exception) {
- throw new FacebookException(exception);
- }
- parameters.putString("q", multiquery.toString());
-
- // We need to authenticate as this app.
- parameters.putString("access_token", getAppAccessToken());
-
- Request request = new Request(null, "fql", parameters, null);
- Response response = request.executeAndWait();
-
- if (response.getError() != null) {
- throw response.getError().getException();
- }
-
- FqlResponse fqlResponse = response.getGraphObjectAs(FqlResponse.class);
-
- GraphObjectList fqlResults = fqlResponse.getData();
- if (fqlResults == null || fqlResults.size() != 2) {
- throw new FacebookException("Unexpected number of results from FQL query");
- }
-
- // We get back two sets of results. The first is from the test_accounts query, the second from the users query.
- Collection testAccounts = fqlResults.get(0).getFqlResultSet().castToListOf(TestAccount.class);
- Collection userAccounts = fqlResults.get(1).getFqlResultSet().castToListOf(UserAccount.class);
-
- // Use both sets of results to populate our static array of accounts.
- populateTestAccounts(testAccounts, userAccounts);
-
- return;
- }
-
- private static synchronized void populateTestAccounts(Collection testAccounts,
- Collection userAccounts) {
- // We get different sets of data from each of these queries. We want to combine them into a single data
- // structure. We have added a Name property to the TestAccount interface, even though we don't really get
- // a name back from the service from that query. We stick the Name from the corresponding UserAccount in it.
- for (TestAccount testAccount : testAccounts) {
- storeTestAccount(testAccount);
- }
-
- for (UserAccount userAccount : userAccounts) {
- TestAccount testAccount = appTestAccounts.get(userAccount.getUid());
- if (testAccount != null) {
- testAccount.setName(userAccount.getName());
- }
- }
- }
-
- private static synchronized void storeTestAccount(TestAccount testAccount) {
- appTestAccounts.put(testAccount.getId(), testAccount);
- }
-
- private static synchronized TestAccount findTestAccountMatchingIdentifier(String identifier) {
- retrieveTestAccountsForAppIfNeeded();
-
- for (TestAccount testAccount : appTestAccounts.values()) {
- if (testAccount.getName().contains(identifier)) {
- return testAccount;
- }
- }
- return null;
- }
-
- @Override
- public final String toString() {
- String superString = super.toString();
-
- return new StringBuilder().append("{TestSession").append(" testUserId:").append(testAccountId)
- .append(" ").append(superString).append("}").toString();
- }
-
- @Override
- void authorize(AuthorizationRequest request) {
- if (mode == Mode.PRIVATE) {
- createTestAccountAndFinishAuth();
- } else {
- findOrCreateSharedTestAccount();
- }
- }
-
- @Override
- void postStateChange(final SessionState oldState, final SessionState newState, final Exception error) {
- // Make sure this doesn't get overwritten.
- String id = testAccountId;
-
- super.postStateChange(oldState, newState, error);
-
- if (newState.isClosed() && id != null && mode == Mode.PRIVATE) {
- deleteTestAccount(id, getAppAccessToken());
- }
- }
-
- boolean getWasAskedToExtendAccessToken() {
- return wasAskedToExtendAccessToken;
- }
-
- void forceExtendAccessToken(boolean forceExtendAccessToken) {
- AccessToken currentToken = getTokenInfo();
- setTokenInfo(
- new AccessToken(currentToken.getToken(), new Date(), currentToken.getPermissions(),
- AccessTokenSource.TEST_USER, new Date(0)));
- setLastAttemptedTokenExtendDate(new Date(0));
- }
-
- @Override
- boolean shouldExtendAccessToken() {
- boolean result = super.shouldExtendAccessToken();
- wasAskedToExtendAccessToken = false;
- return result;
- }
-
- @Override
- void extendAccessToken() {
- wasAskedToExtendAccessToken = true;
- super.extendAccessToken();
- }
-
- void fakeTokenRefreshAttempt() {
- setCurrentTokenRefreshRequest(new TokenRefreshRequest());
- }
-
- static final String getAppAccessToken() {
- return testApplicationId + "|" + testApplicationSecret;
- }
-
- private void findOrCreateSharedTestAccount() {
- TestAccount testAccount = findTestAccountMatchingIdentifier(getSharedTestAccountIdentifier());
- if (testAccount != null) {
- finishAuthWithTestAccount(testAccount);
- } else {
- createTestAccountAndFinishAuth();
- }
- }
-
- private void finishAuthWithTestAccount(TestAccount testAccount) {
- testAccountId = testAccount.getId();
-
- AccessToken accessToken = AccessToken.createFromString(testAccount.getAccessToken(), requestedPermissions,
- AccessTokenSource.TEST_USER);
- finishAuthOrReauth(accessToken, null);
- }
-
- private TestAccount createTestAccountAndFinishAuth() {
- Bundle parameters = new Bundle();
- parameters.putString("installed", "true");
- parameters.putString("permissions", getPermissionsString());
- parameters.putString("access_token", getAppAccessToken());
-
- // If we're in shared mode, we want to rename this user to encode its permissions, so we can find it later
- // in another shared session. If we're in private mode, don't bother renaming it since we're just going to
- // delete it at the end of the session.
- if (mode == Mode.SHARED) {
- parameters.putString("name", String.format("Shared %s Testuser", getSharedTestAccountIdentifier()));
- }
-
- String graphPath = String.format("%s/accounts/test-users", testApplicationId);
- Request createUserRequest = new Request(null, graphPath, parameters, HttpMethod.POST);
- Response response = createUserRequest.executeAndWait();
-
- FacebookRequestError error = response.getError();
- TestAccount testAccount = response.getGraphObjectAs(TestAccount.class);
- if (error != null) {
- finishAuthOrReauth(null, error.getException());
- return null;
- } else {
- assert testAccount != null;
-
- // If we are in shared mode, store this new account in the dictionary so we can re-use it later.
- if (mode == Mode.SHARED) {
- // Remember the new name we gave it, since we didn't get it back in the results of the create request.
- testAccount.setName(parameters.getString("name"));
- storeTestAccount(testAccount);
- }
-
- finishAuthWithTestAccount(testAccount);
-
- return testAccount;
- }
- }
-
- private void deleteTestAccount(String testAccountId, String appAccessToken) {
- Bundle parameters = new Bundle();
- parameters.putString("access_token", appAccessToken);
-
- Request request = new Request(null, testAccountId, parameters, HttpMethod.DELETE);
- Response response = request.executeAndWait();
-
- FacebookRequestError error = response.getError();
- GraphObject graphObject = response.getGraphObject();
- if (error != null) {
- Log.w(LOG_TAG, String.format("Could not delete test account %s: %s", testAccountId, error.getException().toString()));
- } else if (graphObject.getProperty(Response.NON_JSON_RESPONSE_PROPERTY) == (Boolean) false) {
- Log.w(LOG_TAG, String.format("Could not delete test account %s: unknown reason", testAccountId));
- }
- }
-
- private String getPermissionsString() {
- return TextUtils.join(",", requestedPermissions);
- }
-
- private String getSharedTestAccountIdentifier() {
- // We use long even though hashes are ints to avoid sign issues.
- long permissionsHash = getPermissionsString().hashCode() & 0xffffffffL;
- long sessionTagHash = (sessionUniqueUserTag != null) ? sessionUniqueUserTag.hashCode() & 0xffffffffL : 0;
-
- long combinedHash = permissionsHash ^ sessionTagHash;
- return validNameStringFromInteger(combinedHash);
- }
-
- private String validNameStringFromInteger(long i) {
- String s = Long.toString(i);
- StringBuilder result = new StringBuilder("Perm");
-
- // We know each character is a digit. Convert it into a letter 'a'-'j'. Avoid repeated characters
- // that might make Facebook reject the name by converting every other repeated character into one
- // 10 higher ('k'-'t').
- char lastChar = 0;
- for (char c : s.toCharArray()) {
- if (c == lastChar) {
- c += 10;
- }
- result.append((char) (c + 'a' - '0'));
- lastChar = c;
- }
-
- return result.toString();
- }
-
- private interface TestAccount extends GraphObject {
- String getId();
-
- String getAccessToken();
-
- // Note: We don't actually get Name from our FQL query. We fill it in by correlating with UserAccounts.
- String getName();
-
- void setName(String name);
- }
-
- private interface UserAccount extends GraphObject {
- String getUid();
-
- String getName();
-
- void setName(String name);
- }
-
- private interface FqlResult extends GraphObject {
- GraphObjectList getFqlResultSet();
-
- }
-
- private interface FqlResponse extends GraphObject {
- GraphObjectList getData();
- }
-
- private static final class TestTokenCachingStrategy extends TokenCachingStrategy {
- private Bundle bundle;
-
- @Override
- public Bundle load() {
- return bundle;
- }
-
- @Override
- public void save(Bundle value) {
- bundle = value;
- }
-
- @Override
- public void clear() {
- bundle = null;
- }
- }
-}
diff --git a/facebook/facebook/src/com/facebook/TokenCachingStrategy.java b/facebook/facebook/src/com/facebook/TokenCachingStrategy.java
deleted file mode 100644
index cb3271ac8..000000000
--- a/facebook/facebook/src/com/facebook/TokenCachingStrategy.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-import android.os.Bundle;
-import com.facebook.internal.Validate;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- *
- * A base class for implementations of a {@link Session Session} token cache.
- *
- *
- * The Session constructor optionally takes a TokenCachingStrategy, from which it will
- * attempt to load a cached token during construction. Also, whenever the
- * Session updates its token, it will also save the token and associated state
- * to the TokenCachingStrategy.
- *
- *
- * This is the only mechanism supported for an Android service to use Session.
- * The service can create a custom TokenCachingStrategy that returns the Session provided
- * by an Activity through which the user logged in to Facebook.
- *
- */
-public abstract class TokenCachingStrategy {
- /**
- * The key used by Session to store the token value in the Bundle during
- * load and save.
- */
- public static final String TOKEN_KEY = "com.facebook.TokenCachingStrategy.Token";
-
- /**
- * The key used by Session to store the expiration date value in the Bundle
- * during load and save.
- */
- public static final String EXPIRATION_DATE_KEY = "com.facebook.TokenCachingStrategy.ExpirationDate";
-
- /**
- * The key used by Session to store the last refresh date value in the
- * Bundle during load and save.
- */
- public static final String LAST_REFRESH_DATE_KEY = "com.facebook.TokenCachingStrategy.LastRefreshDate";
-
- /**
- * The key used by Session to store the user's id value in the Bundle during
- * load and save.
- */
- public static final String USER_FBID_KEY = "com.facebook.TokenCachingStrategy.UserFBID";
-
- /**
- * The key used by Session to store an enum indicating the source of the token
- * in the Bundle during load and save.
- */
- public static final String TOKEN_SOURCE_KEY = "com.facebook.TokenCachingStrategy.AccessTokenSource";
-
- /**
- * The key used by Session to store the list of permissions granted by the
- * token in the Bundle during load and save.
- */
- public static final String PERMISSIONS_KEY = "com.facebook.TokenCachingStrategy.Permissions";
-
- private static final long INVALID_BUNDLE_MILLISECONDS = Long.MIN_VALUE;
- private static final String IS_SSO_KEY = "com.facebook.TokenCachingStrategy.IsSSO";
-
- /**
- * Called during Session construction to get the token state. Typically this
- * is loaded from a persistent store that was previously initialized via
- * save. The caller may choose to keep a reference to the returned Bundle
- * indefinitely. Therefore the TokenCachingStrategy should not store the returned Bundle
- * and should return a new Bundle on every call to this method.
- *
- * @return A Bundle that represents the token state that was loaded.
- */
- public abstract Bundle load();
-
- /**
- * Called when a Session updates its token. This is passed a Bundle of
- * values that should be stored durably for the purpose of being returned
- * from a later call to load. Some implementations may choose to store
- * bundle beyond the scope of this call, so the caller should keep no
- * references to the bundle to ensure that it is not modified later.
- *
- * @param bundle
- * A Bundle that represents the token state to be saved.
- */
- public abstract void save(Bundle bundle);
-
- /**
- * Called when a Session learns its token is no longer valid or during a
- * call to {@link Session#closeAndClearTokenInformation
- * closeAndClearTokenInformation} to clear the durable state associated with
- * the token.
- */
- public abstract void clear();
-
- /**
- * Returns a boolean indicating whether a Bundle contains properties that
- * could be a valid saved token.
- *
- * @param bundle
- * A Bundle to check for token information.
- * @return a boolean indicating whether a Bundle contains properties that
- * could be a valid saved token.
- */
- public static boolean hasTokenInformation(Bundle bundle) {
- if (bundle == null) {
- return false;
- }
-
- String token = bundle.getString(TOKEN_KEY);
- if ((token == null) || (token.length() == 0)) {
- return false;
- }
-
- long expiresMilliseconds = bundle.getLong(EXPIRATION_DATE_KEY, 0L);
- if (expiresMilliseconds == 0L) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Gets the cached token value from a Bundle.
- *
- * @param bundle
- * A Bundle in which the token value was stored.
- * @return the cached token value, or null.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static String getToken(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
- return bundle.getString(TOKEN_KEY);
- }
-
- /**
- * Puts the token value into a Bundle.
- *
- * @param bundle
- * A Bundle in which the token value should be stored.
- * @param value
- * The String representing the token value, or null.
- *
- * @throws NullPointerException if the passed in Bundle or token value are null
- */
- public static void putToken(Bundle bundle, String value) {
- Validate.notNull(bundle, "bundle");
- Validate.notNull(value, "value");
- bundle.putString(TOKEN_KEY, value);
- }
-
- /**
- * Gets the cached expiration date from a Bundle.
- *
- * @param bundle
- * A Bundle in which the expiration date was stored.
- * @return the cached expiration date, or null.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static Date getExpirationDate(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
- return getDate(bundle, EXPIRATION_DATE_KEY);
- }
-
- /**
- * Puts the expiration date into a Bundle.
- *
- * @param bundle
- * A Bundle in which the expiration date should be stored.
- * @param value
- * The Date representing the expiration date.
- *
- * @throws NullPointerException if the passed in Bundle or date value are null
- */
- public static void putExpirationDate(Bundle bundle, Date value) {
- Validate.notNull(bundle, "bundle");
- Validate.notNull(value, "value");
- putDate(bundle, EXPIRATION_DATE_KEY, value);
- }
-
- /**
- * Gets the cached expiration date from a Bundle.
- *
- * @param bundle
- * A Bundle in which the expiration date was stored.
- * @return the long representing the cached expiration date in milliseconds
- * since the epoch, or 0.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static long getExpirationMilliseconds(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
- return bundle.getLong(EXPIRATION_DATE_KEY);
- }
-
- /**
- * Puts the expiration date into a Bundle.
- *
- * @param bundle
- * A Bundle in which the expiration date should be stored.
- * @param value
- * The long representing the expiration date in milliseconds
- * since the epoch.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static void putExpirationMilliseconds(Bundle bundle, long value) {
- Validate.notNull(bundle, "bundle");
- bundle.putLong(EXPIRATION_DATE_KEY, value);
- }
-
- /**
- * Gets the cached list of permissions from a Bundle.
- *
- * @param bundle
- * A Bundle in which the list of permissions was stored.
- * @return the cached list of permissions.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static List getPermissions(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
- return bundle.getStringArrayList(PERMISSIONS_KEY);
- }
-
- /**
- * Puts the list of permissions into a Bundle.
- *
- * @param bundle
- * A Bundle in which the list of permissions should be stored.
- * @param value
- * The List<String> representing the list of permissions,
- * or null.
- *
- * @throws NullPointerException if the passed in Bundle or permissions list are null
- */
- public static void putPermissions(Bundle bundle, List value) {
- Validate.notNull(bundle, "bundle");
- Validate.notNull(value, "value");
-
- ArrayList arrayList;
- if (value instanceof ArrayList>) {
- arrayList = (ArrayList) value;
- } else {
- arrayList = new ArrayList(value);
- }
- bundle.putStringArrayList(PERMISSIONS_KEY, arrayList);
- }
-
- /**
- * Gets the cached enum indicating the source of the token from the Bundle.
- *
- * @param bundle
- * A Bundle in which the enum was stored.
- * @return enum indicating the source of the token
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static AccessTokenSource getSource(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
- if (bundle.containsKey(TokenCachingStrategy.TOKEN_SOURCE_KEY)) {
- return (AccessTokenSource) bundle.getSerializable(TokenCachingStrategy.TOKEN_SOURCE_KEY);
- } else {
- boolean isSSO = bundle.getBoolean(TokenCachingStrategy.IS_SSO_KEY);
- return isSSO ? AccessTokenSource.FACEBOOK_APPLICATION_WEB : AccessTokenSource.WEB_VIEW;
- }
- }
- /**
- * Puts the enum indicating the source of the token into a Bundle.
- *
- * @param bundle
- * A Bundle in which the enum should be stored.
- * @param value
- * enum indicating the source of the token
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static void putSource(Bundle bundle, AccessTokenSource value) {
- Validate.notNull(bundle, "bundle");
- bundle.putSerializable(TOKEN_SOURCE_KEY, value);
- }
-
- /**
- * Gets the cached last refresh date from a Bundle.
- *
- * @param bundle
- * A Bundle in which the last refresh date was stored.
- * @return the cached last refresh Date, or null.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static Date getLastRefreshDate(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
- return getDate(bundle, LAST_REFRESH_DATE_KEY);
- }
-
- /**
- * Puts the last refresh date into a Bundle.
- *
- * @param bundle
- * A Bundle in which the last refresh date should be stored.
- * @param value
- * The Date representing the last refresh date, or null.
- *
- * @throws NullPointerException if the passed in Bundle or date value are null
- */
- public static void putLastRefreshDate(Bundle bundle, Date value) {
- Validate.notNull(bundle, "bundle");
- Validate.notNull(value, "value");
- putDate(bundle, LAST_REFRESH_DATE_KEY, value);
- }
-
- /**
- * Gets the cached last refresh date from a Bundle.
- *
- * @param bundle
- * A Bundle in which the last refresh date was stored.
- * @return the cached last refresh date in milliseconds since the epoch.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static long getLastRefreshMilliseconds(Bundle bundle) {
- Validate.notNull(bundle, "bundle");
- return bundle.getLong(LAST_REFRESH_DATE_KEY);
- }
-
- /**
- * Puts the last refresh date into a Bundle.
- *
- * @param bundle
- * A Bundle in which the last refresh date should be stored.
- * @param value
- * The long representing the last refresh date in milliseconds
- * since the epoch.
- *
- * @throws NullPointerException if the passed in Bundle is null
- */
- public static void putLastRefreshMilliseconds(Bundle bundle, long value) {
- Validate.notNull(bundle, "bundle");
- bundle.putLong(LAST_REFRESH_DATE_KEY, value);
- }
-
- static Date getDate(Bundle bundle, String key) {
- if (bundle == null) {
- return null;
- }
-
- long n = bundle.getLong(key, INVALID_BUNDLE_MILLISECONDS);
- if (n == INVALID_BUNDLE_MILLISECONDS) {
- return null;
- }
-
- return new Date(n);
- }
-
- static void putDate(Bundle bundle, String key, Date date) {
- bundle.putLong(key, date.getTime());
- }
-}
diff --git a/facebook/facebook/src/com/facebook/UiLifecycleHelper.java b/facebook/facebook/src/com/facebook/UiLifecycleHelper.java
deleted file mode 100644
index 5d42267f6..000000000
--- a/facebook/facebook/src/com/facebook/UiLifecycleHelper.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.support.v4.content.LocalBroadcastManager;
-
-/**
- * This class helps to create, automatically open (if applicable), save, and
- * restore the Active Session in a way that is similar to Android UI lifecycles.
- *
- * When using this class, clients MUST call all the public methods from the
- * respective methods in either an Activity or Fragment. Failure to call all the
- * methods can result in improperly initialized or uninitialized Sessions.
- */
-public class UiLifecycleHelper {
-
- private final static String ACTIVITY_NULL_MESSAGE = "activity cannot be null";
-
- private final Activity activity;
- private final Session.StatusCallback callback;
- private final BroadcastReceiver receiver;
- private final LocalBroadcastManager broadcastManager;
-
- /**
- * Creates a new UiLifecycleHelper.
- *
- * @param activity the Activity associated with the helper. If calling from a Fragment,
- * use {@link android.support.v4.app.Fragment#getActivity()}
- * @param callback the callback for Session status changes, can be null
- */
- public UiLifecycleHelper(Activity activity, Session.StatusCallback callback) {
- if (activity == null) {
- throw new IllegalArgumentException(ACTIVITY_NULL_MESSAGE);
- }
- this.activity = activity;
- this.callback = callback;
- this.receiver = new ActiveSessionBroadcastReceiver();
- this.broadcastManager = LocalBroadcastManager.getInstance(activity);
- }
-
- /**
- * To be called from an Activity or Fragment's onCreate method.
- *
- * @param savedInstanceState the previously saved state
- */
- public void onCreate(Bundle savedInstanceState) {
- Session session = Session.getActiveSession();
- if (session == null) {
- if (savedInstanceState != null) {
- session = Session.restoreSession(activity, null, callback, savedInstanceState);
- }
- if (session == null) {
- session = new Session(activity);
- }
- Session.setActiveSession(session);
- }
-
- // add the broadcast receiver
- IntentFilter filter = new IntentFilter();
- filter.addAction(Session.ACTION_ACTIVE_SESSION_SET);
- filter.addAction(Session.ACTION_ACTIVE_SESSION_UNSET);
-
- // Add a broadcast receiver to listen to when the active Session
- // is set or unset, and add/remove our callback as appropriate
- broadcastManager.registerReceiver(receiver, filter);
- }
-
- /**
- * To be called from an Activity or Fragment's onResume method.
- */
- public void onResume() {
- Session session = Session.getActiveSession();
- if (session != null) {
- if (callback != null) {
- session.addCallback(callback);
- }
- if (SessionState.CREATED_TOKEN_LOADED.equals(session.getState())) {
- session.openForRead(null);
- }
- }
-
- }
-
- /**
- * To be called from an Activity or Fragment's onActivityResult method.
- *
- * @param requestCode the request code
- * @param resultCode the result code
- * @param data the result data
- */
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- Session session = Session.getActiveSession();
- if (session != null) {
- session.onActivityResult(activity, requestCode, resultCode, data);
- }
- }
-
- /**
- * To be called from an Activity or Fragment's onSaveInstanceState method.
- *
- * @param outState the bundle to save state in
- */
- public void onSaveInstanceState(Bundle outState) {
- Session.saveSession(Session.getActiveSession(), outState);
- }
-
- /**
- * To be called from an Activity or Fragment's onPause method.
- */
- public void onPause() {
- if (callback != null) {
- Session session = Session.getActiveSession();
- if (session != null) {
- session.removeCallback(callback);
- }
- }
- }
-
- /**
- * To be called from an Activity or Fragment's onDestroy method.
- */
- public void onDestroy() {
- // remove the broadcast receiver
- broadcastManager.unregisterReceiver(receiver);
- }
-
- /**
- * The BroadcastReceiver implementation that either adds or removes the callback
- * from the active Session object as it's SET or UNSET.
- */
- private class ActiveSessionBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Session.ACTION_ACTIVE_SESSION_SET.equals(intent.getAction())) {
- Session session = Session.getActiveSession();
- if (session != null && callback != null) {
- session.addCallback(callback);
- }
- } else if (Session.ACTION_ACTIVE_SESSION_UNSET.equals(intent.getAction())) {
- Session session = Session.getActiveSession();
- if (session != null && callback != null) {
- session.removeCallback(callback);
- }
- }
- }
- }
-}
diff --git a/facebook/facebook/src/com/facebook/android/AsyncFacebookRunner.java b/facebook/facebook/src/com/facebook/android/AsyncFacebookRunner.java
deleted file mode 100644
index 2420fd4b3..000000000
--- a/facebook/facebook/src/com/facebook/android/AsyncFacebookRunner.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/**
- * Copyright 2010-present Facebook
- *
- * 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 com.facebook.android;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.MalformedURLException;
-
-/**
- * A sample implementation of asynchronous API requests. This class provides
- * the ability to execute API methods and have the call return immediately,
- * without blocking the calling thread. This is necessary when accessing the
- * API in the UI thread, for instance. The request response is returned to
- * the caller via a callback interface, which the developer must implement.
- *
- * This sample implementation simply spawns a new thread for each request,
- * and makes the API call immediately. This may work in many applications,
- * but more sophisticated users may re-implement this behavior using a thread
- * pool, a network thread, a request queue, or other mechanism. Advanced
- * functionality could be built, such as rate-limiting of requests, as per
- * a specific application's needs.
- *
- * @deprecated
- *
- * @see RequestListener
- * The callback interface.
- *
- * @author Jim Brusstar (jimbru@fb.com),
- * Yariv Sadan (yariv@fb.com),
- * Luke Shepard (lshepard@fb.com)
- */
-@Deprecated
-public class AsyncFacebookRunner {
-
- Facebook fb;
-
- public AsyncFacebookRunner(Facebook fb) {
- this.fb = fb;
- }
-
- /**
- * Invalidate the current user session by removing the access token in
- * memory, clearing the browser cookies, and calling auth.expireSession
- * through the API. The application will be notified when logout is
- * complete via the callback interface.
- *
- * Note that this method is asynchronous and the callback will be invoked
- * in a background thread; operations that affect the UI will need to be
- * posted to the UI thread or an appropriate handler.
- *
- * This method is deprecated. See {@link Facebook} and {@link com.facebook.Session} for more info.
- *
- * @param context
- * The Android context in which the logout should be called: it
- * should be the same context in which the login occurred in
- * order to clear any stored cookies
- * @param listener
- * Callback interface to notify the application when the request
- * has completed.
- * @param state
- * An arbitrary object used to identify the request when it
- * returns to the callback. This has no effect on the request
- * itself.
- */
- @Deprecated
- public void logout(final Context context,
- final RequestListener listener,
- final Object state) {
- new Thread() {
- @Override public void run() {
- try {
- String response = fb.logoutImpl(context);
- if (response.length() == 0 || response.equals("false")){
- listener.onFacebookError(new FacebookError(
- "auth.expireSession failed"), state);
- return;
- }
- listener.onComplete(response, state);
- } catch (FileNotFoundException e) {
- listener.onFileNotFoundException(e, state);
- } catch (MalformedURLException e) {
- listener.onMalformedURLException(e, state);
- } catch (IOException e) {
- listener.onIOException(e, state);
- }
- }
- }.start();
- }
-
- @Deprecated
- public void logout(final Context context, final RequestListener listener) {
- logout(context, listener, /* state */ null);
- }
-
- /**
- * Make a request to Facebook's old (pre-graph) API with the given
- * parameters. One of the parameter keys must be "method" and its value
- * should be a valid REST server API method.
- *
- * See http://developers.facebook.com/docs/reference/rest/
- *
- * Note that this method is asynchronous and the callback will be invoked
- * in a background thread; operations that affect the UI will need to be
- * posted to the UI thread or an appropriate handler.
- *
- * Example:
- *
- * Bundle parameters = new Bundle();
- * parameters.putString("method", "auth.expireSession", new Listener());
- * String response = request(parameters);
- *
- *
- * This method is deprecated. See {@link Facebook} and {@link com.facebook.Request} for more info.
- *
- * @param parameters
- * Key-value pairs of parameters to the request. Refer to the
- * documentation: one of the parameters must be "method".
- * @param listener
- * Callback interface to notify the application when the request
- * has completed.
- * @param state
- * An arbitrary object used to identify the request when it
- * returns to the callback. This has no effect on the request
- * itself.
- */
- @Deprecated
- public void request(Bundle parameters,
- RequestListener listener,
- final Object state) {
- request(null, parameters, "GET", listener, state);
- }
-
- @Deprecated
- public void request(Bundle parameters, RequestListener listener) {
- request(null, parameters, "GET", listener, /* state */ null);
- }
-
- /**
- * Make a request to the Facebook Graph API without any parameters.
- *
- * See http://developers.facebook.com/docs/api
- *
- * Note that this method is asynchronous and the callback will be invoked
- * in a background thread; operations that affect the UI will need to be
- * posted to the UI thread or an appropriate handler.
- *
- * This method is deprecated. See {@link Facebook} and {@link com.facebook.Request} for more info.
- *
- * @param graphPath
- * Path to resource in the Facebook graph, e.g., to fetch data
- * about the currently logged authenticated user, provide "me",
- * which will fetch http://graph.facebook.com/me
- * @param listener
- * Callback interface to notify the application when the request
- * has completed.
- * @param state
- * An arbitrary object used to identify the request when it
- * returns to the callback. This has no effect on the request
- * itself.
- */
- @Deprecated
- public void request(String graphPath,
- RequestListener listener,
- final Object state) {
- request(graphPath, new Bundle(), "GET", listener, state);
- }
-
- @Deprecated
- public void request(String graphPath, RequestListener listener) {
- request(graphPath, new Bundle(), "GET", listener, /* state */ null);
- }
-
- /**
- * Make a request to the Facebook Graph API with the given string parameters
- * using an HTTP GET (default method).
- *
- * See http://developers.facebook.com/docs/api
- *
- * Note that this method is asynchronous and the callback will be invoked
- * in a background thread; operations that affect the UI will need to be
- * posted to the UI thread or an appropriate handler.
- *
- * This method is deprecated. See {@link Facebook} and {@link com.facebook.Request} for more info.
- *
- * @param graphPath
- * Path to resource in the Facebook graph, e.g., to fetch data
- * about the currently logged authenticated user, provide "me",
- * which will fetch http://graph.facebook.com/me
- * @param parameters
- * key-value string parameters, e.g. the path "search" with
- * parameters "q" : "facebook" would produce a query for the
- * following graph resource:
- * https://graph.facebook.com/search?q=facebook
- * @param listener
- * Callback interface to notify the application when the request
- * has completed.
- * @param state
- * An arbitrary object used to identify the request when it
- * returns to the callback. This has no effect on the request
- * itself.
- */
- @Deprecated
- public void request(String graphPath,
- Bundle parameters,
- RequestListener listener,
- final Object state) {
- request(graphPath, parameters, "GET", listener, state);
- }
-
- @Deprecated
- public void request(String graphPath,
- Bundle parameters,
- RequestListener listener) {
- request(graphPath, parameters, "GET", listener, /* state */ null);
- }
-
- /**
- * Make a request to the Facebook Graph API with the given HTTP method and
- * string parameters. Note that binary data parameters (e.g. pictures) are
- * not yet supported by this helper function.
- *
- * See http://developers.facebook.com/docs/api
- *
- * Note that this method is asynchronous and the callback will be invoked
- * in a background thread; operations that affect the UI will need to be
- * posted to the UI thread or an appropriate handler.
- *
- * This method is deprecated. See {@link Facebook} and {@link com.facebook.Request} for more info.
- *
- * @param graphPath
- * Path to resource in the Facebook graph, e.g., to fetch data
- * about the currently logged authenticated user, provide "me",
- * which will fetch http://graph.facebook.com/me
- * @param parameters
- * key-value string parameters, e.g. the path "search" with
- * parameters {"q" : "facebook"} would produce a query for the
- * following graph resource:
- * https://graph.facebook.com/search?q=facebook
- * @param httpMethod
- * http verb, e.g. "POST", "DELETE"
- * @param listener
- * Callback interface to notify the application when the request
- * has completed.
- * @param state
- * An arbitrary object used to identify the request when it
- * returns to the callback. This has no effect on the request
- * itself.
- */
- @Deprecated
- public void request(final String graphPath,
- final Bundle parameters,
- final String httpMethod,
- final RequestListener listener,
- final Object state) {
- new Thread() {
- @Override public void run() {
- try {
- String resp = fb.requestImpl(graphPath, parameters, httpMethod);
- listener.onComplete(resp, state);
- } catch (FileNotFoundException e) {
- listener.onFileNotFoundException(e, state);
- } catch (MalformedURLException e) {
- listener.onMalformedURLException(e, state);
- } catch (IOException e) {
- listener.onIOException(e, state);
- }
- }
- }.start();
- }
-
- /**
- * Callback interface for API requests.
- *
- * Each method includes a 'state' parameter that identifies the calling
- * request. It will be set to the value passed when originally calling the
- * request method, or null if none was passed.
- *
- * This interface is deprecated. See {@link Facebook} and {@link com.facebook.Request} for more info.
- */
- @Deprecated
- public static interface RequestListener {
-
- /**
- * Called when a request completes with the given response.
- *
- * Executed by a background thread: do not update the UI in this method.
- */
- public void onComplete(String response, Object state);
-
- /**
- * Called when a request has a network or request error.
- *
- * Executed by a background thread: do not update the UI in this method.
- */
- public void onIOException(IOException e, Object state);
-
- /**
- * Called when a request fails because the requested resource is
- * invalid or does not exist.
- *
- * Executed by a background thread: do not update the UI in this method.
- */
- public void onFileNotFoundException(FileNotFoundException e,
- Object state);
-
- /**
- * Called if an invalid graph path is provided (which may result in a
- * malformed URL).
- *
- * Executed by a background thread: do not update the UI in this method.
- */
- public void onMalformedURLException(MalformedURLException e,
- Object state);
-
- /**
- * Called when the server-side Facebook method fails.
- *
- * Executed by a background thread: do not update the UI in this method.
- */
- public void onFacebookError(FacebookError e, Object state);
-
- }
-
-}
diff --git a/facebook/facebook/src/com/facebook/android/DialogError.java b/facebook/facebook/src/com/facebook/android/DialogError.java
deleted file mode 100644
index a99c4e613..000000000
--- a/facebook/facebook/src/com/facebook/android/DialogError.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Copyright 2010-present Facebook
- *
- * 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 com.facebook.android;
-
-/**
- * Encapsulation of Dialog Error.
- *
- * THIS CLASS SHOULD BE CONSIDERED DEPRECATED.
- *
- * All public members of this class are intentionally deprecated.
- * New code should instead use
- * {@link com.facebook.FacebookException}
- *
- * Adding @Deprecated to this class causes warnings in other deprecated classes
- * that reference this one. That is the only reason this entire class is not
- * deprecated.
- *
- * @devDocDeprecated
- */
-public class DialogError extends Throwable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * The ErrorCode received by the WebView: see
- * http://developer.android.com/reference/android/webkit/WebViewClient.html
- */
- private int mErrorCode;
-
- /** The URL that the dialog was trying to load */
- private String mFailingUrl;
-
- @Deprecated
- public DialogError(String message, int errorCode, String failingUrl) {
- super(message);
- mErrorCode = errorCode;
- mFailingUrl = failingUrl;
- }
-
- @Deprecated
- public int getErrorCode() {
- return mErrorCode;
- }
-
- @Deprecated
- public String getFailingUrl() {
- return mFailingUrl;
- }
-
-}
diff --git a/facebook/facebook/src/com/facebook/android/Facebook.java b/facebook/facebook/src/com/facebook/android/Facebook.java
deleted file mode 100644
index 2b439e7d7..000000000
--- a/facebook/facebook/src/com/facebook/android/Facebook.java
+++ /dev/null
@@ -1,1357 +0,0 @@
-/**
- * Copyright 2010-present Facebook
- *
- * 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 com.facebook.android;
-
-import android.Manifest;
-import android.app.Activity;
-import android.content.*;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.Signature;
-import android.net.Uri;
-import android.os.*;
-import com.facebook.*;
-import com.facebook.Session.StatusCallback;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.ref.WeakReference;
-import java.net.MalformedURLException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * THIS CLASS SHOULD BE CONSIDERED DEPRECATED.
- *
- * All public members of this class are intentionally deprecated.
- * New code should instead use
- * {@link Session} to manage session state,
- * {@link Request} to make API requests, and
- * {@link com.facebook.widget.WebDialog} to make dialog requests.
- *
- * Adding @Deprecated to this class causes warnings in other deprecated classes
- * that reference this one. That is the only reason this entire class is not
- * deprecated.
- *
- * @devDocDeprecated
- */
-public class Facebook {
-
- // Strings used in the authorization flow
- @Deprecated
- public static final String REDIRECT_URI = "fbconnect://success";
- @Deprecated
- public static final String CANCEL_URI = "fbconnect://cancel";
- @Deprecated
- public static final String TOKEN = "access_token";
- @Deprecated
- public static final String EXPIRES = "expires_in";
- @Deprecated
- public static final String SINGLE_SIGN_ON_DISABLED = "service_disabled";
-
- @Deprecated
- public static final Uri ATTRIBUTION_ID_CONTENT_URI =
- Uri.parse("content://com.facebook.katana.provider.AttributionIdProvider");
- @Deprecated
- public static final String ATTRIBUTION_ID_COLUMN_NAME = "aid";
-
- @Deprecated
- public static final int FORCE_DIALOG_AUTH = -1;
-
- private static final String LOGIN = "oauth";
-
- // Used as default activityCode by authorize(). See authorize() below.
- private static final int DEFAULT_AUTH_ACTIVITY_CODE = 32665;
-
- // Facebook server endpoints: may be modified in a subclass for testing
- @Deprecated
- protected static String DIALOG_BASE_URL = "https://m.facebook.com/dialog/";
- @Deprecated
- protected static String GRAPH_BASE_URL = "https://graph.facebook.com/";
- @Deprecated
- protected static String RESTSERVER_URL = "https://api.facebook.com/restserver.php";
-
- private final Object lock = new Object();
-
- private String accessToken = null;
- private long accessExpiresMillisecondsAfterEpoch = 0;
- private long lastAccessUpdateMillisecondsAfterEpoch = 0;
- private String mAppId;
-
- private Activity pendingAuthorizationActivity;
- private String[] pendingAuthorizationPermissions;
- private Session pendingOpeningSession;
-
- private volatile Session session; // must synchronize this.sync to write
- private boolean sessionInvalidated; // must synchronize this.sync to access
- private SetterTokenCachingStrategy tokenCache;
- private volatile Session userSetSession;
-
- // If the last time we extended the access token was more than 24 hours ago
- // we try to refresh the access token again.
- final private long REFRESH_TOKEN_BARRIER = 24L * 60L * 60L * 1000L;
-
- /**
- * Constructor for Facebook object.
- *
- * @param appId
- * Your Facebook application ID. Found at
- * www.facebook.com/developers/apps.php.
- */
- @Deprecated
- public Facebook(String appId) {
- if (appId == null) {
- throw new IllegalArgumentException("You must specify your application ID when instantiating "
- + "a Facebook object. See README for details.");
- }
- mAppId = appId;
- }
-
- /**
- * Default authorize method. Grants only basic permissions.
- *
- * See authorize() below for @params.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- */
- @Deprecated
- public void authorize(Activity activity, final DialogListener listener) {
- authorize(activity, new String[]{}, DEFAULT_AUTH_ACTIVITY_CODE, SessionLoginBehavior.SSO_WITH_FALLBACK,
- listener);
- }
-
- /**
- * Authorize method that grants custom permissions.
- *
- * See authorize() below for @params.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- */
- @Deprecated
- public void authorize(Activity activity, String[] permissions, final DialogListener listener) {
- authorize(activity, permissions, DEFAULT_AUTH_ACTIVITY_CODE, SessionLoginBehavior.SSO_WITH_FALLBACK, listener);
- }
-
- /**
- * Full authorize method.
- *
- * Starts either an Activity or a dialog which prompts the user to log in to
- * Facebook and grant the requested permissions to the given application.
- *
- * This method will, when possible, use Facebook's single sign-on for
- * Android to obtain an access token. This involves proxying a call through
- * the Facebook for Android stand-alone application, which will handle the
- * authentication flow, and return an OAuth access token for making API
- * calls.
- *
- * Because this process will not be available for all users, if single
- * sign-on is not possible, this method will automatically fall back to the
- * OAuth 2.0 User-Agent flow. In this flow, the user credentials are handled
- * by Facebook in an embedded WebView, not by the client application. As
- * such, the dialog makes a network request and renders HTML content rather
- * than a native UI. The access token is retrieved from a redirect to a
- * special URL that the WebView handles.
- *
- * Note that User credentials could be handled natively using the OAuth 2.0
- * Username and Password Flow, but this is not supported by this SDK.
- *
- * See http://developers.facebook.com/docs/authentication/ and
- * http://wiki.oauth.net/OAuth-2 for more details.
- *
- * Note that this method is asynchronous and the callback will be invoked in
- * the original calling thread (not in a background thread).
- *
- * Also note that requests may be made to the API without calling authorize
- * first, in which case only public information is returned.
- *
- * IMPORTANT: Note that single sign-on authentication will not function
- * correctly if you do not include a call to the authorizeCallback() method
- * in your onActivityResult() function! Please see below for more
- * information. single sign-on may be disabled by passing FORCE_DIALOG_AUTH
- * as the activityCode parameter in your call to authorize().
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param activity
- * The Android activity in which we want to display the
- * authorization dialog.
- * @param permissions
- * A list of permissions required for this application: e.g.
- * "read_stream", "publish_stream", "offline_access", etc. see
- * http://developers.facebook.com/docs/authentication/permissions
- * This parameter should not be null -- if you do not require any
- * permissions, then pass in an empty String array.
- * @param activityCode
- * Single sign-on requires an activity result to be called back
- * to the client application -- if you are waiting on other
- * activities to return data, pass a custom activity code here to
- * avoid collisions. If you would like to force the use of legacy
- * dialog-based authorization, pass FORCE_DIALOG_AUTH for this
- * parameter. Otherwise just omit this parameter and Facebook
- * will use a suitable default. See
- * http://developer.android.com/reference/android/
- * app/Activity.html for more information.
- * @param listener
- * Callback interface for notifying the calling application when
- * the authentication dialog has completed, failed, or been
- * canceled.
- */
- @Deprecated
- public void authorize(Activity activity, String[] permissions, int activityCode, final DialogListener listener) {
- SessionLoginBehavior behavior = (activityCode >= 0) ? SessionLoginBehavior.SSO_WITH_FALLBACK
- : SessionLoginBehavior.SUPPRESS_SSO;
-
- authorize(activity, permissions, activityCode, behavior, listener);
- }
-
- /**
- * Full authorize method.
- *
- * Starts either an Activity or a dialog which prompts the user to log in to
- * Facebook and grant the requested permissions to the given application.
- *
- * This method will, when possible, use Facebook's single sign-on for
- * Android to obtain an access token. This involves proxying a call through
- * the Facebook for Android stand-alone application, which will handle the
- * authentication flow, and return an OAuth access token for making API
- * calls.
- *
- * Because this process will not be available for all users, if single
- * sign-on is not possible, this method will automatically fall back to the
- * OAuth 2.0 User-Agent flow. In this flow, the user credentials are handled
- * by Facebook in an embedded WebView, not by the client application. As
- * such, the dialog makes a network request and renders HTML content rather
- * than a native UI. The access token is retrieved from a redirect to a
- * special URL that the WebView handles.
- *
- * Note that User credentials could be handled natively using the OAuth 2.0
- * Username and Password Flow, but this is not supported by this SDK.
- *
- * See http://developers.facebook.com/docs/authentication/ and
- * http://wiki.oauth.net/OAuth-2 for more details.
- *
- * Note that this method is asynchronous and the callback will be invoked in
- * the original calling thread (not in a background thread).
- *
- * Also note that requests may be made to the API without calling authorize
- * first, in which case only public information is returned.
- *
- * IMPORTANT: Note that single sign-on authentication will not function
- * correctly if you do not include a call to the authorizeCallback() method
- * in your onActivityResult() function! Please see below for more
- * information. single sign-on may be disabled by passing FORCE_DIALOG_AUTH
- * as the activityCode parameter in your call to authorize().
- *
- * @param activity
- * The Android activity in which we want to display the
- * authorization dialog.
- * @param permissions
- * A list of permissions required for this application: e.g.
- * "read_stream", "publish_stream", "offline_access", etc. see
- * http://developers.facebook.com/docs/authentication/permissions
- * This parameter should not be null -- if you do not require any
- * permissions, then pass in an empty String array.
- * @param activityCode
- * Single sign-on requires an activity result to be called back
- * to the client application -- if you are waiting on other
- * activities to return data, pass a custom activity code here to
- * avoid collisions. If you would like to force the use of legacy
- * dialog-based authorization, pass FORCE_DIALOG_AUTH for this
- * parameter. Otherwise just omit this parameter and Facebook
- * will use a suitable default. See
- * http://developer.android.com/reference/android/
- * app/Activity.html for more information.
- * @param behavior
- * The {@link SessionLoginBehavior SessionLoginBehavior} that
- * specifies what behaviors should be attempted during
- * authorization.
- * @param listener
- * Callback interface for notifying the calling application when
- * the authentication dialog has completed, failed, or been
- * canceled.
- */
- private void authorize(Activity activity, String[] permissions, int activityCode,
- SessionLoginBehavior behavior, final DialogListener listener) {
- checkUserSession("authorize");
- pendingOpeningSession = new Session.Builder(activity).
- setApplicationId(mAppId).
- setTokenCachingStrategy(getTokenCache()).
- build();
- pendingAuthorizationActivity = activity;
- pendingAuthorizationPermissions = (permissions != null) ? permissions : new String[0];
-
- StatusCallback callback = new StatusCallback() {
- @Override
- public void call(Session callbackSession, SessionState state, Exception exception) {
- // Invoke user-callback.
- onSessionCallback(callbackSession, state, exception, listener);
- }
- };
-
- Session.OpenRequest openRequest = new Session.OpenRequest(activity).
- setCallback(callback).
- setLoginBehavior(behavior).
- setRequestCode(activityCode).
- setPermissions(Arrays.asList(permissions));
- openSession(pendingOpeningSession, openRequest, pendingAuthorizationPermissions.length > 0);
- }
-
- private void openSession(Session session, Session.OpenRequest openRequest, boolean isPublish) {
- openRequest.setIsLegacy(true);
- if (isPublish) {
- session.openForPublish(openRequest);
- } else {
- session.openForRead(openRequest);
- }
- }
-
- @SuppressWarnings("deprecation")
- private void onSessionCallback(Session callbackSession, SessionState state, Exception exception,
- DialogListener listener) {
- Bundle extras = callbackSession.getAuthorizationBundle();
-
- if (state == SessionState.OPENED) {
- Session sessionToClose = null;
-
- synchronized (Facebook.this.lock) {
- if (callbackSession != Facebook.this.session) {
- sessionToClose = Facebook.this.session;
- Facebook.this.session = callbackSession;
- Facebook.this.sessionInvalidated = false;
- }
- }
-
- if (sessionToClose != null) {
- sessionToClose.close();
- }
-
- listener.onComplete(extras);
- } else if (exception != null) {
- if (exception instanceof FacebookOperationCanceledException) {
- listener.onCancel();
- } else if ((exception instanceof FacebookAuthorizationException) && (extras != null)
- && extras.containsKey(Session.WEB_VIEW_ERROR_CODE_KEY)
- && extras.containsKey(Session.WEB_VIEW_FAILING_URL_KEY)) {
- DialogError error = new DialogError(exception.getMessage(),
- extras.getInt(Session.WEB_VIEW_ERROR_CODE_KEY),
- extras.getString(Session.WEB_VIEW_FAILING_URL_KEY));
- listener.onError(error);
- } else {
- FacebookError error = new FacebookError(exception.getMessage());
- listener.onFacebookError(error);
- }
- }
- }
-
- /**
- * Helper to validate a service intent by resolving and checking the
- * provider's package signature.
- *
- * @param context
- * @param intent
- * @return true if the service intent resolution happens successfully and
- * the signatures match.
- */
- private boolean validateServiceIntent(Context context, Intent intent) {
- ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, 0);
- if (resolveInfo == null) {
- return false;
- }
-
- return validateAppSignatureForPackage(context, resolveInfo.serviceInfo.packageName);
- }
-
- /**
- * Query the signature for the application that would be invoked by the
- * given intent and verify that it matches the FB application's signature.
- *
- * @param context
- * @param packageName
- * @return true if the app's signature matches the expected signature.
- */
- private boolean validateAppSignatureForPackage(Context context, String packageName) {
-
- PackageInfo packageInfo;
- try {
- packageInfo = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- return false;
- }
-
- for (Signature signature : packageInfo.signatures) {
- if (signature.toCharsString().equals(FB_APP_SIGNATURE)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * IMPORTANT: If you are using the deprecated authorize() method,
- * 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)
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- */
- @Deprecated
- public void authorizeCallback(int requestCode, int resultCode, Intent data) {
- checkUserSession("authorizeCallback");
- Session pending = this.pendingOpeningSession;
- if (pending != null) {
- if (pending.onActivityResult(this.pendingAuthorizationActivity, requestCode, resultCode, data)) {
- this.pendingOpeningSession = null;
- this.pendingAuthorizationActivity = null;
- this.pendingAuthorizationPermissions = null;
- }
- }
- }
-
- /**
- * Refresh OAuth access token method. Binds to Facebook for Android
- * stand-alone application application to refresh the access token. This
- * method tries to connect to the Facebook App which will handle the
- * authentication flow, and return a new OAuth access token. This method
- * will automatically replace the old token with a new one. Note that this
- * method is asynchronous and the callback will be invoked in the original
- * calling thread (not in a background thread).
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param context
- * The Android Context that will be used to bind to the Facebook
- * RefreshToken Service
- * @param serviceListener
- * Callback interface for notifying the calling application when
- * the refresh request has completed or failed (can be null). In
- * case of a success a new token can be found inside the result
- * Bundle under Facebook.ACCESS_TOKEN key.
- * @return true if the binding to the RefreshToken Service was created
- */
- @Deprecated
- public boolean extendAccessToken(Context context, ServiceListener serviceListener) {
- checkUserSession("extendAccessToken");
- Intent intent = new Intent();
-
- intent.setClassName("com.facebook.katana", "com.facebook.katana.platform.TokenRefreshService");
-
- // Verify that the application whose package name is
- // com.facebook.katana
- // has the expected FB app signature.
- if (!validateServiceIntent(context, intent)) {
- return false;
- }
-
- return context.bindService(intent, new TokenRefreshServiceConnection(context, serviceListener),
- Context.BIND_AUTO_CREATE);
- }
-
- /**
- * Calls extendAccessToken if shouldExtendAccessToken returns true.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @return the same value as extendAccessToken if the the token requires
- * refreshing, true otherwise
- */
- @Deprecated
- public boolean extendAccessTokenIfNeeded(Context context, ServiceListener serviceListener) {
- checkUserSession("extendAccessTokenIfNeeded");
- if (shouldExtendAccessToken()) {
- return extendAccessToken(context, serviceListener);
- }
- return true;
- }
-
- /**
- * Check if the access token requires refreshing.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @return true if the last time a new token was obtained was over 24 hours
- * ago.
- */
- @Deprecated
- public boolean shouldExtendAccessToken() {
- checkUserSession("shouldExtendAccessToken");
- return isSessionValid()
- && (System.currentTimeMillis() - lastAccessUpdateMillisecondsAfterEpoch >= REFRESH_TOKEN_BARRIER);
- }
-
- /**
- * Handles connection to the token refresh service (this service is a part
- * of Facebook App).
- */
- private class TokenRefreshServiceConnection implements ServiceConnection {
-
- final Messenger messageReceiver = new Messenger(
- new TokenRefreshConnectionHandler(Facebook.this, this));
-
- final ServiceListener serviceListener;
- final Context applicationsContext;
-
- Messenger messageSender = null;
-
- public TokenRefreshServiceConnection(Context applicationsContext, ServiceListener serviceListener) {
- this.applicationsContext = applicationsContext;
- this.serviceListener = serviceListener;
- }
-
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- messageSender = new Messenger(service);
- refreshToken();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName arg) {
- serviceListener.onError(new Error("Service disconnected"));
- // We returned an error so there's no point in
- // keeping the binding open.
- applicationsContext.unbindService(TokenRefreshServiceConnection.this);
- }
-
- private void refreshToken() {
- Bundle requestData = new Bundle();
- requestData.putString(TOKEN, accessToken);
-
- Message request = Message.obtain();
- request.setData(requestData);
- request.replyTo = messageReceiver;
-
- try {
- messageSender.send(request);
- } catch (RemoteException e) {
- serviceListener.onError(new Error("Service connection error"));
- }
- }
- }
-
- // Creating a static Handler class to reduce the possibility of a memory leak.
- // Handler objects for the same thread all share a common Looper object, which they post messages
- // to and read from. As messages contain target Handler, as long as there are messages with target
- // handler in the message queue, the handler cannot be garbage collected. If handler is not static,
- // the instance of the containing class also cannot be garbage collected even if it is destroyed.
- private static class TokenRefreshConnectionHandler extends Handler {
- WeakReference facebookWeakReference;
- WeakReference connectionWeakReference;
-
- TokenRefreshConnectionHandler(Facebook facebook, TokenRefreshServiceConnection connection) {
- super();
- facebookWeakReference = new WeakReference(facebook);
- connectionWeakReference = new WeakReference(connection);
- }
-
- @Override
- @SuppressWarnings("deprecation")
- public void handleMessage(Message msg) {
- Facebook facebook = facebookWeakReference.get();
- TokenRefreshServiceConnection connection = connectionWeakReference.get();
- if (facebook == null || connection == null) {
- return;
- }
-
- String token = msg.getData().getString(TOKEN);
- // Legacy functions in Facebook class (and ServiceListener implementors) expect expires_in in
- // milliseconds from epoch
- long expiresAtMsecFromEpoch = msg.getData().getLong(EXPIRES) * 1000L;
-
- if (token != null) {
- facebook.setAccessToken(token);
- facebook.setAccessExpires(expiresAtMsecFromEpoch);
-
- Session refreshSession = facebook.session;
- if (refreshSession != null) {
- // Session.internalRefreshToken expects the original bundle with expires_in in seconds from
- // epoch.
- LegacyHelper.extendTokenCompleted(refreshSession, msg.getData());
- }
-
- if (connection.serviceListener != null) {
- // To avoid confusion we should return the expiration time in
- // the same format as the getAccessExpires() function - that
- // is in milliseconds.
- Bundle resultBundle = (Bundle) msg.getData().clone();
- resultBundle.putLong(EXPIRES, expiresAtMsecFromEpoch);
-
- connection.serviceListener.onComplete(resultBundle);
- }
- } else if (connection.serviceListener != null) { // extract errors only if
- // client wants them
- String error = msg.getData().getString("error");
- if (msg.getData().containsKey("error_code")) {
- int errorCode = msg.getData().getInt("error_code");
- connection.serviceListener.onFacebookError(new FacebookError(error, null, errorCode));
- } else {
- connection.serviceListener.onError(new Error(error != null ? error : "Unknown service error"));
- }
- }
-
- if (connection != null) {
- // The refreshToken function should be called rarely,
- // so there is no point in keeping the binding open.
- connection.applicationsContext.unbindService(connection);
- }
- }
- }
-
- /**
- * Invalidate the current user session by removing the access token in
- * memory, clearing the browser cookie, and calling auth.expireSession
- * through the API.
- *
- * Note that this method blocks waiting for a network response, so do not
- * call it in a UI thread.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param context
- * The Android context in which the logout should be called: it
- * should be the same context in which the login occurred in
- * order to clear any stored cookies
- * @throws IOException
- * @throws MalformedURLException
- * @return JSON string representation of the auth.expireSession response
- * ("true" if successful)
- */
- @Deprecated
- public String logout(Context context) throws MalformedURLException, IOException {
- return logoutImpl(context);
- }
-
- String logoutImpl(Context context) throws MalformedURLException, IOException {
- checkUserSession("logout");
- Bundle b = new Bundle();
- b.putString("method", "auth.expireSession");
- String response = request(b);
-
- long currentTimeMillis = System.currentTimeMillis();
- Session sessionToClose = null;
-
- synchronized (this.lock) {
- sessionToClose = session;
-
- session = null;
- accessToken = null;
- accessExpiresMillisecondsAfterEpoch = 0;
- lastAccessUpdateMillisecondsAfterEpoch = currentTimeMillis;
- sessionInvalidated = false;
- }
-
- if (sessionToClose != null) {
- sessionToClose.closeAndClearTokenInformation();
- }
-
- return response;
- }
-
- /**
- * Make a request to Facebook's old (pre-graph) API with the given
- * parameters. One of the parameter keys must be "method" and its value
- * should be a valid REST server API method.
- *
- * See http://developers.facebook.com/docs/reference/rest/
- *
- * Note that this method blocks waiting for a network response, so do not
- * call it in a UI thread.
- *
- * Example:
- * Bundle parameters = new Bundle();
- * parameters.putString("method", "auth.expireSession");
- * String response = request(parameters);
- *
- *
- * This method is deprecated. See {@link Facebook} and {@link Request} for more info.
- *
- * @param parameters
- * Key-value pairs of parameters to the request. Refer to the
- * documentation: one of the parameters must be "method".
- * @throws IOException
- * if a network error occurs
- * @throws MalformedURLException
- * if accessing an invalid endpoint
- * @throws IllegalArgumentException
- * if one of the parameters is not "method"
- * @return JSON string representation of the response
- */
- @Deprecated
- public String request(Bundle parameters) throws MalformedURLException, IOException {
- if (!parameters.containsKey("method")) {
- throw new IllegalArgumentException("API method must be specified. "
- + "(parameters must contain key \"method\" and value). See"
- + " http://developers.facebook.com/docs/reference/rest/");
- }
- return requestImpl(null, parameters, "GET");
- }
-
- /**
- * Make a request to the Facebook Graph API without any parameters.
- *
- * See http://developers.facebook.com/docs/api
- *
- * Note that this method blocks waiting for a network response, so do not
- * call it in a UI thread.
- *
- * This method is deprecated. See {@link Facebook} and {@link Request} for more info.
- *
- * @param graphPath
- * Path to resource in the Facebook graph, e.g., to fetch data
- * about the currently logged authenticated user, provide "me",
- * which will fetch http://graph.facebook.com/me
- * @throws IOException
- * @throws MalformedURLException
- * @return JSON string representation of the response
- */
- @Deprecated
- public String request(String graphPath) throws MalformedURLException, IOException {
- return requestImpl(graphPath, new Bundle(), "GET");
- }
-
- /**
- * Make a request to the Facebook Graph API with the given string parameters
- * using an HTTP GET (default method).
- *
- * See http://developers.facebook.com/docs/api
- *
- * Note that this method blocks waiting for a network response, so do not
- * call it in a UI thread.
- *
- * This method is deprecated. See {@link Facebook} and {@link Request} for more info.
- *
- * @param graphPath
- * Path to resource in the Facebook graph, e.g., to fetch data
- * about the currently logged authenticated user, provide "me",
- * which will fetch http://graph.facebook.com/me
- * @param parameters
- * key-value string parameters, e.g. the path "search" with
- * parameters "q" : "facebook" would produce a query for the
- * following graph resource:
- * https://graph.facebook.com/search?q=facebook
- * @throws IOException
- * @throws MalformedURLException
- * @return JSON string representation of the response
- */
- @Deprecated
- public String request(String graphPath, Bundle parameters) throws MalformedURLException, IOException {
- return requestImpl(graphPath, parameters, "GET");
- }
-
- /**
- * Synchronously make a request to the Facebook Graph API with the given
- * HTTP method and string parameters. Note that binary data parameters (e.g.
- * pictures) are not yet supported by this helper function.
- *
- * See http://developers.facebook.com/docs/api
- *
- * Note that this method blocks waiting for a network response, so do not
- * call it in a UI thread.
- *
- * This method is deprecated. See {@link Facebook} and {@link Request} for more info.
- *
- * @param graphPath
- * Path to resource in the Facebook graph, e.g., to fetch data
- * about the currently logged authenticated user, provide "me",
- * which will fetch http://graph.facebook.com/me
- * @param params
- * Key-value string parameters, e.g. the path "search" with
- * parameters {"q" : "facebook"} would produce a query for the
- * following graph resource:
- * https://graph.facebook.com/search?q=facebook
- * @param httpMethod
- * http verb, e.g. "GET", "POST", "DELETE"
- * @throws IOException
- * @throws MalformedURLException
- * @return JSON string representation of the response
- */
- @Deprecated
- public String request(String graphPath, Bundle params, String httpMethod) throws FileNotFoundException,
- MalformedURLException, IOException {
- return requestImpl(graphPath, params, httpMethod);
- }
-
- // Internal call to avoid deprecated warnings.
- @SuppressWarnings("deprecation")
- String requestImpl(String graphPath, Bundle params, String httpMethod) throws FileNotFoundException,
- MalformedURLException, IOException {
- params.putString("format", "json");
- if (isSessionValid()) {
- params.putString(TOKEN, getAccessToken());
- }
- String url = (graphPath != null) ? GRAPH_BASE_URL + graphPath : RESTSERVER_URL;
- return Util.openUrl(url, httpMethod, params);
- }
-
- /**
- * Generate a UI dialog for the request action in the given Android context.
- *
- * Note that this method is asynchronous and the callback will be invoked in
- * the original calling thread (not in a background thread).
- *
- * This method is deprecated. See {@link com.facebook.widget.WebDialog}.
- *
- * @param context
- * The Android context in which we will generate this dialog.
- * @param action
- * String representation of the desired method: e.g. "login",
- * "stream.publish", ...
- * @param listener
- * Callback interface to notify the application when the dialog
- * has completed.
- */
- @Deprecated
- public void dialog(Context context, String action, DialogListener listener) {
- dialog(context, action, new Bundle(), listener);
- }
-
- /**
- * Generate a UI dialog for the request action in the given Android context
- * with the provided parameters.
- *
- * Note that this method is asynchronous and the callback will be invoked in
- * the original calling thread (not in a background thread).
- *
- * This method is deprecated. See {@link com.facebook.widget.WebDialog}.
- *
- * @param context
- * The Android context in which we will generate this dialog.
- * @param action
- * String representation of the desired method: e.g. "feed" ...
- * @param parameters
- * String key-value pairs to be passed as URL parameters.
- * @param listener
- * Callback interface to notify the application when the dialog
- * has completed.
- */
- @Deprecated
- public void dialog(Context context, String action, Bundle parameters, final DialogListener listener) {
- parameters.putString("display", "touch");
- parameters.putString("redirect_uri", REDIRECT_URI);
-
- if (action.equals(LOGIN)) {
- parameters.putString("type", "user_agent");
- parameters.putString("client_id", mAppId);
- } else {
- parameters.putString("app_id", mAppId);
- // We do not want to add an access token when displaying the auth dialog.
- if (isSessionValid()) {
- parameters.putString(TOKEN, getAccessToken());
- }
- }
-
- if (context.checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
- Util.showAlert(context, "Error", "Application requires permission to access the Internet");
- } else {
- new FbDialog(context, action, parameters, listener).show();
- }
- }
-
- /**
- * Returns whether the current access token is valid
- *
- * @return boolean - whether this object has an non-expired session token
- */
- @Deprecated
- public boolean isSessionValid() {
- return (getAccessToken() != null)
- && ((getAccessExpires() == 0) || (System.currentTimeMillis() < getAccessExpires()));
- }
-
- /**
- * Allows the user to set a Session for the Facebook class to use.
- * If a Session is set here, then one should not use the authorize, logout,
- * or extendAccessToken methods which alter the Session object since that may
- * result in undefined behavior. Using those methods after setting the
- * session here will result in exceptions being thrown.
- *
- * @param session the Session object to use, cannot be null
- */
- @Deprecated
- public void setSession(Session session) {
- if (session == null) {
- throw new IllegalArgumentException("session cannot be null");
- }
- synchronized (this.lock) {
- this.userSetSession = session;
- }
- }
-
- private void checkUserSession(String methodName) {
- if (userSetSession != null) {
- throw new UnsupportedOperationException(
- String.format("Cannot call %s after setSession has been called.", methodName));
- }
- }
-
- /**
- * Get the underlying Session object to use with 3.0 api.
- *
- * @return Session - underlying session
- */
- @Deprecated
- public final Session getSession() {
- while (true) {
- String cachedToken = null;
- Session oldSession = null;
-
- synchronized (this.lock) {
- if (userSetSession != null) {
- return userSetSession;
- }
- if ((session != null) || !sessionInvalidated) {
- return session;
- }
-
- cachedToken = accessToken;
- oldSession = session;
- }
-
- if (cachedToken == null) {
- return null;
- }
-
- // At this point we do not have a valid session, but mAccessToken is
- // non-null.
- // So we can try building a session based on that.
- List permissions;
- if (oldSession != null) {
- permissions = oldSession.getPermissions();
- } else if (pendingAuthorizationPermissions != null) {
- permissions = Arrays.asList(pendingAuthorizationPermissions);
- } else {
- permissions = Collections.emptyList();
- }
-
- Session newSession = new Session.Builder(pendingAuthorizationActivity).
- setApplicationId(mAppId).
- setTokenCachingStrategy(getTokenCache()).
- build();
- if (newSession.getState() != SessionState.CREATED_TOKEN_LOADED) {
- return null;
- }
- Session.OpenRequest openRequest =
- new Session.OpenRequest(pendingAuthorizationActivity).setPermissions(permissions);
- openSession(newSession, openRequest, !permissions.isEmpty());
-
- Session invalidatedSession = null;
- Session returnSession = null;
-
- synchronized (this.lock) {
- if (sessionInvalidated || (session == null)) {
- invalidatedSession = session;
- returnSession = session = newSession;
- sessionInvalidated = false;
- }
- }
-
- if (invalidatedSession != null) {
- invalidatedSession.close();
- }
-
- if (returnSession != null) {
- return returnSession;
- }
- // Else token state changed between the synchronized blocks, so
- // retry..
- }
- }
-
- /**
- * Retrieve the OAuth 2.0 access token for API access: treat with care.
- * Returns null if no session exists.
- *
- * @return String - access token
- */
- @Deprecated
- public String getAccessToken() {
- Session s = getSession();
- if (s != null) {
- return s.getAccessToken();
- } else {
- return null;
- }
- }
-
- /**
- * Retrieve the current session's expiration time (in milliseconds since
- * Unix epoch), or 0 if the session doesn't expire or doesn't exist.
- *
- * @return long - session expiration time
- */
- @Deprecated
- public long getAccessExpires() {
- Session s = getSession();
- if (s != null) {
- return s.getExpirationDate().getTime();
- } else {
- return accessExpiresMillisecondsAfterEpoch;
- }
- }
-
- /**
- * Retrieve the last time the token was updated (in milliseconds since
- * the Unix epoch), or 0 if the token has not been set.
- *
- * @return long - timestamp of the last token update.
- */
- @Deprecated
- public long getLastAccessUpdate() {
- return lastAccessUpdateMillisecondsAfterEpoch;
- }
-
- /**
- * Restore the token, expiration time, and last update time from cached values.
- * These should be values obtained from getAccessToken(), getAccessExpires, and
- * getLastAccessUpdate() respectively.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param accessToken - access token
- * @param accessExpires - access token expiration time
- * @param lastAccessUpdate - timestamp of the last token update
- */
- @Deprecated
- public void setTokenFromCache(String accessToken, long accessExpires, long lastAccessUpdate) {
- checkUserSession("setTokenFromCache");
- synchronized (this.lock) {
- this.accessToken = accessToken;
- accessExpiresMillisecondsAfterEpoch = accessExpires;
- lastAccessUpdateMillisecondsAfterEpoch = lastAccessUpdate;
- }
- }
-
- /**
- * Set the OAuth 2.0 access token for API access.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param token
- * - access token
- */
- @Deprecated
- public void setAccessToken(String token) {
- checkUserSession("setAccessToken");
- synchronized (this.lock) {
- accessToken = token;
- lastAccessUpdateMillisecondsAfterEpoch = System.currentTimeMillis();
- sessionInvalidated = true;
- }
- }
-
- /**
- * Set the current session's expiration time (in milliseconds since Unix
- * epoch), or 0 if the session doesn't expire.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param timestampInMsec
- * - timestamp in milliseconds
- */
- @Deprecated
- public void setAccessExpires(long timestampInMsec) {
- checkUserSession("setAccessExpires");
- synchronized (this.lock) {
- accessExpiresMillisecondsAfterEpoch = timestampInMsec;
- lastAccessUpdateMillisecondsAfterEpoch = System.currentTimeMillis();
- sessionInvalidated = true;
- }
- }
-
- /**
- * Set the current session's duration (in seconds since Unix epoch), or "0"
- * if session doesn't expire.
- *
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param expiresInSecsFromNow
- * - duration in seconds (or 0 if the session doesn't expire)
- */
- @Deprecated
- public void setAccessExpiresIn(String expiresInSecsFromNow) {
- checkUserSession("setAccessExpiresIn");
- if (expiresInSecsFromNow != null) {
- long expires = expiresInSecsFromNow.equals("0") ? 0 : System.currentTimeMillis()
- + Long.parseLong(expiresInSecsFromNow) * 1000L;
- setAccessExpires(expires);
- }
- }
-
- /**
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @return the String representing application ID
- */
- @Deprecated
- public String getAppId() {
- return mAppId;
- }
-
- /**
- * This method is deprecated. See {@link Facebook} and {@link Session} for more info.
- *
- * @param appId the String representing the application ID
- */
- @Deprecated
- public void setAppId(String appId) {
- checkUserSession("setAppId");
- synchronized (this.lock) {
- mAppId = appId;
- sessionInvalidated = true;
- }
- }
-
- private TokenCachingStrategy getTokenCache() {
- // Intentionally not volatile/synchronized--it is okay if we race to
- // create more than one of these.
- if (tokenCache == null) {
- tokenCache = new SetterTokenCachingStrategy();
- }
- return tokenCache;
- }
-
- private static String[] stringArray(List list) {
- String[] array = new String[list.size()];
-
- if (list != null) {
- for (int i = 0; i < array.length; i++) {
- array[i] = list.get(i);
- }
- }
-
- return array;
- }
-
- private static List stringList(String[] array) {
- if (array != null) {
- return Arrays.asList(array);
- } else {
- return Collections.emptyList();
- }
- }
-
- private class SetterTokenCachingStrategy extends TokenCachingStrategy {
-
- @Override
- public Bundle load() {
- Bundle bundle = new Bundle();
-
- if (accessToken != null) {
- TokenCachingStrategy.putToken(bundle, accessToken);
- TokenCachingStrategy.putExpirationMilliseconds(bundle, accessExpiresMillisecondsAfterEpoch);
- TokenCachingStrategy.putPermissions(bundle, stringList(pendingAuthorizationPermissions));
- TokenCachingStrategy.putSource(bundle, AccessTokenSource.WEB_VIEW);
- TokenCachingStrategy.putLastRefreshMilliseconds(bundle, lastAccessUpdateMillisecondsAfterEpoch);
- }
-
- return bundle;
- }
-
- @Override
- public void save(Bundle bundle) {
- accessToken = TokenCachingStrategy.getToken(bundle);
- accessExpiresMillisecondsAfterEpoch = TokenCachingStrategy.getExpirationMilliseconds(bundle);
- pendingAuthorizationPermissions = stringArray(TokenCachingStrategy.getPermissions(bundle));
- lastAccessUpdateMillisecondsAfterEpoch = TokenCachingStrategy.getLastRefreshMilliseconds(bundle);
- }
-
- @Override
- public void clear() {
- accessToken = null;
- }
- }
-
- /**
- * Get Attribution ID for app install conversion tracking.
- *
- * This method is deprecated. See {@link Facebook} and {@link Settings} for more info.
- *
- * @param contentResolver
- * @return Attribution ID that will be used for conversion tracking. It will be null only if
- * the user has not installed or logged in to the Facebook app.
- */
- @Deprecated
- public static String getAttributionId(ContentResolver contentResolver) {
- return Settings.getAttributionId(contentResolver);
- }
-
- /**
- * Get the auto install publish setting. If true, an install event will be published during authorize(), unless
- * it has occurred previously or the app does not have install attribution enabled on the application's developer
- * config page.
- *
- * This method is deprecated. See {@link Facebook} and {@link Settings} for more info.
- *
- * @return a Boolean indicating whether installation of the app should be auto-published.
- */
- @Deprecated
- public boolean getShouldAutoPublishInstall() {
- return Settings.getShouldAutoPublishInstall();
- }
-
- /**
- * Sets whether auto publishing of installs will occur.
- *
- * This method is deprecated. See {@link Facebook} and {@link Settings} for more info.
- *
- * @param value a Boolean indicating whether installation of the app should be auto-published.
- */
- @Deprecated
- public void setShouldAutoPublishInstall(boolean value) {
- Settings.setShouldAutoPublishInstall(value);
- }
-
- /**
- * Manually publish install attribution to the Facebook graph. Internally handles tracking repeat calls to prevent
- * multiple installs being published to the graph.
- *
- * This method is deprecated. See {@link Facebook} and {@link Settings} for more info.
- *
- * @param context the current Android context
- * @return Always false. Earlier versions of the API returned true if it was no longer necessary to call.
- * Apps should ignore this value, but for compatibility we will return false to ensure repeat calls (and the
- * underlying code will prevent duplicate network traffic).
- */
- @Deprecated
- public boolean publishInstall(final Context context) {
- Settings.publishInstallAsync(context, mAppId);
- return false;
- }
-
- /**
- * Callback interface for dialog requests.
- *
- * THIS CLASS SHOULD BE CONSIDERED DEPRECATED.
- *
- * All public members of this class are intentionally deprecated.
- * New code should instead use
- * {@link com.facebook.widget.WebDialog}
- *
- * Adding @Deprecated to this class causes warnings in other deprecated classes
- * that reference this one. That is the only reason this entire class is not
- * deprecated.
- *
- * @devDocDeprecated
- */
- public static interface DialogListener {
-
- /**
- * Called when a dialog completes.
- *
- * Executed by the thread that initiated the dialog.
- *
- * @param values
- * Key-value string pairs extracted from the response.
- */
- public void onComplete(Bundle values);
-
- /**
- * Called when a Facebook responds to a dialog with an error.
- *
- * Executed by the thread that initiated the dialog.
- *
- */
- public void onFacebookError(FacebookError e);
-
- /**
- * Called when a dialog has an error.
- *
- * Executed by the thread that initiated the dialog.
- *
- */
- public void onError(DialogError e);
-
- /**
- * Called when a dialog is canceled by the user.
- *
- * Executed by the thread that initiated the dialog.
- *
- */
- public void onCancel();
-
- }
-
- /**
- * Callback interface for service requests.
- *
- * THIS CLASS SHOULD BE CONSIDERED DEPRECATED.
- *
- * All public members of this class are intentionally deprecated.
- * New code should instead use
- * {@link Session} to manage session state.
- *
- * Adding @Deprecated to this class causes warnings in other deprecated classes
- * that reference this one. That is the only reason this entire class is not
- * deprecated.
- *
- * @devDocDeprecated
- */
- public static interface ServiceListener {
-
- /**
- * Called when a service request completes.
- *
- * @param values
- * Key-value string pairs extracted from the response.
- */
- public void onComplete(Bundle values);
-
- /**
- * Called when a Facebook server responds to the request with an error.
- */
- public void onFacebookError(FacebookError e);
-
- /**
- * Called when a Facebook Service responds to the request with an error.
- */
- public void onError(Error e);
-
- }
-
- @Deprecated
- public static final String FB_APP_SIGNATURE =
- "30820268308201d102044a9c4610300d06092a864886f70d0101040500307a310"
- + "b3009060355040613025553310b30090603550408130243413112301006035504"
- + "07130950616c6f20416c746f31183016060355040a130f46616365626f6f6b204"
- + "d6f62696c653111300f060355040b130846616365626f6f6b311d301b06035504"
- + "03131446616365626f6f6b20436f72706f726174696f6e3020170d30393038333"
- + "13231353231365a180f32303530303932353231353231365a307a310b30090603"
- + "55040613025553310b30090603550408130243413112301006035504071309506"
- + "16c6f20416c746f31183016060355040a130f46616365626f6f6b204d6f62696c"
- + "653111300f060355040b130846616365626f6f6b311d301b06035504031314466"
- + "16365626f6f6b20436f72706f726174696f6e30819f300d06092a864886f70d01"
- + "0101050003818d0030818902818100c207d51df8eb8c97d93ba0c8c1002c928fa"
- + "b00dc1b42fca5e66e99cc3023ed2d214d822bc59e8e35ddcf5f44c7ae8ade50d7"
- + "e0c434f500e6c131f4a2834f987fc46406115de2018ebbb0d5a3c261bd97581cc"
- + "fef76afc7135a6d59e8855ecd7eacc8f8737e794c60a761c536b72b11fac8e603"
- + "f5da1a2d54aa103b8a13c0dbc10203010001300d06092a864886f70d010104050"
- + "0038181005ee9be8bcbb250648d3b741290a82a1c9dc2e76a0af2f2228f1d9f9c"
- + "4007529c446a70175c5a900d5141812866db46be6559e2141616483998211f4a6"
- + "73149fb2232a10d247663b26a9031e15f84bc1c74d141ff98a02d76f85b2c8ab2"
- + "571b6469b232d8e768a7f7ca04f7abe4a775615916c07940656b58717457b42bd"
- + "928a2";
-
-}
diff --git a/facebook/facebook/src/com/facebook/android/FacebookError.java b/facebook/facebook/src/com/facebook/android/FacebookError.java
deleted file mode 100644
index 41ae794fc..000000000
--- a/facebook/facebook/src/com/facebook/android/FacebookError.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Copyright 2010-present Facebook
- *
- * 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 com.facebook.android;
-
-/**
- * Encapsulation of a Facebook Error: a Facebook request that could not be
- * fulfilled.
- *
- * THIS CLASS SHOULD BE CONSIDERED DEPRECATED.
- *
- * All public members of this class are intentionally deprecated.
- * New code should instead use
- * {@link com.facebook.FacebookException}
- *
- * Adding @Deprecated to this class causes warnings in other deprecated classes
- * that reference this one. That is the only reason this entire class is not
- * deprecated.
- *
- * @devDocDeprecated
- */
-public class FacebookError extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- private int mErrorCode = 0;
- private String mErrorType;
-
- @Deprecated
- public FacebookError(String message) {
- super(message);
- }
-
- @Deprecated
- public FacebookError(String message, String type, int code) {
- super(message);
- mErrorType = type;
- mErrorCode = code;
- }
-
- @Deprecated
- public int getErrorCode() {
- return mErrorCode;
- }
-
- @Deprecated
- public String getErrorType() {
- return mErrorType;
- }
-
-}
diff --git a/facebook/facebook/src/com/facebook/android/FbDialog.java b/facebook/facebook/src/com/facebook/android/FbDialog.java
deleted file mode 100644
index 603e69280..000000000
--- a/facebook/facebook/src/com/facebook/android/FbDialog.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Copyright 2010-present Facebook
- *
- * 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 com.facebook.android;
-
-import android.content.Context;
-import android.os.Bundle;
-import com.facebook.*;
-import com.facebook.android.Facebook.DialogListener;
-import com.facebook.widget.WebDialog;
-
-/**
- * This class is deprecated. See {@link com.facebook.widget.WebDialog}.
- */
-@Deprecated
-public class FbDialog extends WebDialog {
- private DialogListener mListener;
-
- public FbDialog(Context context, String url, DialogListener listener) {
- this(context, url, listener, DEFAULT_THEME);
- }
-
- public FbDialog(Context context, String url, DialogListener listener, int theme) {
- super(context, url, theme);
- setDialogListener(listener);
- }
-
- public FbDialog(Context context, String action, Bundle parameters, DialogListener listener) {
- super(context, action, parameters, DEFAULT_THEME, null);
- setDialogListener(listener);
- }
-
- public FbDialog(Context context, String action, Bundle parameters, DialogListener listener,
- int theme) {
- super(context, action, parameters, theme, null);
- setDialogListener(listener);
- }
-
- private void setDialogListener(DialogListener listener) {
- this.mListener = listener;
- setOnCompleteListener(new OnCompleteListener() {
- @Override
- public void onComplete(Bundle values, FacebookException error) {
- callDialogListener(values, error);
- }
- });
- }
-
- private void callDialogListener(Bundle values, FacebookException error) {
- if (mListener == null) {
- return;
- }
-
- if (values != null) {
- mListener.onComplete(values);
- } else {
- if (error instanceof FacebookDialogException) {
- FacebookDialogException facebookDialogException = (FacebookDialogException) error;
- DialogError dialogError = new DialogError(facebookDialogException.getMessage(),
- facebookDialogException.getErrorCode(), facebookDialogException.getFailingUrl());
- mListener.onError(dialogError);
- } else if (error instanceof FacebookOperationCanceledException) {
- mListener.onCancel();
- } else {
- FacebookError facebookError = new FacebookError(error.getMessage());
- mListener.onFacebookError(facebookError);
- }
- }
- }
-}
diff --git a/facebook/facebook/src/com/facebook/android/Util.java b/facebook/facebook/src/com/facebook/android/Util.java
deleted file mode 100644
index 231c1e78c..000000000
--- a/facebook/facebook/src/com/facebook/android/Util.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/**
- * Copyright 2010-present Facebook
- *
- * 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 com.facebook.android;
-
-import android.app.AlertDialog.Builder;
-import android.content.Context;
-import android.os.Bundle;
-import com.facebook.internal.Utility;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.*;
-import java.net.*;
-
-/**
- * Utility class supporting the Facebook Object.
- *
- * THIS CLASS SHOULD BE CONSIDERED DEPRECATED.
- *
- * All public members of this class are intentionally deprecated.
- * New code should instead use
- * {@link com.facebook.Request}
- *
- * Adding @Deprecated to this class causes warnings in other deprecated classes
- * that reference this one. That is the only reason this entire class is not
- * deprecated.
- *
- * @devDocDeprecated
- */
-public final class Util {
-
- private final static String UTF8 = "UTF-8";
-
- /**
- * Generate the multi-part post body providing the parameters and boundary
- * string
- *
- * @param parameters the parameters need to be posted
- * @param boundary the random string as boundary
- * @return a string of the post body
- */
- @Deprecated
- public static String encodePostBody(Bundle parameters, String boundary) {
- if (parameters == null) return "";
- StringBuilder sb = new StringBuilder();
-
- for (String key : parameters.keySet()) {
- Object parameter = parameters.get(key);
- if (!(parameter instanceof String)) {
- continue;
- }
-
- sb.append("Content-Disposition: form-data; name=\"" + key +
- "\"\r\n\r\n" + (String)parameter);
- sb.append("\r\n" + "--" + boundary + "\r\n");
- }
-
- return sb.toString();
- }
-
- @Deprecated
- public static String encodeUrl(Bundle parameters) {
- if (parameters == null) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (String key : parameters.keySet()) {
- Object parameter = parameters.get(key);
- if (!(parameter instanceof String)) {
- continue;
- }
-
- if (first) first = false; else sb.append("&");
- sb.append(URLEncoder.encode(key) + "=" +
- URLEncoder.encode(parameters.getString(key)));
- }
- return sb.toString();
- }
-
- @Deprecated
- public static Bundle decodeUrl(String s) {
- Bundle params = new Bundle();
- if (s != null) {
- String array[] = s.split("&");
- for (String parameter : array) {
- String v[] = parameter.split("=");
-
- try {
- if (v.length == 2) {
- params.putString(URLDecoder.decode(v[0], UTF8),
- URLDecoder.decode(v[1], UTF8));
- } else if (v.length == 1) {
- params.putString(URLDecoder.decode(v[0], UTF8), "");
- }
- } catch (UnsupportedEncodingException e) {
- // shouldn't happen
- }
- }
- }
- return params;
- }
-
- /**
- * Parse a URL query and fragment parameters into a key-value bundle.
- *
- * @param url the URL to parse
- * @return a dictionary bundle of keys and values
- */
- @Deprecated
- public static Bundle parseUrl(String url) {
- // hack to prevent MalformedURLException
- url = url.replace("fbconnect", "http");
- try {
- URL u = new URL(url);
- Bundle b = decodeUrl(u.getQuery());
- b.putAll(decodeUrl(u.getRef()));
- return b;
- } catch (MalformedURLException e) {
- return new Bundle();
- }
- }
-
-
- /**
- * Connect to an HTTP URL and return the response as a string.
- *
- * Note that the HTTP method override is used on non-GET requests. (i.e.
- * requests are made as "POST" with method specified in the body).
- *
- * @param url - the resource to open: must be a welformed URL
- * @param method - the HTTP method to use ("GET", "POST", etc.)
- * @param params - the query parameter for the URL (e.g. access_token=foo)
- * @return the URL contents as a String
- * @throws MalformedURLException - if the URL format is invalid
- * @throws IOException - if a network problem occurs
- */
- @Deprecated
- public static String openUrl(String url, String method, Bundle params)
- throws MalformedURLException, IOException {
- // random string as boundary for multi-part http post
- String strBoundary = "3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f";
- String endLine = "\r\n";
-
- OutputStream os;
-
- if (method.equals("GET")) {
- url = url + "?" + encodeUrl(params);
- }
- Utility.logd("Facebook-Util", method + " URL: " + url);
- HttpURLConnection conn =
- (HttpURLConnection) new URL(url).openConnection();
- conn.setRequestProperty("User-Agent", System.getProperties().
- getProperty("http.agent") + " FacebookAndroidSDK");
- if (!method.equals("GET")) {
- Bundle dataparams = new Bundle();
- for (String key : params.keySet()) {
- Object parameter = params.get(key);
- if (parameter instanceof byte[]) {
- dataparams.putByteArray(key, (byte[])parameter);
- }
- }
-
- // use method override
- if (!params.containsKey("method")) {
- params.putString("method", method);
- }
-
- if (params.containsKey("access_token")) {
- String decoded_token =
- URLDecoder.decode(params.getString("access_token"));
- params.putString("access_token", decoded_token);
- }
-
- conn.setRequestMethod("POST");
- conn.setRequestProperty(
- "Content-Type",
- "multipart/form-data;boundary="+strBoundary);
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setRequestProperty("Connection", "Keep-Alive");
- conn.connect();
- os = new BufferedOutputStream(conn.getOutputStream());
-
- os.write(("--" + strBoundary +endLine).getBytes());
- os.write((encodePostBody(params, strBoundary)).getBytes());
- os.write((endLine + "--" + strBoundary + endLine).getBytes());
-
- if (!dataparams.isEmpty()) {
-
- for (String key: dataparams.keySet()){
- os.write(("Content-Disposition: form-data; filename=\"" + key + "\"" + endLine).getBytes());
- os.write(("Content-Type: content/unknown" + endLine + endLine).getBytes());
- os.write(dataparams.getByteArray(key));
- os.write((endLine + "--" + strBoundary + endLine).getBytes());
-
- }
- }
- os.flush();
- }
-
- String response = "";
- try {
- response = read(conn.getInputStream());
- } catch (FileNotFoundException e) {
- // Error Stream contains JSON that we can parse to a FB error
- response = read(conn.getErrorStream());
- }
- return response;
- }
-
- @Deprecated
- private static String read(InputStream in) throws IOException {
- StringBuilder sb = new StringBuilder();
- BufferedReader r = new BufferedReader(new InputStreamReader(in), 1000);
- for (String line = r.readLine(); line != null; line = r.readLine()) {
- sb.append(line);
- }
- in.close();
- return sb.toString();
- }
-
- /**
- * Parse a server response into a JSON Object. This is a basic
- * implementation using org.json.JSONObject representation. More
- * sophisticated applications may wish to do their own parsing.
- *
- * The parsed JSON is checked for a variety of error fields and
- * a FacebookException is thrown if an error condition is set,
- * populated with the error message and error type or code if
- * available.
- *
- * @param response - string representation of the response
- * @return the response as a JSON Object
- * @throws JSONException - if the response is not valid JSON
- * @throws FacebookError - if an error condition is set
- */
- @Deprecated
- public static JSONObject parseJson(String response)
- throws JSONException, FacebookError {
- // Edge case: when sending a POST request to /[post_id]/likes
- // the return value is 'true' or 'false'. Unfortunately
- // these values cause the JSONObject constructor to throw
- // an exception.
- if (response.equals("false")) {
- throw new FacebookError("request failed");
- }
- if (response.equals("true")) {
- response = "{value : true}";
- }
- JSONObject json = new JSONObject(response);
-
- // errors set by the server are not consistent
- // they depend on the method and endpoint
- if (json.has("error")) {
- JSONObject error = json.getJSONObject("error");
- throw new FacebookError(
- error.getString("message"), error.getString("type"), 0);
- }
- if (json.has("error_code") && json.has("error_msg")) {
- throw new FacebookError(json.getString("error_msg"), "",
- Integer.parseInt(json.getString("error_code")));
- }
- if (json.has("error_code")) {
- throw new FacebookError("request failed", "",
- Integer.parseInt(json.getString("error_code")));
- }
- if (json.has("error_msg")) {
- throw new FacebookError(json.getString("error_msg"));
- }
- if (json.has("error_reason")) {
- throw new FacebookError(json.getString("error_reason"));
- }
- return json;
- }
-
- /**
- * Display a simple alert dialog with the given text and title.
- *
- * @param context
- * Android context in which the dialog should be displayed
- * @param title
- * Alert dialog title
- * @param text
- * Alert dialog message
- */
- @Deprecated
- public static void showAlert(Context context, String title, String text) {
- Builder alertBuilder = new Builder(context);
- alertBuilder.setTitle(title);
- alertBuilder.setMessage(text);
- alertBuilder.create().show();
- }
-}
diff --git a/facebook/facebook/src/com/facebook/internal/CacheableRequestBatch.java b/facebook/facebook/src/com/facebook/internal/CacheableRequestBatch.java
deleted file mode 100644
index 26a1595c2..000000000
--- a/facebook/facebook/src/com/facebook/internal/CacheableRequestBatch.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-import com.facebook.Request;
-import com.facebook.RequestBatch;
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public class CacheableRequestBatch extends RequestBatch {
- private String cacheKey;
- private boolean forceRoundTrip;
-
- public CacheableRequestBatch() {
- }
-
- public CacheableRequestBatch(Request... requests) {
- super(requests);
- }
-
- public final String getCacheKeyOverride() {
- return cacheKey;
- }
-
- // If this is set, the provided string will override the default key (the URL) for single requests.
- // There is no default for multi-request batches, so no caching will be done unless the override is
- // specified.
- public final void setCacheKeyOverride(String cacheKey) {
- this.cacheKey = cacheKey;
- }
-
- public final boolean getForceRoundTrip() {
- return forceRoundTrip;
- }
-
- public final void setForceRoundTrip(boolean forceRoundTrip) {
- this.forceRoundTrip = forceRoundTrip;
- }
-
-}
diff --git a/facebook/facebook/src/com/facebook/internal/FileLruCache.java b/facebook/facebook/src/com/facebook/internal/FileLruCache.java
deleted file mode 100644
index 1fe81b5e1..000000000
--- a/facebook/facebook/src/com/facebook/internal/FileLruCache.java
+++ /dev/null
@@ -1,606 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-import android.content.Context;
-import android.util.Log;
-import com.facebook.LoggingBehavior;
-import com.facebook.Settings;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.json.JSONTokener;
-
-import java.io.*;
-import java.security.InvalidParameterException;
-import java.util.Date;
-import java.util.PriorityQueue;
-import java.util.concurrent.atomic.AtomicLong;
-
-// This class is intended to be thread-safe.
-//
-// There are two classes of files: buffer files and cache files:
-// - A buffer file is in the process of being written, and there is an open stream on the file. These files are
-// named as "bufferN" where N is an incrementing integer. On startup, we delete all existing files of this form.
-// Once the stream is closed, we rename the buffer file to a cache file or attempt to delete if this fails. We
-// do not otherwise ever attempt to delete these files.
-// - A cache file is a non-changing file that is named by the md5 hash of the cache key. We monitor the size of
-// these files in aggregate and remove the oldest one(s) to stay under quota. This process does not block threads
-// calling into this class, so theoretically we could go arbitrarily over quota but in practice this should not
-// happen because deleting files should be much cheaper than downloading new file content.
-//
-// Since there can only ever be one thread accessing a particular buffer file, we do not synchronize access to these.
-// We do assume that file rename is atomic when converting a buffer file to a cache file, and that if multiple files
-// are renamed to a single target that exactly one of them continues to exist.
-//
-// Standard POSIX file semantics guarantee being able to continue to use a file handle even after the
-// corresponding file has been deleted. Given this and that cache files never change other than deleting in trim(),
-// we only have to ensure that there is at most one trim() process deleting files at any given time.
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public final class FileLruCache {
- static final String TAG = FileLruCache.class.getSimpleName();
- private static final String HEADER_CACHEKEY_KEY = "key";
- private static final String HEADER_CACHE_CONTENT_TAG_KEY = "tag";
-
- private static final AtomicLong bufferIndex = new AtomicLong();
-
- private final String tag;
- private final Limits limits;
- private final File directory;
- private boolean isTrimPending;
- private final Object lock;
-
- // The value of tag should be a final String that works as a directory name.
- public FileLruCache(Context context, String tag, Limits limits) {
- this.tag = tag;
- this.limits = limits;
- this.directory = new File(context.getCacheDir(), tag);
- this.lock = new Object();
-
- // Ensure the cache dir exists
- this.directory.mkdirs();
-
- // Remove any stale partially-written files from a previous run
- BufferFile.deleteAll(this.directory);
- }
-
- // Other code in this class is not necessarily robust to having buffer files deleted concurrently.
- // If this is ever used for non-test code, we should make sure the synchronization is correct. See
- // the threading notes at the top of this class.
- public void clearForTest() throws IOException {
- for (File file : this.directory.listFiles()) {
- file.delete();
- }
- }
-
- // This is not robust to files changing dynamically underneath it and should therefore only be used
- // for test code. If we ever need this for product code we need to think through synchronization.
- // See the threading notes at the top of this class.
- //
- // Also, since trim() runs asynchronously now, this blocks until any pending trim has completed.
- long sizeInBytesForTest() {
- synchronized (lock) {
- while (isTrimPending) {
- try {
- lock.wait();
- } catch (InterruptedException e) {
- // intentional no-op
- }
- }
- }
-
- File[] files = this.directory.listFiles();
- long total = 0;
- for (File file : files) {
- total += file.length();
- }
- return total;
- }
-
- public InputStream get(String key) throws IOException {
- return get(key, null);
- }
-
- public InputStream get(String key, String contentTag) throws IOException {
- File file = new File(this.directory, Utility.md5hash(key));
-
- FileInputStream input = null;
- try {
- input = new FileInputStream(file);
- } catch (IOException e) {
- return null;
- }
-
- BufferedInputStream buffered = new BufferedInputStream(input, Utility.DEFAULT_STREAM_BUFFER_SIZE);
- boolean success = false;
-
- try {
- JSONObject header = StreamHeader.readHeader(buffered);
- if (header == null) {
- return null;
- }
-
- String foundKey = header.optString(HEADER_CACHEKEY_KEY);
- if ((foundKey == null) || !foundKey.equals(key)) {
- return null;
- }
-
- String headerContentTag = header.optString(HEADER_CACHE_CONTENT_TAG_KEY, null);
-
- if ((contentTag == null && headerContentTag != null) ||
- (contentTag != null && !contentTag.equals(headerContentTag))) {
- return null;
- }
-
- long accessTime = new Date().getTime();
- Logger.log(LoggingBehavior.CACHE, TAG, "Setting lastModified to " + Long.valueOf(accessTime) + " for "
- + file.getName());
- file.setLastModified(accessTime);
-
- success = true;
- return buffered;
- } finally {
- if (!success) {
- buffered.close();
- }
- }
- }
-
- OutputStream openPutStream(final String key) throws IOException {
- return openPutStream(key, null);
- }
-
- public OutputStream openPutStream(final String key, String contentTag) throws IOException {
- final File buffer = BufferFile.newFile(this.directory);
- buffer.delete();
- if (!buffer.createNewFile()) {
- throw new IOException("Could not create file at " + buffer.getAbsolutePath());
- }
-
- FileOutputStream file = null;
- try {
- file = new FileOutputStream(buffer);
- } catch (FileNotFoundException e) {
- Logger.log(LoggingBehavior.CACHE, Log.WARN, TAG, "Error creating buffer output stream: " + e);
- throw new IOException(e.getMessage());
- }
-
- StreamCloseCallback renameToTargetCallback = new StreamCloseCallback() {
- @Override
- public void onClose() {
- renameToTargetAndTrim(key, buffer);
- }
- };
-
- CloseCallbackOutputStream cleanup = new CloseCallbackOutputStream(file, renameToTargetCallback);
- BufferedOutputStream buffered = new BufferedOutputStream(cleanup, Utility.DEFAULT_STREAM_BUFFER_SIZE);
- boolean success = false;
-
- try {
- // Prefix the stream with the actual key, since there could be collisions
- JSONObject header = new JSONObject();
- header.put(HEADER_CACHEKEY_KEY, key);
- if (!Utility.isNullOrEmpty(contentTag)) {
- header.put(HEADER_CACHE_CONTENT_TAG_KEY, contentTag);
- }
-
- StreamHeader.writeHeader(buffered, header);
-
- success = true;
- return buffered;
- } catch (JSONException e) {
- // JSON is an implementation detail of the cache, so don't let JSON exceptions out.
- Logger.log(LoggingBehavior.CACHE, Log.WARN, TAG, "Error creating JSON header for cache file: " + e);
- throw new IOException(e.getMessage());
- } finally {
- if (!success) {
- buffered.close();
- }
- }
- }
-
- private void renameToTargetAndTrim(String key, File buffer) {
- final File target = new File(directory, Utility.md5hash(key));
-
- // This is triggered by close(). By the time close() returns, the file should be cached, so this needs to
- // happen synchronously on this thread.
- //
- // However, it does not need to be synchronized, since in the race we will just start an unnecesary trim
- // operation. Avoiding the cost of holding the lock across the file operation seems worth this cost.
- if (!buffer.renameTo(target)) {
- buffer.delete();
- }
-
- postTrim();
- }
-
- // Opens an output stream for the key, and creates an input stream wrapper to copy
- // the contents of input into the new output stream. The effect is to store a
- // copy of input, and associate that data with key.
- public InputStream interceptAndPut(String key, InputStream input) throws IOException {
- OutputStream output = openPutStream(key);
- return new CopyingInputStream(input, output);
- }
-
- public String toString() {
- return "{FileLruCache:" + " tag:" + this.tag + " file:" + this.directory.getName() + "}";
- }
-
- private void postTrim() {
- synchronized (lock) {
- if (!isTrimPending) {
- isTrimPending = true;
- Settings.getExecutor().execute(new Runnable() {
- @Override
- public void run() {
- trim();
- }
- });
- }
- }
- }
-
- private void trim() {
- try {
- Logger.log(LoggingBehavior.CACHE, TAG, "trim started");
- PriorityQueue heap = new PriorityQueue();
- long size = 0;
- long count = 0;
- for (File file : this.directory.listFiles(BufferFile.excludeBufferFiles())) {
- ModifiedFile modified = new ModifiedFile(file);
- heap.add(modified);
- Logger.log(LoggingBehavior.CACHE, TAG, " trim considering time=" + Long.valueOf(modified.getModified())
- + " name=" + modified.getFile().getName());
-
- size += file.length();
- count++;
- }
-
- while ((size > limits.getByteCount()) || (count > limits.getFileCount())) {
- File file = heap.remove().getFile();
- Logger.log(LoggingBehavior.CACHE, TAG, " trim removing " + file.getName());
- size -= file.length();
- count--;
- file.delete();
- }
- } finally {
- synchronized (lock) {
- isTrimPending = false;
- lock.notifyAll();
- }
- }
- }
-
- private static class BufferFile {
- private static final String FILE_NAME_PREFIX = "buffer";
- private static final FilenameFilter filterExcludeBufferFiles = new FilenameFilter() {
- @Override
- public boolean accept(File dir, String filename) {
- return !filename.startsWith(FILE_NAME_PREFIX);
- }
- };
- private static final FilenameFilter filterExcludeNonBufferFiles = new FilenameFilter() {
- @Override
- public boolean accept(File dir, String filename) {
- return filename.startsWith(FILE_NAME_PREFIX);
- }
- };
-
- static void deleteAll(final File root) {
- for (File file : root.listFiles(excludeNonBufferFiles())) {
- file.delete();
- }
- }
-
- static FilenameFilter excludeBufferFiles() {
- return filterExcludeBufferFiles;
- }
-
- static FilenameFilter excludeNonBufferFiles() {
- return filterExcludeNonBufferFiles;
- }
-
- static File newFile(final File root) {
- String name = FILE_NAME_PREFIX + Long.valueOf(bufferIndex.incrementAndGet()).toString();
- return new File(root, name);
- }
- }
-
- // Treats the first part of a stream as a header, reads/writes it as a JSON blob, and
- // leaves the stream positioned exactly after the header.
- //
- // The format is as follows:
- // byte: meaning
- // ---------------------------------
- // 0: version number
- // 1-3: big-endian JSON header blob size
- // 4-size+4: UTF-8 JSON header blob
- // ...: stream data
- private static final class StreamHeader {
- private static final int HEADER_VERSION = 0;
-
- static void writeHeader(OutputStream stream, JSONObject header) throws IOException {
- String headerString = header.toString();
- byte[] headerBytes = headerString.getBytes();
-
- // Write version number and big-endian header size
- stream.write(HEADER_VERSION);
- stream.write((headerBytes.length >> 16) & 0xff);
- stream.write((headerBytes.length >> 8) & 0xff);
- stream.write((headerBytes.length >> 0) & 0xff);
-
- stream.write(headerBytes);
- }
-
- static JSONObject readHeader(InputStream stream) throws IOException {
- int version = stream.read();
- if (version != HEADER_VERSION) {
- return null;
- }
-
- int headerSize = 0;
- for (int i = 0; i < 3; i++) {
- int b = stream.read();
- if (b == -1) {
- Logger.log(LoggingBehavior.CACHE, TAG,
- "readHeader: stream.read returned -1 while reading header size");
- return null;
- }
- headerSize <<= 8;
- headerSize += b & 0xff;
- }
-
- byte[] headerBytes = new byte[headerSize];
- int count = 0;
- while (count < headerBytes.length) {
- int readCount = stream.read(headerBytes, count, headerBytes.length - count);
- if (readCount < 1) {
- Logger.log(LoggingBehavior.CACHE, TAG,
- "readHeader: stream.read stopped at " + Integer.valueOf(count) + " when expected "
- + headerBytes.length);
- return null;
- }
- count += readCount;
- }
-
- String headerString = new String(headerBytes);
- JSONObject header = null;
- JSONTokener tokener = new JSONTokener(headerString);
- try {
- Object parsed = tokener.nextValue();
- if (!(parsed instanceof JSONObject)) {
- Logger.log(LoggingBehavior.CACHE, TAG, "readHeader: expected JSONObject, got " + parsed.getClass().getCanonicalName());
- return null;
- }
- header = (JSONObject) parsed;
- } catch (JSONException e) {
- throw new IOException(e.getMessage());
- }
-
- return header;
- }
- }
-
- private static class CloseCallbackOutputStream extends OutputStream {
- final OutputStream innerStream;
- final StreamCloseCallback callback;
-
- CloseCallbackOutputStream(OutputStream innerStream, StreamCloseCallback callback) {
- this.innerStream = innerStream;
- this.callback = callback;
- }
-
- @Override
- public void close() throws IOException {
- try {
- this.innerStream.close();
- } finally {
- this.callback.onClose();
- }
- }
-
- @Override
- public void flush() throws IOException {
- this.innerStream.flush();
- }
-
- @Override
- public void write(byte[] buffer, int offset, int count) throws IOException {
- this.innerStream.write(buffer, offset, count);
- }
-
- @Override
- public void write(byte[] buffer) throws IOException {
- this.innerStream.write(buffer);
- }
-
- @Override
- public void write(int oneByte) throws IOException {
- this.innerStream.write(oneByte);
- }
- }
-
- private static final class CopyingInputStream extends InputStream {
- final InputStream input;
- final OutputStream output;
-
- CopyingInputStream(final InputStream input, final OutputStream output) {
- this.input = input;
- this.output = output;
- }
-
- @Override
- public int available() throws IOException {
- return input.available();
- }
-
- @Override
- public void close() throws IOException {
- // According to http://www.cs.cornell.edu/andru/javaspec/11.doc.html:
- // "If a finally clause is executed because of abrupt completion of a try block and the finally clause
- // itself completes abruptly, then the reason for the abrupt completion of the try block is discarded
- // and the new reason for abrupt completion is propagated from there."
- //
- // Android does appear to behave like this.
- try {
- this.input.close();
- } finally {
- this.output.close();
- }
- }
-
- @Override
- public void mark(int readlimit) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean markSupported() {
- return false;
- }
-
- @Override
- public int read(byte[] buffer) throws IOException {
- int count = input.read(buffer);
- if (count > 0) {
- output.write(buffer, 0, count);
- }
- return count;
- }
-
- @Override
- public int read() throws IOException {
- int b = input.read();
- if (b >= 0) {
- output.write(b);
- }
- return b;
- }
-
- @Override
- public int read(byte[] buffer, int offset, int length) throws IOException {
- int count = input.read(buffer, offset, length);
- if (count > 0) {
- output.write(buffer, offset, count);
- }
- return count;
- }
-
- @Override
- public synchronized void reset() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long skip(long byteCount) throws IOException {
- byte[] buffer = new byte[1024];
- long total = 0;
- while (total < byteCount) {
- int count = read(buffer, 0, (int)Math.min(byteCount - total, buffer.length));
- if (count < 0) {
- return total;
- }
- total += count;
- }
- return total;
- }
- }
-
- public static final class Limits {
- private int byteCount;
- private int fileCount;
-
- public Limits() {
- // A Samsung Galaxy Nexus can create 1k files in half a second. By the time
- // it gets to 5k files it takes 5 seconds. 10k files took 15 seconds. This
- // continues to slow down as files are added. This assumes all files are in
- // a single directory.
- //
- // Following a git-like strategy where we partition MD5-named files based on
- // the first 2 characters is slower across the board.
- this.fileCount = 1024;
- this.byteCount = 1024 * 1024;
- }
-
- int getByteCount() {
- return byteCount;
- }
-
- int getFileCount() {
- return fileCount;
- }
-
- void setByteCount(int n) {
- if (n < 0) {
- throw new InvalidParameterException("Cache byte-count limit must be >= 0");
- }
- byteCount = n;
- }
-
- void setFileCount(int n) {
- if (n < 0) {
- throw new InvalidParameterException("Cache file count limit must be >= 0");
- }
- fileCount = n;
- }
- }
-
- // Caches the result of lastModified during sort/heap operations
- private final static class ModifiedFile implements Comparable {
- private final File file;
- private final long modified;
-
- ModifiedFile(File file) {
- this.file = file;
- this.modified = file.lastModified();
- }
-
- File getFile() {
- return file;
- }
-
- long getModified() {
- return modified;
- }
-
- @Override
- public int compareTo(ModifiedFile another) {
- if (getModified() < another.getModified()) {
- return -1;
- } else if (getModified() > another.getModified()) {
- return 1;
- } else {
- return getFile().compareTo(another.getFile());
- }
- }
-
- @Override
- public boolean equals(Object another) {
- return
- (another instanceof ModifiedFile) &&
- (compareTo((ModifiedFile)another) == 0);
- }
- }
-
- private interface StreamCloseCallback {
- void onClose();
- }
-}
diff --git a/facebook/facebook/src/com/facebook/internal/Logger.java b/facebook/facebook/src/com/facebook/internal/Logger.java
deleted file mode 100644
index 6a232c6c8..000000000
--- a/facebook/facebook/src/com/facebook/internal/Logger.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-import android.util.Log;
-import com.facebook.LoggingBehavior;
-import com.facebook.Settings;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public class Logger {
- public static final String LOG_TAG_BASE = "FacebookSDK.";
- private static final HashMap stringsToReplace = new HashMap();
-
- private final LoggingBehavior behavior;
- private final String tag;
- private StringBuilder contents;
- private int priority = Log.DEBUG;
-
- // Note that the mapping of replaced strings is never emptied, so it should be used only for things that
- // are not expected to be too numerous, such as access tokens.
- public synchronized static void registerStringToReplace(String original, String replace) {
- stringsToReplace.put(original, replace);
- }
-
- public synchronized static void registerAccessToken(String accessToken) {
- if (Settings.isLoggingBehaviorEnabled(LoggingBehavior.INCLUDE_ACCESS_TOKENS) == false) {
- registerStringToReplace(accessToken, "ACCESS_TOKEN_REMOVED");
- }
- }
-
- public static void log(LoggingBehavior behavior, String tag, String string) {
- log(behavior, Log.DEBUG, tag, string);
- }
-
- public static void log(LoggingBehavior behavior, String tag, String format, Object... args) {
- if (Settings.isLoggingBehaviorEnabled(behavior)) {
- String string = String.format(format, args);
- log(behavior, Log.DEBUG, tag, string);
- }
- }
-
- public static void log(LoggingBehavior behavior, int priority, String tag, String string) {
- if (Settings.isLoggingBehaviorEnabled(behavior)) {
- string = replaceStrings(string);
- if (tag.startsWith(LOG_TAG_BASE) == false) {
- tag = LOG_TAG_BASE + tag;
- }
- Log.println(priority, tag, string);
- }
- }
-
- private synchronized static String replaceStrings(String string) {
- for (Map.Entry entry : stringsToReplace.entrySet()) {
- string = string.replace(entry.getKey(), entry.getValue());
- }
- return string;
- }
-
- public Logger(LoggingBehavior behavior, String tag) {
- Validate.notNullOrEmpty(tag, "tag");
-
- this.behavior = behavior;
- this.tag = LOG_TAG_BASE + tag;
- this.contents = new StringBuilder();
- }
-
- public int getPriority() {
- return priority;
- }
-
- public void setPriority(int value) {
- Validate.oneOf(value, "value", Log.ASSERT, Log.DEBUG, Log.ERROR, Log.INFO, Log.VERBOSE, Log.WARN);
-
- priority = value;
- }
-
- public String getContents() {
- return replaceStrings(contents.toString());
- }
-
- // Writes the accumulated contents, then clears contents to start again.
- public void log() {
- logString(contents.toString());
- contents = new StringBuilder();
- }
-
- // Immediately logs a string, ignoring any accumulated contents, which are left unchanged.
- public void logString(String string) {
- log(behavior, priority, tag, string);
- }
-
- public void append(StringBuilder stringBuilder) {
- if (shouldLog()) {
- contents.append(stringBuilder);
- }
- }
-
- public void append(String string) {
- if (shouldLog()) {
- contents.append(string);
- }
- }
-
- public void append(String format, Object... args) {
- if (shouldLog()) {
- contents.append(String.format(format, args));
- }
- }
-
- public void appendKeyValue(String key, Object value) {
- append(" %s:\t%s\n", key, value);
- }
-
- private boolean shouldLog() {
- return Settings.isLoggingBehaviorEnabled(behavior);
- }
-}
diff --git a/facebook/facebook/src/com/facebook/internal/ServerProtocol.java b/facebook/facebook/src/com/facebook/internal/ServerProtocol.java
deleted file mode 100644
index 6cb65324d..000000000
--- a/facebook/facebook/src/com/facebook/internal/ServerProtocol.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-import com.facebook.internal.Utility;
-
-import java.util.Collection;
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public final class ServerProtocol {
- static final String FACEBOOK_COM = "facebook.com";
- public static final String DIALOG_AUTHORITY = "m." + FACEBOOK_COM;
- public static final String DIALOG_PATH = "dialog/";
- public static final String DIALOG_PARAM_SCOPE = "scope";
- public static final String DIALOG_PARAM_CLIENT_ID = "client_id";
- public static final String DIALOG_PARAM_DISPLAY = "display";
- public static final String DIALOG_PARAM_REDIRECT_URI = "redirect_uri";
- public static final String DIALOG_PARAM_TYPE = "type";
-
- // URL components
- public static final String GRAPH_URL = "https://graph." + FACEBOOK_COM;
- public static final String GRAPH_URL_BASE = "https://graph." + FACEBOOK_COM + "/";
- public static final String REST_URL_BASE = "https://api." + FACEBOOK_COM + "/method/";
- public static final String BATCHED_REST_METHOD_URL_BASE = "method/";
-
- public static final Collection errorsProxyAuthDisabled =
- Utility.unmodifiableCollection("service_disabled", "AndroidAuthKillSwitchException");
- public static final Collection errorsUserCanceled =
- Utility.unmodifiableCollection("access_denied", "OAuthAccessDeniedException");
-}
diff --git a/facebook/facebook/src/com/facebook/internal/SessionAuthorizationType.java b/facebook/facebook/src/com/facebook/internal/SessionAuthorizationType.java
deleted file mode 100644
index 6684019a1..000000000
--- a/facebook/facebook/src/com/facebook/internal/SessionAuthorizationType.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public enum SessionAuthorizationType {
- READ,
- PUBLISH
-}
diff --git a/facebook/facebook/src/com/facebook/internal/SessionTracker.java b/facebook/facebook/src/com/facebook/internal/SessionTracker.java
deleted file mode 100644
index e013de5c5..000000000
--- a/facebook/facebook/src/com/facebook/internal/SessionTracker.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.support.v4.content.LocalBroadcastManager;
-import com.facebook.Session;
-import com.facebook.SessionState;
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public class SessionTracker {
-
- private Session session;
- private final Session.StatusCallback callback;
- private final BroadcastReceiver receiver;
- private final LocalBroadcastManager broadcastManager;
- private boolean isTracking = false;
-
- /**
- * Constructs a SessionTracker to track the active Session object.
- *
- * @param context the context object.
- * @param callback the callback to use whenever the active Session's
- * state changes
- */
- public SessionTracker(Context context, Session.StatusCallback callback) {
- this(context, callback, null);
- }
-
- /**
- * Constructs a SessionTracker to track the Session object passed in.
- * If the Session is null, then it will track the active Session instead.
- *
- * @param context the context object.
- * @param callback the callback to use whenever the Session's state changes
- * @param session the Session object to track
- */
- SessionTracker(Context context, Session.StatusCallback callback, Session session) {
- this(context, callback, session, true);
- }
-
- /**
- * Constructs a SessionTracker to track the Session object passed in.
- * If the Session is null, then it will track the active Session instead.
- *
- * @param context the context object.
- * @param callback the callback to use whenever the Session's state changes
- * @param session the Session object to track
- * @param startTracking whether to start tracking the Session right away
- */
- public SessionTracker(Context context, Session.StatusCallback callback, Session session, boolean startTracking) {
- this.callback = new CallbackWrapper(callback);
- this.session = session;
- this.receiver = new ActiveSessionBroadcastReceiver();
- this.broadcastManager = LocalBroadcastManager.getInstance(context);
-
- if (startTracking) {
- startTracking();
- }
- }
-
- /**
- * Returns the current Session that's being tracked.
- *
- * @return the current Session associated with this tracker
- */
- public Session getSession() {
- return (session == null) ? Session.getActiveSession() : session;
- }
-
- /**
- * Returns the current Session that's being tracked if it's open,
- * otherwise returns null.
- *
- * @return the current Session if it's open, otherwise returns null
- */
- public Session getOpenSession() {
- Session openSession = getSession();
- if (openSession != null && openSession.isOpened()) {
- return openSession;
- }
- return null;
- }
-
- /**
- * Set the Session object to track.
- *
- * @param newSession the new Session object to track
- */
- public void setSession(Session newSession) {
- if (newSession == null) {
- if (session != null) {
- // We're current tracking a Session. Remove the callback
- // and start tracking the active Session.
- session.removeCallback(callback);
- session = null;
- addBroadcastReceiver();
- if (getSession() != null) {
- getSession().addCallback(callback);
- }
- }
- } else {
- if (session == null) {
- // We're currently tracking the active Session, but will be
- // switching to tracking a different Session object.
- Session activeSession = Session.getActiveSession();
- if (activeSession != null) {
- activeSession.removeCallback(callback);
- }
- broadcastManager.unregisterReceiver(receiver);
- } else {
- // We're currently tracking a Session, but are now switching
- // to a new Session, so we remove the callback from the old
- // Session, and add it to the new one.
- session.removeCallback(callback);
- }
- session = newSession;
- session.addCallback(callback);
- }
- }
-
- /**
- * Start tracking the Session (either active or the one given).
- */
- public void startTracking() {
- if (isTracking) {
- return;
- }
- if (this.session == null) {
- addBroadcastReceiver();
- }
- // if the session is not null, then add the callback to it right away
- if (getSession() != null) {
- getSession().addCallback(callback);
- }
- isTracking = true;
- }
-
- /**
- * Stop tracking the Session and remove any callbacks attached
- * to those sessions.
- */
- public void stopTracking() {
- if (!isTracking) {
- return;
- }
- Session session = getSession();
- if (session != null) {
- session.removeCallback(callback);
- }
- broadcastManager.unregisterReceiver(receiver);
- isTracking = false;
- }
-
- /**
- * Returns whether it's currently tracking the Session.
- *
- * @return true if currently tracking the Session
- */
- public boolean isTracking() {
- return isTracking;
- }
-
- /**
- * Returns whether it's currently tracking the active Session.
- *
- * @return true if the currently tracked session is the active Session.
- */
- public boolean isTrackingActiveSession() {
- return session == null;
- }
-
- private void addBroadcastReceiver() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Session.ACTION_ACTIVE_SESSION_SET);
- filter.addAction(Session.ACTION_ACTIVE_SESSION_UNSET);
-
- // Add a broadcast receiver to listen to when the active Session
- // is set or unset, and add/remove our callback as appropriate
- broadcastManager.registerReceiver(receiver, filter);
- }
-
- /**
- * The BroadcastReceiver implementation that either adds or removes the callback
- * from the active Session object as it's SET or UNSET.
- */
- private class ActiveSessionBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Session.ACTION_ACTIVE_SESSION_SET.equals(intent.getAction())) {
- Session session = Session.getActiveSession();
- if (session != null) {
- session.addCallback(SessionTracker.this.callback);
- }
- }
- }
- }
-
- private class CallbackWrapper implements Session.StatusCallback {
-
- private final Session.StatusCallback wrapped;
- public CallbackWrapper(Session.StatusCallback wrapped) {
- this.wrapped = wrapped;
- }
-
- @Override
- public void call(Session session, SessionState state, Exception exception) {
- if (wrapped != null && isTracking()) {
- wrapped.call(session, state, exception);
- }
- // if we're not tracking the Active Session, and the current session
- // is closed, then start tracking the Active Session.
- if (session == SessionTracker.this.session && state.isClosed()) {
- setSession(null);
- }
- }
- }
-}
diff --git a/facebook/facebook/src/com/facebook/internal/Utility.java b/facebook/facebook/src/com/facebook/internal/Utility.java
deleted file mode 100644
index 371e5d056..000000000
--- a/facebook/facebook/src/com/facebook/internal/Utility.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Log;
-import android.webkit.CookieManager;
-import android.webkit.CookieSyncManager;
-import com.facebook.FacebookException;
-import com.facebook.Session;
-import com.facebook.android.BuildConfig;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.json.JSONTokener;
-
-import java.io.*;
-import java.net.HttpURLConnection;
-import java.net.URLConnection;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.*;
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public final class Utility {
- static final String LOG_TAG = "FacebookSDK";
- private static final String HASH_ALGORITHM_MD5 = "MD5";
- private static final String URL_SCHEME = "https";
-
- // This is the default used by the buffer streams, but they trace a warning if you do not specify.
- public static final int DEFAULT_STREAM_BUFFER_SIZE = 8192;
-
- // Returns true iff all items in subset are in superset, treating null and
- // empty collections as
- // the same.
- public static boolean isSubset(Collection subset, Collection superset) {
- if ((superset == null) || (superset.size() == 0)) {
- return ((subset == null) || (subset.size() == 0));
- }
-
- HashSet hash = new HashSet(superset);
- for (T t : subset) {
- if (!hash.contains(t)) {
- return false;
- }
- }
- return true;
- }
-
- public static boolean isNullOrEmpty(Collection c) {
- return (c == null) || (c.size() == 0);
- }
-
- public static boolean isNullOrEmpty(String s) {
- return (s == null) || (s.length() == 0);
- }
-
- public static Collection unmodifiableCollection(T... ts) {
- return Collections.unmodifiableCollection(Arrays.asList(ts));
- }
-
- public static ArrayList arrayList(T... ts) {
- ArrayList arrayList = new ArrayList(ts.length);
- for (T t : ts) {
- arrayList.add(t);
- }
- return arrayList;
- }
-
- static String md5hash(String key) {
- MessageDigest hash = null;
- try {
- hash = MessageDigest.getInstance(HASH_ALGORITHM_MD5);
- } catch (NoSuchAlgorithmException e) {
- return null;
- }
-
- hash.update(key.getBytes());
- byte[] digest = hash.digest();
- StringBuilder builder = new StringBuilder();
- for (int b : digest) {
- builder.append(Integer.toHexString((b >> 4) & 0xf));
- builder.append(Integer.toHexString((b >> 0) & 0xf));
- }
- return builder.toString();
- }
-
- public static Uri buildUri(String authority, String path, Bundle parameters) {
- Uri.Builder builder = new Uri.Builder();
- builder.scheme(URL_SCHEME);
- builder.authority(authority);
- builder.path(path);
- for (String key : parameters.keySet()) {
- Object parameter = parameters.get(key);
- if (parameter instanceof String) {
- builder.appendQueryParameter(key, (String) parameter);
- }
- }
- return builder.build();
- }
-
- public static void putObjectInBundle(Bundle bundle, String key, Object value) {
- if (value instanceof String) {
- bundle.putString(key, (String) value);
- } else if (value instanceof Parcelable) {
- bundle.putParcelable(key, (Parcelable) value);
- } else if (value instanceof byte[]) {
- bundle.putByteArray(key, (byte[]) value);
- } else {
- throw new FacebookException("attempted to add unsupported type to Bundle");
- }
- }
-
- public static void closeQuietly(Closeable closeable) {
- try {
- if (closeable != null) {
- closeable.close();
- }
- } catch (IOException ioe) {
- // ignore
- }
- }
-
- public static void disconnectQuietly(URLConnection connection) {
- if (connection instanceof HttpURLConnection) {
- ((HttpURLConnection)connection).disconnect();
- }
- }
-
- public static String getMetadataApplicationId(Context context) {
- try {
- ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
- context.getPackageName(), PackageManager.GET_META_DATA);
- if (ai.metaData != null) {
- return ai.metaData.getString(Session.APPLICATION_ID_PROPERTY);
- }
- } catch (PackageManager.NameNotFoundException e) {
- // if we can't find it in the manifest, just return null
- }
-
- return null;
- }
-
- static Map convertJSONObjectToHashMap(JSONObject jsonObject) {
- HashMap map = new HashMap();
- JSONArray keys = jsonObject.names();
- for (int i = 0; i < keys.length(); ++i) {
- String key;
- try {
- key = keys.getString(i);
- Object value = jsonObject.get(key);
- if (value instanceof JSONObject) {
- value = convertJSONObjectToHashMap((JSONObject) value);
- }
- map.put(key, value);
- } catch (JSONException e) {
- }
- }
- return map;
- }
-
- // Returns either a JSONObject or JSONArray representation of the 'key' property of 'jsonObject'.
- public static Object getStringPropertyAsJSON(JSONObject jsonObject, String key, String nonJSONPropertyKey)
- throws JSONException {
- Object value = jsonObject.opt(key);
- if (value != null && value instanceof String) {
- JSONTokener tokener = new JSONTokener((String) value);
- value = tokener.nextValue();
- }
-
- if (value != null && !(value instanceof JSONObject || value instanceof JSONArray)) {
- if (nonJSONPropertyKey != null) {
- // Facebook sometimes gives us back a non-JSON value such as
- // literal "true" or "false" as a result.
- // If we got something like that, we present it to the caller as
- // a GraphObject with a single
- // property. We only do this if the caller wants that behavior.
- jsonObject = new JSONObject();
- jsonObject.putOpt(nonJSONPropertyKey, value);
- return jsonObject;
- } else {
- throw new FacebookException("Got an unexpected non-JSON object.");
- }
- }
-
- return value;
-
- }
-
- public static String readStreamToString(InputStream inputStream) throws IOException {
- BufferedInputStream bufferedInputStream = null;
- InputStreamReader reader = null;
- try {
- bufferedInputStream = new BufferedInputStream(inputStream);
- reader = new InputStreamReader(bufferedInputStream);
- StringBuilder stringBuilder = new StringBuilder();
-
- final int bufferSize = 1024 * 2;
- char[] buffer = new char[bufferSize];
- int n = 0;
- while ((n = reader.read(buffer)) != -1) {
- stringBuilder.append(buffer, 0, n);
- }
-
- return stringBuilder.toString();
- } finally {
- closeQuietly(bufferedInputStream);
- closeQuietly(reader);
- }
- }
-
- public static boolean stringsEqualOrEmpty(String a, String b) {
- boolean aEmpty = TextUtils.isEmpty(a);
- boolean bEmpty = TextUtils.isEmpty(b);
-
- if (aEmpty && bEmpty) {
- // Both null or empty, they match.
- return true;
- }
- if (!aEmpty && !bEmpty) {
- // Both non-empty, check equality.
- return a.equals(b);
- }
- // One empty, one non-empty, can't match.
- return false;
- }
-
- private static void clearCookiesForDomain(Context context, String domain) {
- // This is to work around a bug where CookieManager may fail to instantiate if CookieSyncManager
- // has never been created.
- CookieSyncManager syncManager = CookieSyncManager.createInstance(context);
- syncManager.sync();
-
- CookieManager cookieManager = CookieManager.getInstance();
-
- String cookies = cookieManager.getCookie(domain);
- if (cookies == null) {
- return;
- }
-
- String[] splitCookies = cookies.split(";");
- for (String cookie : splitCookies) {
- String[] cookieParts = cookie.split("=");
- if (cookieParts.length > 0) {
- String newCookie = cookieParts[0].trim() + "=;expires=Sat, 1 Jan 2000 00:00:01 UTC;";
- cookieManager.setCookie(domain, newCookie);
- }
- }
- cookieManager.removeExpiredCookie();
- }
-
- public static void clearFacebookCookies(Context context) {
- // setCookie acts differently when trying to expire cookies between builds of Android that are using
- // Chromium HTTP stack and those that are not. Using both of these domains to ensure it works on both.
- clearCookiesForDomain(context, "facebook.com");
- clearCookiesForDomain(context, ".facebook.com");
- clearCookiesForDomain(context, "https://facebook.com");
- clearCookiesForDomain(context, "https://.facebook.com");
- }
-
- public static void logd(String tag, String msg) {
- if (BuildConfig.DEBUG) {
- Log.d(tag, msg);
- }
- }
-}
diff --git a/facebook/facebook/src/com/facebook/internal/Validate.java b/facebook/facebook/src/com/facebook/internal/Validate.java
deleted file mode 100644
index c66dee731..000000000
--- a/facebook/facebook/src/com/facebook/internal/Validate.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.internal;
-
-import java.util.Collection;
-
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-public final class Validate {
- public static void notNull(Object arg, String name) {
- if (arg == null) {
- throw new NullPointerException("Argument " + name + " cannot be null");
- }
- }
-
- public static void notEmpty(Collection container, String name) {
- if (container.isEmpty()) {
- throw new IllegalArgumentException("Container '" + name + "' cannot be empty");
- }
- }
-
- public static void containsNoNulls(Collection container, String name) {
- Validate.notNull(container, name);
- for (T item : container) {
- if (item == null) {
- throw new NullPointerException("Container '" + name + "' cannot contain null values");
- }
- }
- }
-
- public static void notEmptyAndContainsNoNulls(Collection container, String name) {
- Validate.containsNoNulls(container, name);
- Validate.notEmpty(container, name);
- }
-
- public static void notNullOrEmpty(String arg, String name) {
- if (Utility.isNullOrEmpty(arg)) {
- throw new IllegalArgumentException("Argument " + name + " cannot be null or empty");
- }
- }
-
- public static void oneOf(Object arg, String name, Object... values) {
- for (Object value : values) {
- if (value != null) {
- if (value.equals(arg)) {
- return;
- }
- } else {
- if (arg == null) {
- return;
- }
- }
- }
- throw new IllegalArgumentException("Argument " + name + " was not one of the allowed values");
- }
-}
diff --git a/facebook/facebook/src/com/facebook/internal/package-info.java b/facebook/facebook/src/com/facebook/internal/package-info.java
deleted file mode 100644
index 4392d0f35..000000000
--- a/facebook/facebook/src/com/facebook/internal/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
- * any of the classes in this package is unsupported, and they may be modified or removed without warning at
- * any time.
- */
-package com.facebook.internal;
\ No newline at end of file
diff --git a/facebook/facebook/src/com/facebook/model/GraphLocation.java b/facebook/facebook/src/com/facebook/model/GraphLocation.java
deleted file mode 100644
index 7fec04b96..000000000
--- a/facebook/facebook/src/com/facebook/model/GraphLocation.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.model;
-
-/**
- * Provides a strongly-typed representation of a Location as defined by the Graph API.
- *
- * Note that this interface is intended to be used with GraphObject.Factory
- * and not implemented directly.
- */
-public interface GraphLocation extends GraphObject {
- /**
- * Returns the street component of the location.
- *
- * @return the street component of the location, or null
- */
- public String getStreet();
-
- /**
- * Sets the street component of the location.
- *
- * @param street
- * the street component of the location, or null
- */
- public void setStreet(String street);
-
- /**
- * Gets the city component of the location.
- *
- * @return the city component of the location
- */
- public String getCity();
-
- /**
- * Sets the city component of the location.
- *
- * @param city
- * the city component of the location
- */
- public void setCity(String city);
-
- /**
- * Returns the state component of the location.
- *
- * @return the state component of the location
- */
- public String getState();
-
- /**
- * Sets the state component of the location.
- *
- * @param state
- * the state component of the location
- */
- public void setState(String state);
-
- /**
- * Returns the country component of the location.
- *
- * @return the country component of the location
- */
- public String getCountry();
-
- /**
- * Sets the country component of the location
- *
- * @param country
- * the country component of the location
- */
- public void setCountry(String country);
-
- /**
- * Returns the postal code component of the location.
- *
- * @return the postal code component of the location
- */
- public String getZip();
-
- /**
- * Sets the postal code component of the location.
- *
- * @param zip
- * the postal code component of the location
- */
- public void setZip(String zip);
-
- /**
- * Returns the latitude component of the location.
- *
- * @return the latitude component of the location
- */
- public double getLatitude();
-
- /**
- * Sets the latitude component of the location.
- *
- * @param latitude
- * the latitude component of the location
- */
- public void setLatitude(double latitude);
-
- /**
- * Returns the longitude component of the location.
- *
- * @return the longitude component of the location
- */
- public double getLongitude();
-
- /**
- * Sets the longitude component of the location.
- *
- * @param longitude
- * the longitude component of the location
- */
- public void setLongitude(double longitude);
-}
diff --git a/facebook/facebook/src/com/facebook/model/GraphMultiResult.java b/facebook/facebook/src/com/facebook/model/GraphMultiResult.java
deleted file mode 100644
index f5d65569f..000000000
--- a/facebook/facebook/src/com/facebook/model/GraphMultiResult.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.model;
-
-/**
- * Defines a GraphObject that represents the result of a query that returns multiple GraphObjects
- * nested under a "data" property.
- *
- * Note that this interface is intended to be used with GraphObject.Factory
- * and not implemented directly.
- */
-public interface GraphMultiResult extends GraphObject {
- /**
- * Provides access to the GraphObjects that make up the result set.
- * @return a list of GraphObjects
- */
- public GraphObjectList getData();
-}
diff --git a/facebook/facebook/src/com/facebook/model/GraphObject.java b/facebook/facebook/src/com/facebook/model/GraphObject.java
deleted file mode 100644
index 9b78f062a..000000000
--- a/facebook/facebook/src/com/facebook/model/GraphObject.java
+++ /dev/null
@@ -1,745 +0,0 @@
-/**
- * Copyright 2012 Facebook
- *
- * 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 com.facebook.model;
-
-import com.facebook.FacebookGraphObjectException;
-import com.facebook.internal.Utility;
-import com.facebook.internal.Validate;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.lang.reflect.*;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-/**
- * GraphObject is the primary interface used by the Facebook SDK for Android to represent objects in the Facebook
- * Social Graph and the Facebook Open Graph (OG). It is the base interface for all typed access to graph objects
- * in the SDK. No concrete classes implement GraphObject or its derived interfaces. Rather, they are implemented as
- * proxies (see the {@link com.facebook.model.GraphObject.Factory Factory} class) that provide strongly-typed property
- * getters and setters to access the underlying data. Since the primary use case for graph objects is sending and
- * receiving them over the wire to/from Facebook services, they are represented as JSONObjects. No validation is done
- * that a graph object is actually of a specific type -- any graph object can be treated as any GraphObject-derived
- * interface, and the presence or absence of specific properties determines its suitability for use as that
- * particular type of object.
- *
- */
-public interface GraphObject {
- /**
- * Returns a new proxy that treats this graph object as a different GraphObject-derived type.
- * @param graphObjectClass the type of GraphObject to return
- * @return a new instance of the GraphObject-derived-type that references the same underlying data
- */
- public T cast(Class graphObjectClass);
-
- /**
- * Returns a Java Collections map of names and properties. Modifying the returned map modifies the
- * inner JSON representation.
- * @return a Java Collections map representing the GraphObject state
- */
- public Map asMap();
-
- /**
- * Gets the underlying JSONObject representation of this graph object.
- * @return the underlying JSONObject representation of this graph object
- */
- public JSONObject getInnerJSONObject();
-
- /**
- * Gets a property of the GraphObject
- * @param propertyName the name of the property to get
- * @return the value of the named property
- */
- public Object getProperty(String propertyName);
-
- /**
- * Sets a property of the GraphObject
- * @param propertyName the name of the property to set
- * @param propertyValue the value of the named property to set
- */
- public void setProperty(String propertyName, Object propertyValue);
-
- /**
- * Removes a property of the GraphObject
- * @param propertyName the name of the property to remove
- */
- public void removeProperty(String propertyName);
-
- /**
- * Creates proxies that implement GraphObject, GraphObjectList, and their derived types. These proxies allow access
- * to underlying collections and name/value property bags via strongly-typed property getters and setters.
- *
- * This supports get/set properties that use primitive types, JSON types, Date, other GraphObject types, Iterable,
- * Collection, List, and GraphObjectList.
- */
- final class Factory {
- private static final HashSet> verifiedGraphObjectClasses = new HashSet>();
- private static final SimpleDateFormat[] dateFormats = new SimpleDateFormat[] {
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US), new SimpleDateFormat("yyyy-MM-dd", Locale.US), };
-
- // No objects of this type should exist.
- private Factory() {
- }
-
- /**
- * Creates a GraphObject proxy that provides typed access to the data in an underlying JSONObject.
- * @param json the JSONObject containing the data to be exposed
- * @return a GraphObject that represents the underlying data
- *
- * @throws com.facebook.FacebookException
- * If the passed in Class is not a valid GraphObject interface
- */
- public static GraphObject create(JSONObject json) {
- return create(json, GraphObject.class);
- }
-
- /**
- * Creates a GraphObject-derived proxy that provides typed access to the data in an underlying JSONObject.
- * @param json the JSONObject containing the data to be exposed
- * @param graphObjectClass the GraphObject-derived type to return
- * @return a graphObjectClass that represents the underlying data
- *
- * @throws com.facebook.FacebookException
- * If the passed in Class is not a valid GraphObject interface
- */
- public static T create(JSONObject json, Class graphObjectClass) {
- return createGraphObjectProxy(graphObjectClass, json);
- }
-
- /**
- * Creates a GraphObject proxy that initially contains no data.
- * @return a GraphObject with no data
- *
- * @throws com.facebook.FacebookException
- * If the passed in Class is not a valid GraphObject interface
- */
- public static GraphObject create() {
- return create(GraphObject.class);
- }
-
- /**
- * Creates a GraphObject-derived proxy that initially contains no data.
- * @param graphObjectClass the GraphObject-derived type to return
- * @return a graphObjectClass with no data
- *
- * @throws com.facebook.FacebookException
- * If the passed in Class is not a valid GraphObject interface
- */
- public static T create(Class graphObjectClass) {
- return createGraphObjectProxy(graphObjectClass, new JSONObject());
- }
-
- /**
- * Determines if two GraphObjects represent the same underlying graph object, based on their IDs.
- * @param a a graph object
- * @param b another graph object
- * @return true if both graph objects have an ID and it is the same ID, false otherwise
- */
- public static boolean hasSameId(GraphObject a, GraphObject b) {
- if (a == null || b == null || !a.asMap().containsKey("id") || !b.asMap().containsKey("id")) {
- return false;
- }
- if (a.equals(b)) {
- return true;
- }
- Object idA = a.getProperty("id");
- Object idB = b.getProperty("id");
- if (idA == null || idB == null || !(idA instanceof String) || !(idB instanceof String)) {
- return false;
- }
- return idA.equals(idB);
- }
-
- /**
- * Creates a GraphObjectList-derived proxy that provides typed access to the data in an underlying JSONArray.
- * @param array the JSONArray containing the data to be exposed
- * @param graphObjectClass the GraphObject-derived type to return
- * @return a graphObjectClass that represents the underlying data
- *
- * @throws com.facebook.FacebookException
- * If the passed in Class is not a valid GraphObject interface
- */
- public static GraphObjectList createList(JSONArray array, Class graphObjectClass) {
- return new GraphObjectListImpl(array, graphObjectClass);
- }
-
- /**
- * Creates a GraphObjectList-derived proxy that initially contains no data.
- * @param graphObjectClass the GraphObject-derived type to return
- * @return a GraphObjectList with no data
- *
- * @throws com.facebook.FacebookException
- * If the passed in Class is not a valid GraphObject interface
- */
- public static GraphObjectList createList(Class graphObjectClass) {
- return createList(new JSONArray(), graphObjectClass);
- }
-
- private static T createGraphObjectProxy(Class graphObjectClass, JSONObject state) {
- verifyCanProxyClass(graphObjectClass);
-
- Class>[] interfaces = new Class[] { graphObjectClass };
- GraphObjectProxy graphObjectProxy = new GraphObjectProxy(state, graphObjectClass);
-
- @SuppressWarnings("unchecked")
- T graphObject = (T) Proxy.newProxyInstance(GraphObject.class.getClassLoader(), interfaces, graphObjectProxy);
-
- return graphObject;
- }
-
- private static Map createGraphObjectProxyForMap(JSONObject state) {
- Class>[] interfaces = new Class[]{Map.class};
- GraphObjectProxy graphObjectProxy = new GraphObjectProxy(state, Map.class);
-
- @SuppressWarnings("unchecked")
- Map graphObject = (Map) Proxy
- .newProxyInstance(GraphObject.class.getClassLoader(), interfaces, graphObjectProxy);
-
- return graphObject;
- }
-
- private static synchronized boolean hasClassBeenVerified(Class graphObjectClass) {
- return verifiedGraphObjectClasses.contains(graphObjectClass);
- }
-
- private static synchronized void recordClassHasBeenVerified(Class graphObjectClass) {
- verifiedGraphObjectClasses.add(graphObjectClass);
- }
-
- private static void verifyCanProxyClass(Class graphObjectClass) {
- if (hasClassBeenVerified(graphObjectClass)) {
- return;
- }
-
- if (!graphObjectClass.isInterface()) {
- throw new FacebookGraphObjectException("Factory can only wrap interfaces, not class: "
- + graphObjectClass.getName());
- }
-
- Method[] methods = graphObjectClass.getMethods();
- for (Method method : methods) {
- String methodName = method.getName();
- int parameterCount = method.getParameterTypes().length;
- Class> returnType = method.getReturnType();
- boolean hasPropertyNameOverride = method.isAnnotationPresent(PropertyName.class);
-
- if (method.getDeclaringClass().isAssignableFrom(GraphObject.class)) {
- // Don't worry about any methods from GraphObject or one of its base classes.
- continue;
- } else if (parameterCount == 1 && returnType == Void.TYPE) {
- if (hasPropertyNameOverride) {
- // If a property override is present, it MUST be valid. We don't fallback
- // to using the method name
- if (!Utility.isNullOrEmpty(method.getAnnotation(PropertyName.class).value())) {
- continue;
- }
- } else if (methodName.startsWith("set") && methodName.length() > 3) {
- // Looks like a valid setter
- continue;
- }
- } else if (parameterCount == 0 && returnType != Void.TYPE) {
- if (hasPropertyNameOverride) {
- // If a property override is present, it MUST be valid. We don't fallback
- // to using the method name
- if (!Utility.isNullOrEmpty(method.getAnnotation(PropertyName.class).value())) {
- continue;
- }
- } else if (methodName.startsWith("get") && methodName.length() > 3) {
- // Looks like a valid getter
- continue;
- }
- }
-
- throw new FacebookGraphObjectException("Factory can't proxy method: " + method.toString());
- }
-
- recordClassHasBeenVerified(graphObjectClass);
- }
-
- // If expectedType is a generic type, expectedTypeAsParameterizedType must be provided in order to determine
- // generic parameter types.
- static U coerceValueToExpectedType(Object value, Class expectedType,
- ParameterizedType expectedTypeAsParameterizedType) {
- if (value == null) {
- return null;
- }
-
- Class> valueType = value.getClass();
- if (expectedType.isAssignableFrom(valueType)) {
- @SuppressWarnings("unchecked")
- U result = (U) value;
- return result;
- }
-
- if (expectedType.isPrimitive()) {
- // If the result is a primitive, let the runtime succeed or fail at unboxing it.
- @SuppressWarnings("unchecked")
- U result = (U) value;
- return result;
- }
-
- if (GraphObject.class.isAssignableFrom(expectedType)) {
- @SuppressWarnings("unchecked")
- Class extends GraphObject> graphObjectClass = (Class extends GraphObject>) expectedType;
-
- // We need a GraphObject, but we don't have one.
- if (JSONObject.class.isAssignableFrom(valueType)) {
- // We can wrap a JSONObject as a GraphObject.
- @SuppressWarnings("unchecked")
- U result = (U) createGraphObjectProxy(graphObjectClass, (JSONObject) value);
- return result;
- } else if (GraphObject.class.isAssignableFrom(valueType)) {
- // We can cast a GraphObject-derived class to another GraphObject-derived class.
- @SuppressWarnings("unchecked")
- U result = (U) ((GraphObject) value).cast(graphObjectClass);
- return result;
- } else {
- throw new FacebookGraphObjectException("Can't create GraphObject from " + valueType.getName());
- }
- } else if (Iterable.class.equals(expectedType) || Collection.class.equals(expectedType)
- || List.class.equals(expectedType) || GraphObjectList.class.equals(expectedType)) {
- if (expectedTypeAsParameterizedType == null) {
- throw new FacebookGraphObjectException("can't infer generic type of: " + expectedType.toString());
- }
-
- Type[] actualTypeArguments = expectedTypeAsParameterizedType.getActualTypeArguments();
-
- if (actualTypeArguments == null || actualTypeArguments.length != 1
- || !(actualTypeArguments[0] instanceof Class>)) {
- throw new FacebookGraphObjectException(
- "Expect collection properties to be of a type with exactly one generic parameter.");
- }
- Class> collectionGenericArgument = (Class>) actualTypeArguments[0];
-
- if (JSONArray.class.isAssignableFrom(valueType)) {
- JSONArray jsonArray = (JSONArray) value;
- @SuppressWarnings("unchecked")
- U result = (U) createList(jsonArray, collectionGenericArgument);
- return result;
- } else {
- throw new FacebookGraphObjectException("Can't create Collection from " + valueType.getName());
- }
- } else if (String.class.equals(expectedType)) {
- if (Double.class.isAssignableFrom(valueType) ||
- Float.class.isAssignableFrom(valueType)) {
- @SuppressWarnings("unchecked")
- U result = (U) String.format("%f", value);
- return result;
- } else if (Number.class.isAssignableFrom(valueType)) {
- @SuppressWarnings("unchecked")
- U result = (U) String.format("%d", value);
- return result;
- }
- } else if (Date.class.equals(expectedType)) {
- if (String.class.isAssignableFrom(valueType)) {
- for (SimpleDateFormat format : dateFormats) {
- try {
- Date date = format.parse((String) value);
- if (date != null) {
- @SuppressWarnings("unchecked")
- U result = (U) date;
- return result;
- }
- } catch (ParseException e) {
- // Keep going.
- }
- }
- }
- }
- throw new FacebookGraphObjectException("Can't convert type" + valueType.getName() + " to "
- + expectedType.getName());
- }
-
- static String convertCamelCaseToLowercaseWithUnderscores(String string) {
- string = string.replaceAll("([a-z])([A-Z])", "$1_$2");
- return string.toLowerCase(Locale.US);
- }
-
- private static Object getUnderlyingJSONObject(Object obj) {
- Class> objClass = obj.getClass();
- if (GraphObject.class.isAssignableFrom(objClass)) {
- GraphObject graphObject = (GraphObject) obj;
- return graphObject.getInnerJSONObject();
- } else if (GraphObjectList.class.isAssignableFrom(objClass)) {
- GraphObjectList> graphObjectList = (GraphObjectList>) obj;
- return graphObjectList.getInnerJSONArray();
- }
- return obj;
- }
-
- private abstract static class ProxyBase implements InvocationHandler {
- // Pre-loaded Method objects for the methods in java.lang.Object
- private static final String EQUALS_METHOD = "equals";
- private static final String TOSTRING_METHOD = "toString";
-
- protected final STATE state;
-
- protected ProxyBase(STATE state) {
- this.state = state;
- }
-
- // Declared to return Object just to simplify implementation of proxy helpers.
- protected final Object throwUnexpectedMethodSignature(Method method) {
- throw new FacebookGraphObjectException(getClass().getName() + " got an unexpected method signature: "
- + method.toString());
- }
-
- protected final Object proxyObjectMethods(Object proxy, Method method, Object[] args) throws Throwable {
- String methodName = method.getName();
- if (methodName.equals(EQUALS_METHOD)) {
- Object other = args[0];
-
- if (other == null) {
- return false;
- }
-
- InvocationHandler handler = Proxy.getInvocationHandler(other);
- if (!(handler instanceof GraphObjectProxy)) {
- return false;
- }
- GraphObjectProxy otherProxy = (GraphObjectProxy) handler;
- return this.state.equals(otherProxy.state);
- } else if (methodName.equals(TOSTRING_METHOD)) {
- return toString();
- }
-
- // For others, just defer to the implementation object.
- return method.invoke(this.state, args);
- }
-
- }
-
- private final static class GraphObjectProxy extends ProxyBase {
- private static final String CLEAR_METHOD = "clear";
- private static final String CONTAINSKEY_METHOD = "containsKey";
- private static final String CONTAINSVALUE_METHOD = "containsValue";
- private static final String ENTRYSET_METHOD = "entrySet";
- private static final String GET_METHOD = "get";
- private static final String ISEMPTY_METHOD = "isEmpty";
- private static final String KEYSET_METHOD = "keySet";
- private static final String PUT_METHOD = "put";
- private static final String PUTALL_METHOD = "putAll";
- private static final String REMOVE_METHOD = "remove";
- private static final String SIZE_METHOD = "size";
- private static final String VALUES_METHOD = "values";
- private static final String CAST_METHOD = "cast";
- private static final String CASTTOMAP_METHOD = "asMap";
- private static final String GETPROPERTY_METHOD = "getProperty";
- private static final String SETPROPERTY_METHOD = "setProperty";
- private static final String REMOVEPROPERTY_METHOD = "removeProperty";
- private static final String GETINNERJSONOBJECT_METHOD = "getInnerJSONObject";
-
- private final Class> graphObjectClass;
-
- public GraphObjectProxy(JSONObject state, Class> graphObjectClass) {
- super(state);
- this.graphObjectClass = graphObjectClass;
- }
-
- @Override
- public String toString() {
- return String.format("GraphObject{graphObjectClass=%s, state=%s}", graphObjectClass.getSimpleName(), state);
- }
-
- @Override
- public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Class> declaringClass = method.getDeclaringClass();
-
- if (declaringClass == Object.class) {
- return proxyObjectMethods(proxy, method, args);
- } else if (declaringClass == Map.class) {
- return proxyMapMethods(method, args);
- } else if (declaringClass == GraphObject.class) {
- return proxyGraphObjectMethods(proxy, method, args);
- } else if (GraphObject.class.isAssignableFrom(declaringClass)) {
- return proxyGraphObjectGettersAndSetters(method, args);
- }
-
- return throwUnexpectedMethodSignature(method);
- }
-
- private final Object proxyMapMethods(Method method, Object[] args) {
- String methodName = method.getName();
- if (methodName.equals(CLEAR_METHOD)) {
- JsonUtil.jsonObjectClear(this.state);
- return null;
- } else if (methodName.equals(CONTAINSKEY_METHOD)) {
- return this.state.has((String) args[0]);
- } else if (methodName.equals(CONTAINSVALUE_METHOD)) {
- return JsonUtil.jsonObjectContainsValue(this.state, args[0]);
- } else if (methodName.equals(ENTRYSET_METHOD)) {
- return JsonUtil.jsonObjectEntrySet(this.state);
- } else if (methodName.equals(GET_METHOD)) {
- return this.state.opt((String) args[0]);
- } else if (methodName.equals(ISEMPTY_METHOD)) {
- return this.state.length() == 0;
- } else if (methodName.equals(KEYSET_METHOD)) {
- return JsonUtil.jsonObjectKeySet(this.state);
- } else if (methodName.equals(PUT_METHOD)) {
- return setJSONProperty(args);
- } else if (methodName.equals(PUTALL_METHOD)) {
- Map map = null;
- if (args[0] instanceof Map, ?>) {
- @SuppressWarnings("unchecked")
- Map