com.facebook.android.friendsmash.ScoreboardFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.android.friendsmash.ScoreboardFragment.java

Source

/**
 * 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.android.friendsmash;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.facebook.Session;
import com.facebook.widget.ProfilePictureView;

/**
 *  Fragment shown once a user opens the scoreboard
 */
public class ScoreboardFragment extends Fragment {

    // Tag used when logging messages
    private static final String TAG = ScoreboardFragment.class.getSimpleName();

    // Store the Application (as you can't always get to it when you can't access the Activity - e.g. during rotations)
    private FriendSmashApplication application;

    // LinearLayout as the container for the scoreboard entries
    private LinearLayout scoreboardContainer;

    // FrameLayout of the progress container to show the spinner
    private FrameLayout progressContainer;

    // Handler for putting messages on Main UI thread from background thread after fetching the scores
    private Handler uiHandler;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        application = (FriendSmashApplication) getActivity().getApplication();

        // Instantiate the handler
        uiHandler = new Handler();

        setRetainInstance(true);
    }

    @TargetApi(13)
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.fragment_scoreboard, parent, false);

        scoreboardContainer = (LinearLayout) v.findViewById(R.id.scoreboardContainer);
        progressContainer = (FrameLayout) v.findViewById(R.id.progressContainer);

        // Set the progressContainer as invisible by default
        progressContainer.setVisibility(View.INVISIBLE);

        // Note: Scoreboard is populated during onResume below

        return v;
    }

    // Close the game and show the specified error to the user
    private void closeAndShowError(String error) {
        Bundle bundle = new Bundle();
        bundle.putString("error", error);

        Intent i = new Intent();
        i.putExtras(bundle);

        getActivity().setResult(Activity.RESULT_CANCELED, i);
        getActivity().finish();
    }

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

        // Populate scoreboard - fetch information if necessary ...
        if (application.getScoreboardEntriesList() == null) {
            // scoreboardEntriesList is null, so fetch the information from Facebook (scoreboard will be updated in
            // the scoreboardEntriesFetched callback) and show the progress spinner while doing so
            progressContainer.setVisibility(View.VISIBLE);
            fetchScoreboardEntries();
        } else {
            // Information has already been fetched, so populate the scoreboard
            populateScoreboard();
        }
    }

    // Fetch a List of ScoreboardEntry objects with the scores and details
    // of the user and their friends' scores who have played FriendSmash
    private void fetchScoreboardEntries() {
        // Fetch the scores ...
        AsyncTask.execute(new Runnable() {
            public void run() {
                try {
                    // Instantiate the scoreboardEntriesList
                    ArrayList<ScoreboardEntry> scoreboardEntriesList = new ArrayList<ScoreboardEntry>();

                    // Get the attributes used for the HTTP GET
                    String currentUserFBID = application.getCurrentFBUser().getId();
                    String currentUserAccessToken = Session.getActiveSession().getAccessToken();

                    // Execute the HTTP Get to our server for the scores of the user's friends
                    HttpClient client = new DefaultHttpClient();
                    String getURL = "http://www.friendsmash.com/scores?fbid=" + currentUserFBID + "&access_token="
                            + currentUserAccessToken;
                    HttpGet get = new HttpGet(getURL);
                    HttpResponse responseGet = client.execute(get);

                    // Parse the response
                    HttpEntity responseEntity = responseGet.getEntity();
                    String response = EntityUtils.toString(responseEntity);
                    if (!response.equals(null)) {
                        JSONArray responseJSONArray = new JSONArray(response);

                        // Go through the response JSON Array to populate the scoreboard
                        if (responseJSONArray != null && responseJSONArray.length() > 0) {

                            // Loop through all users that have been retrieved
                            for (int i = 0; i < responseJSONArray.length(); i++) {
                                // Store the user details in the following attributes
                                String userID = null;
                                String userName = null;
                                int userScore = -1;

                                // Extract the user information
                                JSONObject currentUser = responseJSONArray.optJSONObject(i);
                                if (currentUser != null) {
                                    userID = currentUser.optString("fbid");
                                    userName = currentUser.optString("first_name");
                                    String fetchedScoreAsString = currentUser.optString("highscore");
                                    if (fetchedScoreAsString != null) {
                                        userScore = Integer.parseInt(fetchedScoreAsString);
                                    }
                                    if (userID != null && userName != null && userScore >= 0) {
                                        // All attributes have been successfully fetched, so create a new
                                        // ScoreboardEntry and add it to the List
                                        ScoreboardEntry currentUserScoreboardEntry = new ScoreboardEntry(userID,
                                                userName, userScore);
                                        scoreboardEntriesList.add(currentUserScoreboardEntry);
                                    }
                                }
                            }
                        }
                    }

                    // Now that all scores should have been fetched and added to the scoreboardEntriesList, sort it,
                    // set it within scoreboardFragment and then callback to scoreboardFragment to populate the scoreboard
                    Comparator<ScoreboardEntry> comparator = Collections.reverseOrder();
                    Collections.sort(scoreboardEntriesList, comparator);
                    application.setScoreboardEntriesList(scoreboardEntriesList);

                    // Populate the scoreboard on the UI thread
                    uiHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            populateScoreboard();
                        }
                    });
                } catch (Exception e) {
                    Log.e(FriendSmashApplication.TAG, e.toString());
                    closeAndShowError(getResources().getString(R.string.network_error));
                }
            }
        });
    }

    private void populateScoreboard() {
        // Ensure all components are firstly removed from scoreboardContainer
        scoreboardContainer.removeAllViews();

        // Ensure the progress spinner is hidden
        progressContainer.setVisibility(View.INVISIBLE);

        // Ensure scoreboardEntriesList is not null and not empty first
        if (application.getScoreboardEntriesList() == null || application.getScoreboardEntriesList().size() <= 0) {
            closeAndShowError(getResources().getString(R.string.error_no_scores));
        } else {
            // Iterate through scoreboardEntriesList, creating new UI elements for each entry
            int index = 0;
            Iterator<ScoreboardEntry> scoreboardEntriesIterator = application.getScoreboardEntriesList().iterator();
            while (scoreboardEntriesIterator.hasNext()) {
                // Get the current scoreboard entry
                final ScoreboardEntry currentScoreboardEntry = scoreboardEntriesIterator.next();

                // FrameLayout Container for the currentScoreboardEntry ...

                // Create and add a new FrameLayout to display the details of this entry
                FrameLayout frameLayout = new FrameLayout(getActivity());
                scoreboardContainer.addView(frameLayout);

                // Set the attributes for this frameLayout
                int topPadding = getResources().getDimensionPixelSize(R.dimen.scoreboard_entry_top_margin);
                frameLayout.setPadding(0, topPadding, 0, 0);

                // ImageView background image ...
                {
                    // Create and add an ImageView for the background image to this entry
                    ImageView backgroundImageView = new ImageView(getActivity());
                    frameLayout.addView(backgroundImageView);

                    // Set the image of the backgroundImageView
                    String uri = "drawable/scores_stub_even";
                    if (index % 2 != 0) {
                        // Odd entry
                        uri = "drawable/scores_stub_odd";
                    }
                    int imageResource = getResources().getIdentifier(uri, null, getActivity().getPackageName());
                    Drawable image = getResources().getDrawable(imageResource);
                    backgroundImageView.setImageDrawable(image);

                    // Other attributes of backgroundImageView to modify
                    FrameLayout.LayoutParams backgroundImageViewLayoutParams = new FrameLayout.LayoutParams(
                            FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
                    int backgroundImageViewMarginTop = getResources()
                            .getDimensionPixelSize(R.dimen.scoreboard_background_imageview_margin_top);
                    backgroundImageViewLayoutParams.setMargins(0, backgroundImageViewMarginTop, 0, 0);
                    backgroundImageViewLayoutParams.gravity = Gravity.LEFT;
                    if (index % 2 != 0) {
                        // Odd entry
                        backgroundImageViewLayoutParams.gravity = Gravity.RIGHT;
                    }
                    backgroundImageView.setLayoutParams(backgroundImageViewLayoutParams);
                }

                // ProfilePictureView of the current user ...
                {
                    // Create and add a ProfilePictureView for the current user entry's profile picture
                    ProfilePictureView profilePictureView = new ProfilePictureView(getActivity());
                    frameLayout.addView(profilePictureView);

                    // Set the attributes of the profilePictureView
                    int profilePictureViewWidth = getResources()
                            .getDimensionPixelSize(R.dimen.scoreboard_profile_picture_view_width);
                    FrameLayout.LayoutParams profilePictureViewLayoutParams = new FrameLayout.LayoutParams(
                            profilePictureViewWidth, profilePictureViewWidth);
                    int profilePictureViewMarginLeft = 0;
                    int profilePictureViewMarginTop = getResources()
                            .getDimensionPixelSize(R.dimen.scoreboard_profile_picture_view_margin_top);
                    int profilePictureViewMarginRight = 0;
                    int profilePictureViewMarginBottom = 0;
                    if (index % 2 == 0) {
                        profilePictureViewMarginLeft = getResources()
                                .getDimensionPixelSize(R.dimen.scoreboard_profile_picture_view_margin_left);
                    } else {
                        profilePictureViewMarginRight = getResources()
                                .getDimensionPixelSize(R.dimen.scoreboard_profile_picture_view_margin_right);
                    }
                    profilePictureViewLayoutParams.setMargins(profilePictureViewMarginLeft,
                            profilePictureViewMarginTop, profilePictureViewMarginRight,
                            profilePictureViewMarginBottom);
                    profilePictureViewLayoutParams.gravity = Gravity.LEFT;
                    if (index % 2 != 0) {
                        // Odd entry
                        profilePictureViewLayoutParams.gravity = Gravity.RIGHT;
                    }
                    profilePictureView.setLayoutParams(profilePictureViewLayoutParams);

                    // Finally set the id of the user to show their profile pic
                    profilePictureView.setProfileId(currentScoreboardEntry.getId());
                }

                // LinearLayout to hold the text in this entry

                // Create and add a LinearLayout to hold the TextViews
                LinearLayout textViewsLinearLayout = new LinearLayout(getActivity());
                frameLayout.addView(textViewsLinearLayout);

                // Set the attributes for this textViewsLinearLayout
                FrameLayout.LayoutParams textViewsLinearLayoutLayoutParams = new FrameLayout.LayoutParams(
                        FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
                int textViewsLinearLayoutMarginLeft = 0;
                int textViewsLinearLayoutMarginTop = getResources()
                        .getDimensionPixelSize(R.dimen.scoreboard_textviews_linearlayout_margin_top);
                int textViewsLinearLayoutMarginRight = 0;
                int textViewsLinearLayoutMarginBottom = 0;
                if (index % 2 == 0) {
                    textViewsLinearLayoutMarginLeft = getResources()
                            .getDimensionPixelSize(R.dimen.scoreboard_textviews_linearlayout_margin_left);
                } else {
                    textViewsLinearLayoutMarginRight = getResources()
                            .getDimensionPixelSize(R.dimen.scoreboard_textviews_linearlayout_margin_right);
                }
                textViewsLinearLayoutLayoutParams.setMargins(textViewsLinearLayoutMarginLeft,
                        textViewsLinearLayoutMarginTop, textViewsLinearLayoutMarginRight,
                        textViewsLinearLayoutMarginBottom);
                textViewsLinearLayoutLayoutParams.gravity = Gravity.LEFT;
                if (index % 2 != 0) {
                    // Odd entry
                    textViewsLinearLayoutLayoutParams.gravity = Gravity.RIGHT;
                }
                textViewsLinearLayout.setLayoutParams(textViewsLinearLayoutLayoutParams);
                textViewsLinearLayout.setOrientation(LinearLayout.VERTICAL);

                // TextView with the position and name of the current user
                {
                    // Set the text that should go in this TextView first
                    int position = index + 1;
                    String currentScoreboardEntryTitle = position + ". " + currentScoreboardEntry.getName();

                    // Create and add a TextView for the current user position and first name
                    TextView titleTextView = new TextView(getActivity());
                    textViewsLinearLayout.addView(titleTextView);

                    // Set the text and other attributes for this TextView
                    titleTextView.setText(currentScoreboardEntryTitle);
                    titleTextView.setTextAppearance(getActivity(), R.style.ScoreboardPlayerNameFont);
                }

                // TextView with the score of the current user
                {
                    // Create and add a TextView for the current user score
                    TextView scoreTextView = new TextView(getActivity());
                    textViewsLinearLayout.addView(scoreTextView);

                    // Set the text and other attributes for this TextView
                    scoreTextView.setText("Score: " + currentScoreboardEntry.getScore());
                    scoreTextView.setTextAppearance(getActivity(), R.style.ScoreboardPlayerScoreFont);
                }

                // Finally make this frameLayout clickable so that a game starts with the user smashing
                // the user represented by this frameLayout in the scoreContainer
                frameLayout.setOnTouchListener(new OnTouchListener() {

                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        if (event.getAction() == MotionEvent.ACTION_UP) {
                            Bundle bundle = new Bundle();
                            bundle.putString("user_id", currentScoreboardEntry.getId());

                            Intent i = new Intent();
                            i.putExtras(bundle);

                            getActivity().setResult(Activity.RESULT_FIRST_USER, i);
                            getActivity().finish();
                            return false;
                        } else {
                            return true;
                        }
                    }

                });

                // Increment the index before looping back
                index++;
            }
        }
    }
}