com.facebook.samples.booleanog.LogicActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.samples.booleanog.LogicActivity.java

Source

/**
 * 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.samples.booleanog;

import android.app.AlertDialog;
import android.content.Intent;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import com.facebook.*;
import com.facebook.model.*;
import com.facebook.widget.FriendPickerFragment;
import com.facebook.widget.UserSettingsFragment;
import com.facebook.widget.PickerFragment;

import java.text.SimpleDateFormat;
import java.util.*;

public class LogicActivity extends FragmentActivity {

    private static final String TAG = "BooleanOpenGraphSample";

    private static final String SAVE_ACTIVE_TAB = TAG + ".SAVE_ACTIVE_TAB";
    private static final String SAVE_CONTENT_SELECTION = TAG + ".SAVE_CONTENT_SELECTION";
    private static final String SAVE_LEFT_OPERAND_SELECTION = TAG + ".SAVE_LEFT_OPERAND_SELECTION";
    private static final String SAVE_RIGHT_OPERAND_SELECTION = TAG + ".SAVE_RIGHT_OPERAND_SELECTION";
    private static final String SAVE_RESULT_TEXT = TAG + ".SAVE_RESULT_TEXT";
    private static final String SAVE_POST_RESULT_TEXT = TAG + ".SAVE_POST_RESULT_TEXT";
    private static final String SAVE_PENDING = TAG + ".SAVE_PENDING";
    private static final String SAVE_FRIEND_ACTIONS = TAG + ".SAVE_FRIEND_ACTIONS";
    private static final String PENDING_POST_PATH = "PENDING_POST_PATH";
    private static final String PENDING_POST_LEFT = "PENDING_POST_LEFT";
    private static final String PENDING_POST_RIGHT = "PENDING_POST_RIGHT";
    private static final String PENDING_POST_RESULT = "PENDING_POST_RESULT";

    private static final String AND_ACTION = "fb_sample_boolean_og:and";
    private static final String OR_ACTION = "fb_sample_boolean_og:or";
    private static final String POST_AND_ACTION_PATH = "me/" + AND_ACTION;
    private static final String POST_OR_ACTION_PATH = "me/" + OR_ACTION;
    private static final String TRUE_GRAPH_OBJECT_URL = "http://samples.ogp.me/369360019783304";
    private static final String FALSE_GRAPH_OBJECT_URL = "http://samples.ogp.me/369360256449947";
    private static final String INSTALLED = "installed";
    private static final List<String> PERMISSIONS = Arrays.asList("publish_actions");

    private static volatile TruthValueGraphObject TRUE_GRAPH_OBJECT;
    private static volatile TruthValueGraphObject FALSE_GRAPH_OBJECT;
    private static volatile int TRUE_SPINNER_INDEX = -1;
    private static volatile int FALSE_SPINNER_INDEX = -1;

    // Main layout
    private Button logicButton;
    private Button friendsButton;
    private Button settingsButton;
    private Button contentButton;
    private String activeTab;

    // Logic group
    private ViewGroup logicGroup;
    private Spinner leftSpinner;
    private Spinner rightSpinner;
    private Button andButton;
    private Button orButton;
    private TextView resultText;
    private TextView postResultText;
    private Bundle pendingPost;

    // Friends group
    private ViewGroup friendsGroup;
    private FriendPickerFragment friendPickerFragment;
    private RequestAsyncTask pendingRequest;
    private SimpleCursorAdapter friendActivityAdapter;
    private ProgressBar friendActivityProgressBar;
    private ArrayList<ActionRow> friendActionList;

    // Login group
    private ViewGroup settingsGroup;
    private UserSettingsFragment userSettingsFragment;

    // Content group
    private ViewGroup contentGroup;
    private ImageView contentImage;
    private Spinner contentSpinner;

    private UiLifecycleHelper uiHelper;
    private Session.StatusCallback callback = new Session.StatusCallback() {
        @Override
        public void call(Session session, SessionState state, Exception exception) {
            if (exception != null) {
                pendingPost = null;
            } else if (state == SessionState.OPENED) {
                friendPickerFragment.loadData(false);
            } else if (state == SessionState.OPENED_TOKEN_UPDATED) {
                sendPendingPost();
            }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uiHelper = new UiLifecycleHelper(this, callback);
        uiHelper.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        // Views
        logicButton = (Button) findViewById(R.id.logic_button);
        friendsButton = (Button) findViewById(R.id.friends_button);
        settingsButton = (Button) findViewById(R.id.settings_button);
        contentButton = (Button) findViewById(R.id.content_button);

        logicGroup = (ViewGroup) findViewById(R.id.logic_group);
        leftSpinner = (Spinner) findViewById(R.id.left_spinner);
        rightSpinner = (Spinner) findViewById(R.id.right_spinner);
        andButton = (Button) findViewById(R.id.and_button);
        orButton = (Button) findViewById(R.id.or_button);
        resultText = (TextView) findViewById(R.id.result_text);
        postResultText = (TextView) findViewById(R.id.post_result_text);

        friendsGroup = (ViewGroup) findViewById(R.id.friends_group);
        ListView friendActivityList = (ListView) findViewById(R.id.friend_activity_list);
        String[] mapColumnNames = { "date", "action" };
        int[] mapViewIds = { R.id.friend_action_date, R.id.friend_action_data };
        friendActivityAdapter = new SimpleCursorAdapter(this, R.layout.friend_activity_row, createEmptyCursor(),
                mapColumnNames, mapViewIds);
        friendActivityList.setAdapter(friendActivityAdapter);
        friendActivityProgressBar = (ProgressBar) findViewById(R.id.friend_activity_progress_bar);

        settingsGroup = (ViewGroup) findViewById(R.id.settings_group);

        contentGroup = (ViewGroup) findViewById(R.id.content_group);
        contentImage = (ImageView) findViewById(R.id.content_image);
        contentSpinner = (Spinner) findViewById(R.id.content_spinner);

        // Fragments
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        friendPickerFragment = (FriendPickerFragment) fragmentManager.findFragmentById(R.id.friend_picker_fragment);
        if (friendPickerFragment == null) {
            Bundle args = new Bundle();
            args.putBoolean(FriendPickerFragment.SHOW_TITLE_BAR_BUNDLE_KEY, false);
            friendPickerFragment = new FriendPickerFragment(args);
            transaction.add(R.id.friend_picker_fragment, friendPickerFragment);
        }

        userSettingsFragment = (UserSettingsFragment) fragmentManager.findFragmentById(R.id.login_fragment);
        if (userSettingsFragment == null) {
            userSettingsFragment = new UserSettingsFragment();
            transaction.add(R.id.login_fragment, userSettingsFragment);
        }

        transaction.commit();

        // Spinners
        ArrayAdapter<CharSequence> truthAdapter = ArrayAdapter.createFromResource(this, R.array.truth_values,
                android.R.layout.simple_spinner_item);
        truthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        leftSpinner.setAdapter(truthAdapter);
        rightSpinner.setAdapter(truthAdapter);
        contentSpinner.setAdapter(truthAdapter);
        leftSpinner.setSelection(0);
        rightSpinner.setSelection(0);

        // Navigation
        for (Button button : Arrays.asList(logicButton, friendsButton, settingsButton, contentButton)) {
            initializeNavigationButton(button);
        }

        // Logic
        initializeCalculationButton(andButton);
        initializeCalculationButton(orButton);

        // Friends
        friendPickerFragment.setOnErrorListener(new PickerFragment.OnErrorListener() {
            @Override
            public void onError(PickerFragment<?> fragment, FacebookException error) {
                LogicActivity.this.onError(error);
            }
        });
        friendPickerFragment.setUserId("me");
        friendPickerFragment.setMultiSelect(false);
        friendPickerFragment.setOnSelectionChangedListener(new PickerFragment.OnSelectionChangedListener() {
            @Override
            public void onSelectionChanged(PickerFragment<?> fragment) {
                LogicActivity.this.onFriendSelectionChanged();
            }
        });
        friendPickerFragment.setExtraFields(Arrays.asList(INSTALLED));
        friendPickerFragment.setFilter(new PickerFragment.GraphObjectFilter<GraphUser>() {
            @Override
            public boolean includeItem(GraphUser graphObject) {
                Boolean installed = graphObject.cast(GraphUserWithInstalled.class).getInstalled();
                return (installed != null) && installed.booleanValue();
            }
        });

        // Content
        contentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                LogicActivity.this.onContentSelectionChanged();
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
                LogicActivity.this.onContentSelectionChanged();
            }
        });

        // Restore saved state
        Button startButton = logicButton;

        if (savedInstanceState != null) {
            leftSpinner.setSelection(savedInstanceState.getInt(SAVE_LEFT_OPERAND_SELECTION));
            rightSpinner.setSelection(savedInstanceState.getInt(SAVE_RIGHT_OPERAND_SELECTION));
            contentSpinner.setSelection(savedInstanceState.getInt(SAVE_CONTENT_SELECTION));
            resultText.setText(savedInstanceState.getString(SAVE_RESULT_TEXT));
            postResultText.setText(savedInstanceState.getString(SAVE_POST_RESULT_TEXT));
            activeTab = savedInstanceState.getString(SAVE_ACTIVE_TAB);
            pendingPost = savedInstanceState.getBundle(SAVE_PENDING);

            friendActionList = savedInstanceState.getParcelableArrayList(SAVE_FRIEND_ACTIONS);
            if ((friendActionList != null) && (friendActionList.size() > 0)) {
                updateCursor(friendActionList);
            }

            if (getString(R.string.navigate_friends).equals(activeTab)) {
                startButton = friendsButton;
            } else if (getString(R.string.navigate_content).equals(activeTab)) {
                startButton = contentButton;
            } else if (getString(R.string.navigate_settings).equals(activeTab)) {
                startButton = settingsButton;
            }
        }

        if (!handleNativeLink()) {
            onNavigateButtonClick(startButton);
        }
    }

    // -----------------------------------------------------------------------------------
    // Activity lifecycle

    @Override
    public void onStart() {
        super.onStart();
        Session session = Session.getActiveSession();
        if (session != null && session.isOpened()) {
            friendPickerFragment.loadData(false);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        uiHelper.onResume();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        uiHelper.onSaveInstanceState(outState);

        outState.putInt(SAVE_LEFT_OPERAND_SELECTION, leftSpinner.getSelectedItemPosition());
        outState.putInt(SAVE_RIGHT_OPERAND_SELECTION, rightSpinner.getSelectedItemPosition());
        outState.putInt(SAVE_CONTENT_SELECTION, contentSpinner.getSelectedItemPosition());
        outState.putString(SAVE_RESULT_TEXT, resultText.getText().toString());
        outState.putString(SAVE_POST_RESULT_TEXT, postResultText.getText().toString());
        outState.putString(SAVE_ACTIVE_TAB, activeTab);
        outState.putBundle(SAVE_PENDING, pendingPost);
        outState.putParcelableArrayList(SAVE_FRIEND_ACTIONS, friendActionList);
    }

    @Override
    public void onPause() {
        super.onPause();
        uiHelper.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        uiHelper.onDestroy();

        friendPickerFragment.setOnErrorListener(null);
        friendPickerFragment.setOnSelectionChangedListener(null);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        uiHelper.onActivityResult(requestCode, resultCode, data);
    }

    // -----------------------------------------------------------------------------------
    // Navigation

    private void initializeNavigationButton(Button button) {
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onNavigateButtonClick((Button) view);
            }
        });
    }

    private void onNavigateButtonClick(Button source) {
        activeTab = source.getText().toString();

        logicGroup.setVisibility(getGroupVisibility(source, logicButton));
        friendsGroup.setVisibility(getGroupVisibility(source, friendsButton));
        settingsGroup.setVisibility(getGroupVisibility(source, settingsButton));
        contentGroup.setVisibility(getGroupVisibility(source, contentButton));

        // Show an error if viewing friends and there is no logged in user.
        if (source == friendsButton) {
            Session session = Session.getActiveSession();
            if ((session == null) || !session.isOpened()) {
                new AlertDialog.Builder(this).setTitle(R.string.feature_requires_login_title)
                        .setMessage(R.string.feature_requires_login_message)
                        .setPositiveButton(R.string.ok_button, null).show();
            }
        }
    }

    private int getGroupVisibility(Button source, Button groupButton) {
        if (source == groupButton) {
            return View.VISIBLE;
        } else {
            return View.GONE;
        }
    }

    // -----------------------------------------------------------------------------------
    // Logic group

    private void initializeCalculationButton(Button button) {
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onOperationButtonClick(view);
            }
        });
    }

    private void onOperationButtonClick(View view) {
        if (view == andButton) {
            onAndButtonClick();
        } else if (view == orButton) {
            onOrButtonClick();
        } else {
            assert false;
        }
    }

    private void onAndButtonClick() {
        boolean leftOperand = getSpinnerBoolean(leftSpinner);
        boolean rightOperand = getSpinnerBoolean(rightSpinner);
        boolean result = leftOperand && rightOperand;

        resultText.setText(getLogicText(getString(R.string.and_operation), leftOperand, rightOperand, result));
        postAction(POST_AND_ACTION_PATH, leftOperand, rightOperand, result);
    }

    private void onOrButtonClick() {
        boolean leftOperand = getSpinnerBoolean(leftSpinner);
        boolean rightOperand = getSpinnerBoolean(rightSpinner);
        boolean result = leftOperand || rightOperand;

        resultText.setText(getLogicText(getString(R.string.or_operation), leftOperand, rightOperand, result));
        postAction(POST_OR_ACTION_PATH, leftOperand, rightOperand, result);
    }

    private String getLogicText(String op, boolean leftOperand, boolean rightOperand, boolean result) {
        String trueString = getString(R.string.true_value);
        String falseString = getString(R.string.false_value);
        String arg0String = leftOperand ? trueString : falseString;
        String arg1String = rightOperand ? trueString : falseString;
        String resultString = result ? trueString : falseString;

        return String.format("%s %s %s = %s", arg0String, op, arg1String, resultString);
    }

    private void postAction(final String actionPath, final boolean leftOperand, final boolean rightOperand,
            final boolean result) {
        Bundle post = new Bundle();
        post.putString(PENDING_POST_PATH, actionPath);
        post.putBoolean(PENDING_POST_LEFT, leftOperand);
        post.putBoolean(PENDING_POST_RIGHT, rightOperand);
        post.putBoolean(PENDING_POST_RESULT, result);
        pendingPost = post;

        sendPendingPost();
    }

    private void sendPendingPost() {
        if (pendingPost == null) {
            return;
        }

        Session session = Session.getActiveSession();
        if ((session == null) || !session.isOpened()) {
            postResultText.setText("Not logged in, no post generated.");
            pendingPost = null;
            return;
        }

        List<String> permissions = session.getPermissions();
        if (!permissions.containsAll(PERMISSIONS)) {
            Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this,
                    PERMISSIONS);
            session.requestNewPublishPermissions(newPermissionsRequest);
            return;
        }

        postResultText.setText("Posting action...");

        // For demo purposes, result is just a boolean, but operands are Open Graph objects
        String actionPath = pendingPost.getString(PENDING_POST_PATH);
        boolean leftOperand = pendingPost.getBoolean(PENDING_POST_LEFT);
        boolean rightOperand = pendingPost.getBoolean(PENDING_POST_RIGHT);
        boolean result = pendingPost.getBoolean(PENDING_POST_RESULT);

        LogicAction action = GraphObject.Factory.create(LogicAction.class);
        action.setResult(result);
        action.setTruthvalue(getTruthValueObject(leftOperand));
        action.setAnothertruthvalue(getTruthValueObject(rightOperand));

        Request.Callback callback = new Request.Callback() {
            @Override
            public void onCompleted(Response response) {
                onPostActionResponse(response);
            }
        };
        Request request = new Request(session, actionPath, null, HttpMethod.POST, callback);
        request.setGraphObject(action);
        RequestAsyncTask task = new RequestAsyncTask(request);

        task.execute();
    }

    private void onPostActionResponse(Response response) {
        PostResponse postResponse = response.getGraphObjectAs(PostResponse.class);
        if (postResponse != null && postResponse.getId() != null) {
            postResultText.setText("Post id = " + postResponse.getId());
        } else if (response.getError() != null) {
            postResultText.setText(response.getError().getErrorMessage());
        } else {
            postResultText.setText("");
        }
    }

    private TruthValueGraphObject getTruthValueObject(boolean value) {
        if (value) {
            if (TRUE_GRAPH_OBJECT == null) {
                TruthValueGraphObject object = GraphObject.Factory.create(TruthValueGraphObject.class);
                object.setUrl(TRUE_GRAPH_OBJECT_URL);
                TRUE_GRAPH_OBJECT = object;
            }
            return TRUE_GRAPH_OBJECT;
        } else {
            if (FALSE_GRAPH_OBJECT == null) {
                TruthValueGraphObject object = GraphObject.Factory.create(TruthValueGraphObject.class);
                object.setUrl(FALSE_GRAPH_OBJECT_URL);
                FALSE_GRAPH_OBJECT = object;
            }
            return FALSE_GRAPH_OBJECT;
        }
    }

    // -----------------------------------------------------------------------------------
    // Friends group

    private void onFriendSelectionChanged() {
        GraphUser user = chooseOne(friendPickerFragment.getSelection());
        if (user != null) {
            onChooseFriend(user.getId());
        } else {
            friendActivityAdapter.changeCursor(createEmptyCursor());
        }
    }

    private void onChooseFriend(String friendId) {
        friendActivityProgressBar.setVisibility(View.VISIBLE);

        String andPath = String.format("%s/%s", friendId, AND_ACTION);
        String orPath = String.format("%s/%s", friendId, OR_ACTION);
        Request getAnds = new Request(Session.getActiveSession(), andPath, null, HttpMethod.GET);
        Request getOrs = new Request(Session.getActiveSession(), orPath, null, HttpMethod.GET);

        RequestBatch batch = new RequestBatch(getAnds, getOrs);

        if (pendingRequest != null) {
            pendingRequest.cancel(true);
        }

        pendingRequest = new RequestAsyncTask(batch) {
            @Override
            protected void onPostExecute(List<Response> result) {
                if (pendingRequest == this) {
                    pendingRequest = null;

                    LogicActivity.this.onPostExecute(result);
                }
            }
        };

        pendingRequest.execute();
    }

    private void onPostExecute(List<Response> result) {
        friendActivityProgressBar.setVisibility(View.GONE);

        friendActionList = createActionRows(result);
        updateCursor(friendActionList);
    }

    private ArrayList<ActionRow> createActionRows(List<Response> result) {
        ArrayList<ActionRow> publishedItems = new ArrayList<ActionRow>();

        for (Response response : result) {
            if (response.getError() != null) {
                continue;
            }

            GraphMultiResult list = response.getGraphObjectAs(GraphMultiResult.class);
            List<PublishedLogicAction> listData = list.getData().castToListOf(PublishedLogicAction.class);

            for (PublishedLogicAction action : listData) {
                publishedItems.add(createActionRow(action));
            }
        }

        Collections.sort(publishedItems);
        return publishedItems;
    }

    private void updateCursor(Iterable<ActionRow> publishedItems) {
        MatrixCursor cursor = createEmptyCursor();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());

        int id = 0;
        for (ActionRow item : publishedItems) {
            Object[] row = new Object[3];
            row[0] = id++;
            row[1] = dateFormat.format(item.publishDate);
            row[2] = item.actionText;
            cursor.addRow(row);
        }

        friendActivityAdapter.changeCursor(cursor);
        friendActivityAdapter.notifyDataSetChanged();
    }

    private MatrixCursor createEmptyCursor() {
        String[] cursorColumns = { "_ID", "date", "action" };
        return new MatrixCursor(cursorColumns);
    }

    private ActionRow createActionRow(PublishedLogicAction action) {
        String actionText = getActionText(action);
        Date publishDate = action.getPublishTime();

        return new ActionRow(actionText, publishDate);
    }

    private String getActionText(PublishedLogicAction action) {
        LogicAction actionData = action.getData();
        if (actionData == null) {
            return "";
        }

        TruthValueGraphObject left = actionData.getTruthvalue();
        TruthValueGraphObject right = actionData.getAnothertruthvalue();
        Boolean actionResult = actionData.getResult();

        String verb = action.getType();
        if (AND_ACTION.equals(verb)) {
            verb = getString(R.string.and_operation);
        } else if (OR_ACTION.equals(verb)) {
            verb = getString(R.string.or_operation);
        }

        if ((left == null) || (right == null) || (actionResult == null) || (verb == null)) {
            return "";
        }

        return String.format("%s %s %s = %s", left.getTitle(), verb, right.getTitle(), actionResult.toString());
    }

    // -----------------------------------------------------------------------------------
    // Content group

    private Boolean getDeepLinkContent(Uri deepLinkUri) {
        if (deepLinkUri != null) {
            String deepLink = deepLinkUri.toString();

            if (deepLink.startsWith(TRUE_GRAPH_OBJECT_URL)) {
                return Boolean.TRUE;
            } else if (deepLink.startsWith(FALSE_GRAPH_OBJECT_URL)) {
                return Boolean.FALSE;
            }
        }

        return null;
    }

    private void onContentSelectionChanged() {
        Boolean spinnerBoolean = getSpinnerBoolean(contentSpinner);
        if (Boolean.TRUE.equals(spinnerBoolean)) {
            contentImage.setVisibility(View.VISIBLE);
            contentImage.setImageResource(R.drawable.true_content);
        } else if (Boolean.FALSE.equals(spinnerBoolean)) {
            contentImage.setVisibility(View.VISIBLE);
            contentImage.setImageResource(R.drawable.false_content);
        } else {
            contentImage.setImageResource(View.INVISIBLE);
        }
    }

    // -----------------------------------------------------------------------------------
    // Utility methods

    private boolean handleNativeLink() {
        Session existingSession = Session.getActiveSession();
        // If we have a valid existing session, we'll use it; if not, open one using the provided Intent
        // but do not cache the token (we don't want to use the same user identity the next time the
        // app is run).
        if (existingSession == null || !existingSession.isOpened()) {
            AccessToken accessToken = AccessToken.createFromNativeLinkingIntent(getIntent());
            if (accessToken != null) {
                Session newSession = new Session.Builder(this)
                        .setTokenCachingStrategy(new NonCachingTokenCachingStrategy()).build();
                newSession.open(accessToken, null);

                Session.setActiveSession(newSession);
            }
        }
        // See if we have a deep link in addition.
        Boolean deepLinkContent = getDeepLinkContent(getIntent().getData());
        if (deepLinkContent != null) {
            onNavigateButtonClick(contentButton);
            contentSpinner.setSelection(getSpinnerPosition(deepLinkContent));
            return true;
        }

        return false;
    }

    private int getSpinnerPosition(Boolean value) {
        initializeSpinnerIndexes();

        if (Boolean.TRUE.equals(value)) {
            return TRUE_SPINNER_INDEX;
        } else if (Boolean.FALSE.equals(value)) {
            return FALSE_SPINNER_INDEX;
        } else {
            return -1;
        }
    }

    private Boolean getSpinnerBoolean(Spinner spinner) {
        initializeSpinnerIndexes();

        int position = spinner.getSelectedItemPosition();
        if (position == TRUE_SPINNER_INDEX) {
            return Boolean.TRUE;
        } else if (position == FALSE_SPINNER_INDEX) {
            return Boolean.FALSE;
        } else {
            return null;
        }
    }

    private void initializeSpinnerIndexes() {
        if ((TRUE_SPINNER_INDEX < 0) || (FALSE_SPINNER_INDEX < 0)) {
            String[] truthArray = getResources().getStringArray(R.array.truth_values);
            List<String> truthList = Arrays.asList(truthArray);
            TRUE_SPINNER_INDEX = truthList.indexOf(getString(R.string.true_value));
            FALSE_SPINNER_INDEX = truthList.indexOf(getString(R.string.false_value));
        }
    }

    private void onError(Exception error) {
        showErrorMessage(error.getMessage());
    }

    private void showErrorMessage(String message) {
        new AlertDialog.Builder(this).setTitle(R.string.error_dialog_title).setMessage(message)
                .setPositiveButton(R.string.ok_button, null).show();
    }

    private <T> T chooseOne(List<T> ts) {
        for (T t : ts) {
            return t;
        }

        return null;
    }

    // -----------------------------------------------------------------------------------
    // Supporting types

    private interface GraphUserWithInstalled extends GraphUser {
        Boolean getInstalled();
    }

    private static class ActionRow implements Comparable<ActionRow>, Parcelable {
        final String actionText;
        final Date publishDate;

        ActionRow(String actionText, Date publishDate) {
            this.actionText = actionText;
            this.publishDate = publishDate;
        }

        @Override
        public int compareTo(ActionRow other) {
            if (other == null) {
                return 1;
            } else {
                return publishDate.compareTo(other.publishDate);
            }
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeString(actionText);
            parcel.writeLong(publishDate.getTime());
        }

        @SuppressWarnings("unused")
        public final Creator<ActionRow> CREATOR = new Creator<ActionRow>() {
            @Override
            public ActionRow createFromParcel(Parcel parcel) {
                String actionText = parcel.readString();
                Date publishDate = new Date(parcel.readLong());
                return new ActionRow(actionText, publishDate);
            }

            @Override
            public ActionRow[] newArray(int size) {
                return new ActionRow[size];
            }
        };
    }

    /**
     * Used to create and consume TruthValue open graph objects.
     */
    private interface TruthValueGraphObject extends GraphObject {
        void setUrl(String url);

        String getTitle();
    }

    /**
     * Used to create and consume And an Or open graph actions
     */
    private interface LogicAction extends OpenGraphAction {
        Boolean getResult();

        void setResult(Boolean result);

        TruthValueGraphObject getTruthvalue();

        void setTruthvalue(TruthValueGraphObject truthvalue);

        TruthValueGraphObject getAnothertruthvalue();

        void setAnothertruthvalue(TruthValueGraphObject anothertruthvalue);
    }

    /**
     * Used to consume published And and Or open graph actions.
     */
    private interface PublishedLogicAction extends OpenGraphAction {
        LogicAction getData();

        String getType();
    }

    /**
     * Used to inspect the response from posting an action
     */
    private interface PostResponse extends GraphObject {
        String getId();
    }
}