/**
* 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.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);
}
}
}
}